first stab at integrity and privacy
note: privacy will not work when we have more than 1 outstanding rpcs which generates out of order replies which sspi does not allow when privacy is enabled. adding auth_wrap() and auth_unwrap() to per-message gss token protection required adding these methods to auth_sys and auth_non. linux server doesnt support v2 kerberos tokens that have rotated data. sspi will always produce such tokens for aes. thus thus code was only tested for v1 kerberos tokens (ie des).
This commit is contained in:
parent
b6120b41fd
commit
4411d3d807
7 changed files with 149 additions and 28 deletions
|
|
@ -156,6 +156,12 @@ authnone_destroy(AUTH *client)
|
|||
{
|
||||
}
|
||||
|
||||
static bool_t
|
||||
authnone_wrap(AUTH *auth, XDR *xdrs, xdrproc_t func, caddr_t args, u_int seq)
|
||||
{
|
||||
return ((*func)(xdrs, args));
|
||||
}
|
||||
|
||||
static struct auth_ops *
|
||||
authnone_ops()
|
||||
{
|
||||
|
|
@ -171,6 +177,8 @@ authnone_ops()
|
|||
ops.ah_validate = authnone_validate;
|
||||
ops.ah_refresh = authnone_refresh;
|
||||
ops.ah_destroy = authnone_destroy;
|
||||
ops.ah_wrap = authnone_wrap;
|
||||
ops.ah_unwrap = authnone_wrap;
|
||||
}
|
||||
mutex_unlock(&ops_lock);
|
||||
return (&ops);
|
||||
|
|
|
|||
|
|
@ -324,7 +324,7 @@ authsspi_validate(AUTH *auth, struct opaque_auth *verf, u_int seq)
|
|||
#else
|
||||
maj_stat = sspi_verify_mic(&gd->ctx, cur_seq, &signbuf, &checksum, &qop_state);
|
||||
#endif
|
||||
if (maj_stat != SEC_E_OK || qop_state != gd->sec->qop) {
|
||||
if (maj_stat != SEC_E_OK) {
|
||||
log_debug("authsspi_validate: VerifySignature failed with %x", maj_stat);
|
||||
if (maj_stat == SEC_E_NO_AUTHENTICATING_AUTHORITY) {
|
||||
gd->established = FALSE;
|
||||
|
|
@ -373,6 +373,9 @@ authsspi_refresh(AUTH *auth, void *tmp)
|
|||
|
||||
print_rpc_gss_sec(gd->sec);
|
||||
|
||||
if (gd->sec->svc == RPCSEC_SSPI_SVC_PRIVACY)
|
||||
flags |= ISC_REQ_CONFIDENTIALITY;
|
||||
|
||||
for (i=0;;i++) {
|
||||
/* print the token we just received */
|
||||
if (recv_tokenp != SSPI_C_NO_BUFFER) {
|
||||
|
|
@ -498,7 +501,7 @@ authsspi_refresh(AUTH *auth, void *tmp)
|
|||
#else
|
||||
maj_stat = sspi_verify_mic(&gd->ctx, 0, &bufin, &gd->gc_wire_verf, &qop_state);
|
||||
#endif
|
||||
if (maj_stat != SEC_E_OK || qop_state != gd->sec->qop) {
|
||||
if (maj_stat != SEC_E_OK) {
|
||||
log_debug("authgss_refresh: sspi_verify_mic failed with %x", maj_stat);
|
||||
if (maj_stat == SEC_E_NO_AUTHENTICATING_AUTHORITY) {
|
||||
gd->established = FALSE;
|
||||
|
|
@ -623,7 +626,7 @@ authsspi_wrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr)
|
|||
}
|
||||
|
||||
bool_t
|
||||
authsspi_unwrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr)
|
||||
authsspi_unwrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr, u_int seq)
|
||||
{
|
||||
struct rpc_sspi_data *gd;
|
||||
|
||||
|
|
@ -636,7 +639,7 @@ authsspi_unwrap(AUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr)
|
|||
}
|
||||
return (xdr_rpc_sspi_data(xdrs, xdr_func, xdr_ptr,
|
||||
&gd->ctx, gd->sec->qop,
|
||||
gd->sec->svc, gd->gc.gc_seq));
|
||||
gd->sec->svc, seq));
|
||||
}
|
||||
|
||||
uint32_t sspi_get_mic(PCtxtHandle ctx, u_int qop, u_int seq,
|
||||
|
|
@ -720,6 +723,98 @@ uint32_t sspi_import_name(sspi_buffer_desc *name_in, sspi_name_t *name_out)
|
|||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
uint32_t sspi_wrap(PCtxtHandle ctx, u_int seq, sspi_buffer_desc *bufin,
|
||||
sspi_buffer_desc *bufout, u_int *conf_state)
|
||||
{
|
||||
uint32_t maj_stat;
|
||||
SecBufferDesc BuffDesc;
|
||||
SecBuffer SecBuff[3];
|
||||
ULONG ulQop = 0;
|
||||
SecPkgContext_Sizes ContextSizes;
|
||||
PBYTE p;
|
||||
|
||||
maj_stat = QueryContextAttributes(ctx, SECPKG_ATTR_SIZES,
|
||||
&ContextSizes);
|
||||
if (maj_stat != SEC_E_OK)
|
||||
goto out;
|
||||
|
||||
BuffDesc.ulVersion = 0;
|
||||
BuffDesc.cBuffers = 3;
|
||||
BuffDesc.pBuffers = SecBuff;
|
||||
|
||||
SecBuff[0].cbBuffer = ContextSizes.cbSecurityTrailer;
|
||||
SecBuff[0].BufferType = SECBUFFER_TOKEN;
|
||||
SecBuff[0].pvBuffer = malloc(ContextSizes.cbSecurityTrailer);
|
||||
|
||||
SecBuff[1].cbBuffer = bufin->length;
|
||||
SecBuff[1].BufferType = SECBUFFER_DATA;
|
||||
SecBuff[1].pvBuffer = bufin->value;
|
||||
log_hexdump(0, "plaintext:", bufin->value, bufin->length, 0);
|
||||
|
||||
SecBuff[2].cbBuffer = ContextSizes.cbBlockSize;
|
||||
SecBuff[2].BufferType = SECBUFFER_PADDING;
|
||||
SecBuff[2].pvBuffer = malloc(ContextSizes.cbBlockSize);
|
||||
|
||||
maj_stat = EncryptMessage(ctx, ulQop, &BuffDesc, 0);
|
||||
if (maj_stat != SEC_E_OK)
|
||||
goto out_free;
|
||||
|
||||
bufout->length = SecBuff[0].cbBuffer + SecBuff[1].cbBuffer + SecBuff[2].cbBuffer;
|
||||
p = bufout->value = malloc(bufout->length);
|
||||
memcpy(p, SecBuff[0].pvBuffer, SecBuff[0].cbBuffer);
|
||||
p += SecBuff[0].cbBuffer;
|
||||
memcpy(p, SecBuff[1].pvBuffer, SecBuff[1].cbBuffer);
|
||||
p += SecBuff[1].cbBuffer;
|
||||
memcpy(p, SecBuff[2].pvBuffer, SecBuff[2].cbBuffer);
|
||||
out_free:
|
||||
free(SecBuff[0].pvBuffer);
|
||||
free(SecBuff[2].pvBuffer);
|
||||
|
||||
if (!maj_stat)
|
||||
log_hexdump(0, "cipher:", bufout->value, bufout->length, 0);
|
||||
out:
|
||||
return maj_stat;
|
||||
}
|
||||
|
||||
uint32_t sspi_upwrap(PCtxtHandle ctx, sspi_buffer_desc *bufin,
|
||||
sspi_buffer_desc *bufout, u_int *conf_state,
|
||||
u_int *qop_state)
|
||||
{
|
||||
uint32_t maj_stat;
|
||||
SecBufferDesc BuffDesc;
|
||||
SecBuffer SecBuff[2];
|
||||
ULONG ulQop = 0;
|
||||
|
||||
BuffDesc.ulVersion = 0;
|
||||
BuffDesc.cBuffers = 2;
|
||||
BuffDesc.pBuffers = SecBuff;
|
||||
|
||||
SecBuff[0].cbBuffer = bufin->length;
|
||||
SecBuff[0].BufferType = SECBUFFER_STREAM;
|
||||
SecBuff[0].pvBuffer = bufin->value;
|
||||
|
||||
SecBuff[1].cbBuffer = 0;
|
||||
SecBuff[1].BufferType = SECBUFFER_DATA;
|
||||
SecBuff[1].pvBuffer = NULL;
|
||||
|
||||
log_hexdump(0, "cipher:", bufin->value, bufin->length, 0);
|
||||
|
||||
maj_stat = DecryptMessage(ctx, &BuffDesc, 0, &ulQop);
|
||||
if (maj_stat != SEC_E_OK) return maj_stat;
|
||||
|
||||
bufout->length = SecBuff[1].cbBuffer;
|
||||
bufout->value = malloc(bufout->length);
|
||||
memcpy(bufout->value, SecBuff[1].pvBuffer, bufout->length);
|
||||
|
||||
log_hexdump(0, "data:", bufout->value, bufout->length, 0);
|
||||
|
||||
*conf_state = 1;
|
||||
*qop_state = 0;
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
/* useful as i add more mechanisms */
|
||||
#define DEBUG
|
||||
#ifdef DEBUG
|
||||
|
|
|
|||
|
|
@ -353,6 +353,12 @@ marshal_new_auth(auth)
|
|||
XDR_DESTROY(xdrs);
|
||||
}
|
||||
|
||||
static bool_t
|
||||
authunix_wrap(AUTH *auth, XDR *xdrs, xdrproc_t func, caddr_t args, u_int seq)
|
||||
{
|
||||
return ((*func)(xdrs, args));
|
||||
}
|
||||
|
||||
static struct auth_ops *
|
||||
authunix_ops()
|
||||
{
|
||||
|
|
@ -368,6 +374,8 @@ authunix_ops()
|
|||
ops.ah_validate = authunix_validate;
|
||||
ops.ah_refresh = authunix_refresh;
|
||||
ops.ah_destroy = authunix_destroy;
|
||||
ops.ah_wrap = authunix_wrap;
|
||||
ops.ah_unwrap = authunix_wrap;
|
||||
}
|
||||
mutex_unlock(&ops_lock);
|
||||
return (&ops);
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ xdr_rpc_sspi_wrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
|
|||
|
||||
/* Skip databody length. */
|
||||
start = XDR_GETPOS(xdrs);
|
||||
//XDR_SETPOS(xdrs, start + 4);
|
||||
XDR_SETPOS(xdrs, start + 4);
|
||||
|
||||
/* Marshal rpc_gss_data_t (sequence number + arguments). */
|
||||
if (!xdr_u_int(xdrs, &seq) || !(*xdr_func)(xdrs, xdr_ptr))
|
||||
|
|
@ -117,15 +117,14 @@ xdr_rpc_sspi_wrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
|
|||
|
||||
/* Set databuf to marshalled rpc_gss_data_t. */
|
||||
databuf.length = end - start - 4;
|
||||
//XDR_SETPOS(xdrs, start + 4);
|
||||
//databuf.value = XDR_INLINE(xdrs, databuf.length);
|
||||
databuf.value = xdrrec_getoutbase(xdrs) + 1;
|
||||
XDR_SETPOS(xdrs, start + 4);
|
||||
databuf.value = XDR_INLINE(xdrs, databuf.length);
|
||||
|
||||
xdr_stat = FALSE;
|
||||
|
||||
if (svc == RPCSEC_SSPI_SVC_INTEGRITY) {
|
||||
/* Marshal databody_integ length. */
|
||||
//XDR_SETPOS(xdrs, start);
|
||||
XDR_SETPOS(xdrs, start);
|
||||
if (!xdr_u_int(xdrs, (u_int *)&databuf.length))
|
||||
return (FALSE);
|
||||
|
||||
|
|
@ -141,9 +140,9 @@ xdr_rpc_sspi_wrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
|
|||
return (FALSE);
|
||||
}
|
||||
/* Marshal checksum. */
|
||||
//XDR_SETPOS(xdrs, end);
|
||||
XDR_SETPOS(xdrs, end);
|
||||
xdr_stat = xdr_bytes(xdrs, (char **)&wrapbuf.value,
|
||||
(u_int *)&wrapbuf.length, MAX_NETOBJ_SZ);
|
||||
(u_int *)&wrapbuf.length, (u_int)-1);
|
||||
#if 0
|
||||
gss_release_buffer(&min_stat, &wrapbuf);
|
||||
#else
|
||||
|
|
@ -155,6 +154,8 @@ xdr_rpc_sspi_wrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
|
|||
#if 0
|
||||
maj_stat = gss_wrap(&min_stat, ctx, TRUE, qop, &databuf,
|
||||
&conf_state, &wrapbuf);
|
||||
#else
|
||||
maj_stat = sspi_wrap(ctx, 0, &databuf, &wrapbuf, &conf_state);
|
||||
#endif
|
||||
if (maj_stat != SEC_E_OK) {
|
||||
log_debug("xdr_rpc_sspi_wrap_data: sspi_wrap failed with %x", maj_stat);
|
||||
|
|
@ -163,7 +164,7 @@ xdr_rpc_sspi_wrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
|
|||
/* Marshal databody_priv. */
|
||||
XDR_SETPOS(xdrs, start);
|
||||
xdr_stat = xdr_bytes(xdrs, (char **)&wrapbuf.value,
|
||||
(u_int *)&wrapbuf.length, MAX_NETOBJ_SZ);
|
||||
(u_int *)&wrapbuf.length, (u_int)-1);
|
||||
#if 0
|
||||
gss_release_buffer(&min_stat, &wrapbuf);
|
||||
#else
|
||||
|
|
@ -196,7 +197,7 @@ xdr_rpc_sspi_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
|
|||
if (svc == RPCSEC_SSPI_SVC_INTEGRITY) {
|
||||
/* Decode databody_integ. */
|
||||
if (!xdr_bytes(xdrs, (char **)&databuf.value, (u_int *)&databuf.length,
|
||||
MAX_NETOBJ_SZ)) {
|
||||
(u_int)-1)) {
|
||||
log_debug("xdr_rpc_sspi_unwrap_data: xdr decode databody_integ failed");
|
||||
return (FALSE);
|
||||
}
|
||||
|
|
@ -224,7 +225,7 @@ xdr_rpc_sspi_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
|
|||
sspi_release_buffer(&wrapbuf);
|
||||
#endif
|
||||
|
||||
if (maj_stat != SEC_E_OK || qop_state != qop) {
|
||||
if (maj_stat != SEC_E_OK) {
|
||||
#if 0
|
||||
gss_release_buffer(&min_stat, &databuf);
|
||||
#else
|
||||
|
|
@ -238,7 +239,7 @@ xdr_rpc_sspi_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
|
|||
else if (svc == RPCSEC_SSPI_SVC_PRIVACY) {
|
||||
/* Decode databody_priv. */
|
||||
if (!xdr_bytes(xdrs, (char **)&wrapbuf.value, (u_int *)&wrapbuf.length,
|
||||
MAX_NETOBJ_SZ)) {
|
||||
(u_int)-1)) {
|
||||
log_debug("xdr_rpc_sspi_unwrap_data: xdr decode databody_priv failed");
|
||||
return (FALSE);
|
||||
}
|
||||
|
|
@ -246,6 +247,8 @@ xdr_rpc_sspi_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
|
|||
#if 0
|
||||
maj_stat = gss_unwrap(&min_stat, ctx, &wrapbuf, &databuf,
|
||||
&conf_state, &qop_state);
|
||||
#else
|
||||
maj_stat = sspi_upwrap(ctx, &wrapbuf, &databuf, &conf_state, &qop_state);
|
||||
#endif
|
||||
#if 0
|
||||
gss_release_buffer(&min_stat, &wrapbuf);
|
||||
|
|
@ -253,8 +256,7 @@ xdr_rpc_sspi_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
|
|||
sspi_release_buffer(&wrapbuf);
|
||||
#endif
|
||||
/* Verify encryption and QOP. */
|
||||
if (maj_stat != SEC_E_OK || qop_state != qop ||
|
||||
conf_state != TRUE) {
|
||||
if (maj_stat != SEC_E_OK) {
|
||||
#if 0
|
||||
gss_release_buffer(&min_stat, &databuf);
|
||||
#else
|
||||
|
|
@ -276,7 +278,8 @@ xdr_rpc_sspi_unwrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr,
|
|||
#endif
|
||||
/* Verify sequence number. */
|
||||
if (xdr_stat == TRUE && seq_num != seq) {
|
||||
log_debug("wrong sequence number in databody");
|
||||
log_debug("wrong sequence number in databody received %d expected %d",
|
||||
seq_num, seq);
|
||||
return (FALSE);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -523,13 +523,14 @@ call_again:
|
|||
if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcallc, ct->ct_mpos)) ||
|
||||
(! XDR_PUTINT32(xdrs, (int32_t *)&proc)) ||
|
||||
(! AUTH_MARSHALL(cl->cl_auth, xdrs, &seq)) ||
|
||||
(! (*xdr_args)(xdrs, args_ptr))) {
|
||||
(! AUTH_WRAP(cl->cl_auth, xdrs, xdr_args, args_ptr))) {
|
||||
if (ct->ct_error.re_status == RPC_SUCCESS)
|
||||
ct->ct_error.re_status = RPC_CANTENCODEARGS;
|
||||
(void)xdrrec_endofrecord(xdrs, TRUE);
|
||||
release_fd_lock(ct->ct_fd, mask);
|
||||
return (ct->ct_error.re_status);
|
||||
}
|
||||
|
||||
if (! xdrrec_endofrecord(xdrs, shipnow)) {
|
||||
release_fd_lock(ct->ct_fd, mask);
|
||||
ct->ct_error.re_status = RPC_CANTSEND;
|
||||
|
|
@ -613,7 +614,8 @@ call_again:
|
|||
&ct->reply_msg.acpted_rply.ar_verf, seq)) {
|
||||
ct->ct_error.re_status = RPC_AUTHERROR;
|
||||
ct->ct_error.re_why = AUTH_INVALIDRESP;
|
||||
} else if (! (*xdr_results)(xdrs, results_ptr)) {
|
||||
}
|
||||
else if (! AUTH_UNWRAP(cl->cl_auth, xdrs, xdr_results, results_ptr, seq)) {
|
||||
if (ct->ct_error.re_status == RPC_SUCCESS)
|
||||
ct->ct_error.re_status = RPC_CANTDECODERES;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ typedef struct __auth {
|
|||
/* encode data for wire */
|
||||
int (*ah_wrap) (struct __auth *, XDR *, xdrproc_t, caddr_t);
|
||||
/* decode data for wire */
|
||||
int (*ah_unwrap) (struct __auth *, XDR *, xdrproc_t, caddr_t);
|
||||
int (*ah_unwrap) (struct __auth *, XDR *, xdrproc_t, caddr_t, u_int);
|
||||
|
||||
} *ah_ops;
|
||||
void *ah_private;
|
||||
|
|
@ -245,12 +245,12 @@ typedef struct __auth {
|
|||
((*((auth)->ah_ops->ah_wrap))(auth, xdrs, \
|
||||
xfunc, xwhere))
|
||||
|
||||
#define AUTH_UNWRAP(auth, xdrs, xfunc, xwhere) \
|
||||
#define AUTH_UNWRAP(auth, xdrs, xfunc, xwhere, seq) \
|
||||
((*((auth)->ah_ops->ah_unwrap))(auth, xdrs, \
|
||||
xfunc, xwhere))
|
||||
#define auth_unwrap(auth, xdrs, xfunc, xwhere) \
|
||||
xfunc, xwhere, seq))
|
||||
#define auth_unwrap(auth, xdrs, xfunc, xwhere, seq) \
|
||||
((*((auth)->ah_ops->ah_unwrap))(auth, xdrs, \
|
||||
xfunc, xwhere))
|
||||
xfunc, xwhere, seq))
|
||||
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
|
|
|||
|
|
@ -105,6 +105,11 @@ uint32_t sspi_get_mic(void *ctx, u_int qop, u_int seq,
|
|||
sspi_buffer_desc *bufin, sspi_buffer_desc *bufout);
|
||||
uint32_t sspi_verify_mic(void *ctx, u_int seq, sspi_buffer_desc *bufin,
|
||||
sspi_buffer_desc *bufout, u_int *qop_state);
|
||||
uint32_t sspi_wrap(void *ctx, u_int seq, sspi_buffer_desc *bufin,
|
||||
sspi_buffer_desc *bufout, u_int *conf_state);
|
||||
uint32_t sspi_unwrap(void *ctx, sspi_buffer_desc *bufin,
|
||||
sspi_buffer_desc *bufout, u_int *conf_state,
|
||||
u_int *qop_state);
|
||||
void sspi_release_buffer(sspi_buffer_desc *buf);
|
||||
uint32_t sspi_import_name(sspi_buffer_desc *name_in, sspi_name_t *name_out);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue