DNS_ERROR dns_sign_update(struct dns_update_request *req, gss_ctx_id_t gss_ctx, const char *keyname, const char *algorithmname, time_t time_signed, uint16 fudge) { struct dns_buffer *buf; DNS_ERROR err; struct dns_domain_name *key, *algorithm; struct gss_buffer_desc_struct msg, mic; OM_uint32 major, minor; struct dns_rrec *rec; err = dns_marshall_update_request(req, req, &buf); if (!ERR_DNS_IS_OK(err)) return err; err = dns_domain_name_from_string(buf, keyname, &key); if (!ERR_DNS_IS_OK(err)) goto error; err = dns_domain_name_from_string(buf, algorithmname, &algorithm); if (!ERR_DNS_IS_OK(err)) goto error; dns_marshall_domain_name(buf, key); dns_marshall_uint16(buf, DNS_CLASS_ANY); dns_marshall_uint32(buf, 0); /* TTL */ dns_marshall_domain_name(buf, algorithm); dns_marshall_uint16(buf, 0); /* Time prefix for 48-bit time_t */ dns_marshall_uint32(buf, time_signed); dns_marshall_uint16(buf, fudge); dns_marshall_uint16(buf, 0); /* error */ dns_marshall_uint16(buf, 0); /* other len */ err = buf->error; if (!ERR_DNS_IS_OK(buf->error)) goto error; msg.value = (void *)buf->data; msg.length = buf->offset; major = gss_get_mic(&minor, gss_ctx, 0, &msg, &mic); if (major != 0) { err = ERROR_DNS_GSS_ERROR; goto error; } if (mic.length > 0xffff) { gss_release_buffer(&minor, &mic); err = ERROR_DNS_GSS_ERROR; goto error; } err = dns_create_tsig_record(buf, keyname, algorithmname, time_signed, fudge, mic.length, (uint8 *)mic.value, req->id, 0, &rec); gss_release_buffer(&minor, &mic); if (!ERR_DNS_IS_OK(err)) goto error; err = dns_add_rrec(req, rec, &req->num_additionals, &req->additionals); error: TALLOC_FREE(buf); return err; }
/* * Send a reply. Note that we only need to send a reply if we * need to send a MIC or a mechanism token. Otherwise, we can * return an empty buffer. * * The return value of this will be returned to the API, so it * must return GSS_S_CONTINUE_NEEDED if a token was generated. */ static OM_uint32 spnego_reply_internal(OM_uint32 *minor_status, gssspnego_ctx context_handle, const gss_buffer_t mech_buf, gss_buffer_t mech_token, gss_buffer_t output_token) { NegotiationToken nt; gss_buffer_desc mic_buf; OM_uint32 ret; size_t size; if (mech_buf == GSS_C_NO_BUFFER && mech_token->length == 0) { output_token->length = 0; output_token->value = NULL; return context_handle->open ? GSS_S_COMPLETE : GSS_S_FAILURE; } memset(&nt, 0, sizeof(nt)); nt.element = choice_NegotiationToken_negTokenResp; ALLOC(nt.u.negTokenResp.negResult, 1); if (nt.u.negTokenResp.negResult == NULL) { *minor_status = ENOMEM; return GSS_S_FAILURE; } nt.u.negTokenResp.supportedMech = NULL; output_token->length = 0; output_token->value = NULL; if (mech_token->length == 0) { nt.u.negTokenResp.responseToken = NULL; *(nt.u.negTokenResp.negResult) = accept_completed; } else { ALLOC(nt.u.negTokenResp.responseToken, 1); if (nt.u.negTokenResp.responseToken == NULL) { free_NegotiationToken(&nt); *minor_status = ENOMEM; return GSS_S_FAILURE; } nt.u.negTokenResp.responseToken->length = mech_token->length; nt.u.negTokenResp.responseToken->data = mech_token->value; mech_token->length = 0; mech_token->value = NULL; *(nt.u.negTokenResp.negResult) = accept_incomplete; } if (mech_buf != GSS_C_NO_BUFFER) { ret = gss_get_mic(minor_status, context_handle->negotiated_ctx_id, 0, mech_buf, &mic_buf); if (ret == GSS_S_COMPLETE) { ALLOC(nt.u.negTokenResp.mechListMIC, 1); if (nt.u.negTokenResp.mechListMIC == NULL) { gss_release_buffer(minor_status, &mic_buf); free_NegotiationToken(&nt); *minor_status = ENOMEM; return GSS_S_FAILURE; } nt.u.negTokenResp.mechListMIC->length = mic_buf.length; nt.u.negTokenResp.mechListMIC->data = mic_buf.value; } else if (ret == GSS_S_UNAVAILABLE) { nt.u.negTokenResp.mechListMIC = NULL; } if (ret) { free_NegotiationToken(&nt); *minor_status = ENOMEM; return GSS_S_FAILURE; } } else { nt.u.negTokenResp.mechListMIC = NULL; } ASN1_MALLOC_ENCODE(NegotiationToken, output_token->value, output_token->length, &nt, &size, ret); if (ret) { free_NegotiationToken(&nt); *minor_status = ret; return GSS_S_FAILURE; } if (*(nt.u.negTokenResp.negResult) == accept_completed) ret = GSS_S_COMPLETE; else ret = GSS_S_CONTINUE_NEEDED; free_NegotiationToken(&nt); return ret; }
bool_t xdr_rpc_gss_wrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr, gss_ctx_id_t ctx, gss_qop_t qop, rpc_gss_svc_t svc, u_int seq) { gss_buffer_desc databuf, wrapbuf; OM_uint32 maj_stat, min_stat; int start, end, conf_state; bool_t xdr_stat; u_int databuflen, maxwrapsz; /* Skip databody length. */ start = XDR_GETPOS(xdrs); XDR_SETPOS(xdrs, start + 4); memset(&databuf, 0, sizeof(databuf)); memset(&wrapbuf, 0, sizeof(wrapbuf)); /* Marshal rpc_gss_data_t (sequence number + arguments). */ if (!xdr_u_int(xdrs, &seq) || !(*xdr_func)(xdrs, xdr_ptr)) return (FALSE); end = XDR_GETPOS(xdrs); /* Set databuf to marshalled rpc_gss_data_t. */ databuflen = end - start - 4; XDR_SETPOS(xdrs, start + 4); databuf.value = XDR_INLINE(xdrs, databuflen); xdr_stat = FALSE; if (svc == RPCSEC_GSS_SVC_INTEGRITY) { /* Marshal databody_integ length. */ XDR_SETPOS(xdrs, start); if (!xdr_u_int(xdrs, (u_int *)&databuflen)) return (FALSE); databuf.length = databuflen; /* Checksum rpc_gss_data_t. */ maj_stat = gss_get_mic(&min_stat, ctx, qop, &databuf, &wrapbuf); if (maj_stat != GSS_S_COMPLETE) { log_debug("gss_get_mic failed"); return (FALSE); } /* Marshal checksum. */ XDR_SETPOS(xdrs, end); maxwrapsz = (u_int)(wrapbuf.length + RPC_SLACK_SPACE); xdr_stat = xdr_rpc_gss_buf(xdrs, &wrapbuf, maxwrapsz); gss_release_buffer(&min_stat, &wrapbuf); } else if (svc == RPCSEC_GSS_SVC_PRIVACY) { /* Encrypt rpc_gss_data_t. */ maj_stat = gss_wrap(&min_stat, ctx, TRUE, qop, &databuf, &conf_state, &wrapbuf); if (maj_stat != GSS_S_COMPLETE) { log_status("gss_wrap", maj_stat, min_stat); return (FALSE); } /* Marshal databody_priv. */ XDR_SETPOS(xdrs, start); maxwrapsz = (u_int)(wrapbuf.length + RPC_SLACK_SPACE); xdr_stat = xdr_rpc_gss_buf(xdrs, &wrapbuf, maxwrapsz); gss_release_buffer(&min_stat, &wrapbuf); } return (xdr_stat); }
static bool_t authgss_marshal(AUTH *auth, XDR *xdrs) { XDR tmpxdrs; char tmp[MAX_AUTH_BYTES]; struct rpc_gss_data *gd; gss_buffer_desc rpcbuf, checksum; OM_uint32 maj_stat, min_stat; bool_t xdr_stat; log_debug("in authgss_marshal()"); gd = AUTH_PRIVATE(auth); if (gd->established) gd->gc.gc_seq++; xdrmem_create(&tmpxdrs, tmp, sizeof(tmp), XDR_ENCODE); if (!xdr_rpc_gss_cred(&tmpxdrs, &gd->gc)) { XDR_DESTROY(&tmpxdrs); return (FALSE); } auth->ah_cred.oa_flavor = RPCSEC_GSS; auth->ah_cred.oa_base = tmp; auth->ah_cred.oa_length = XDR_GETPOS(&tmpxdrs); XDR_DESTROY(&tmpxdrs); if (!xdr_opaque_auth(xdrs, &auth->ah_cred)) return (FALSE); if (gd->gc.gc_proc == RPCSEC_GSS_INIT || gd->gc.gc_proc == RPCSEC_GSS_CONTINUE_INIT) { return (xdr_opaque_auth(xdrs, &_null_auth)); } /* Checksum serialized RPC header, up to and including credential. */ rpcbuf.length = XDR_GETPOS(xdrs); XDR_SETPOS(xdrs, 0); rpcbuf.value = XDR_INLINE(xdrs, rpcbuf.length); maj_stat = gss_get_mic(&min_stat, gd->ctx, gd->sec.qop, &rpcbuf, &checksum); if (maj_stat != GSS_S_COMPLETE) { log_status("gss_get_mic", maj_stat, min_stat); if (maj_stat == GSS_S_CONTEXT_EXPIRED) { gd->established = FALSE; authgss_destroy_context(auth); } return (FALSE); } auth->ah_verf.oa_flavor = RPCSEC_GSS; auth->ah_verf.oa_base = checksum.value; auth->ah_verf.oa_length = checksum.length; xdr_stat = xdr_opaque_auth(xdrs, &auth->ah_verf); gss_release_buffer(&min_stat, &checksum); return (xdr_stat); }
static int proto (int sock, const char *hostname, const char *service) { struct sockaddr_in remote, local; socklen_t addrlen; int context_established = 0; gss_ctx_id_t context_hdl = GSS_C_NO_CONTEXT; gss_buffer_t input_token, output_token; gss_buffer_desc real_input_token, real_output_token; OM_uint32 maj_stat, min_stat; gss_name_t server; gss_buffer_desc name_token; char *str; name_token.length = asprintf (&str, "%s@%s", service, hostname); if (str == NULL) errx(1, "out of memory"); name_token.value = str; maj_stat = gss_import_name (&min_stat, &name_token, GSS_C_NT_HOSTBASED_SERVICE, &server); if (GSS_ERROR(maj_stat)) gss_err (1, min_stat, "Error importing name `%s@%s':\n", service, hostname); addrlen = sizeof(local); if (getsockname (sock, (struct sockaddr *)&local, &addrlen) < 0 || addrlen != sizeof(local)) err (1, "getsockname(%s)", hostname); addrlen = sizeof(remote); if (getpeername (sock, (struct sockaddr *)&remote, &addrlen) < 0 || addrlen != sizeof(remote)) err (1, "getpeername(%s)", hostname); input_token = &real_input_token; output_token = &real_output_token; input_token->length = 0; output_token->length = 0; while(!context_established) { maj_stat = gss_init_sec_context(&min_stat, GSS_C_NO_CREDENTIAL, &context_hdl, server, GSS_C_NO_OID, GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG, 0, GSS_C_NO_CHANNEL_BINDINGS, input_token, NULL, output_token, NULL, NULL); if (GSS_ERROR(maj_stat)) gss_err (1, min_stat, "gss_init_sec_context"); if (output_token->length != 0) nt_write_token (sock, output_token); if (GSS_ERROR(maj_stat)) { if (context_hdl != GSS_C_NO_CONTEXT) gss_delete_sec_context (&min_stat, &context_hdl, GSS_C_NO_BUFFER); break; } if (maj_stat & GSS_S_CONTINUE_NEEDED) { nt_read_token (sock, input_token); } else { context_established = 1; } } /* get_mic */ input_token->length = 3; input_token->value = strdup("hej"); maj_stat = gss_get_mic(&min_stat, context_hdl, GSS_C_QOP_DEFAULT, input_token, output_token); if (GSS_ERROR(maj_stat)) gss_err (1, min_stat, "gss_get_mic"); nt_write_token (sock, input_token); nt_write_token (sock, output_token); /* wrap */ input_token->length = 7; input_token->value = "hemligt"; maj_stat = gss_wrap (&min_stat, context_hdl, 1, GSS_C_QOP_DEFAULT, input_token, NULL, output_token); if (GSS_ERROR(maj_stat)) gss_err (1, min_stat, "gss_wrap"); nt_write_token (sock, output_token); return 0; }
int main(int argc, char **argv) { struct module_stat stat; int mod; int syscall_num; stat.version = sizeof(stat); mod = modfind("gsstest_syscall"); if (mod < 0) { fprintf(stderr, "%s: kernel support not present\n", argv[0]); exit(1); } modstat(mod, &stat); syscall_num = stat.data.intval; switch (atoi(argv[1])) { case 1: syscall(syscall_num, 1, NULL, NULL); break; case 2: { struct gsstest_2_args args; struct gsstest_2_res res; char hostname[512]; char token_buffer[8192]; OM_uint32 maj_stat, min_stat; gss_ctx_id_t client_context = GSS_C_NO_CONTEXT; gss_cred_id_t client_cred; gss_OID mech_type = GSS_C_NO_OID; gss_buffer_desc name_buf, message_buf; gss_name_t name; int32_t enctypes[] = { ETYPE_DES_CBC_CRC, ETYPE_ARCFOUR_HMAC_MD5, ETYPE_ARCFOUR_HMAC_MD5_56, ETYPE_AES256_CTS_HMAC_SHA1_96, ETYPE_AES128_CTS_HMAC_SHA1_96, ETYPE_DES3_CBC_SHA1, }; int num_enctypes = sizeof(enctypes) / sizeof(enctypes[0]); int established; int i; for (i = 0; i < num_enctypes; i++) { printf("testing etype %d\n", enctypes[i]); args.output_token.length = sizeof(token_buffer); args.output_token.value = token_buffer; gethostname(hostname, sizeof(hostname)); snprintf(token_buffer, sizeof(token_buffer), "nfs@%s", hostname); name_buf.length = strlen(token_buffer); name_buf.value = token_buffer; maj_stat = gss_import_name(&min_stat, &name_buf, GSS_C_NT_HOSTBASED_SERVICE, &name); if (GSS_ERROR(maj_stat)) { printf("gss_import_name failed\n"); report_error(mech_type, maj_stat, min_stat); goto out; } maj_stat = gss_acquire_cred(&min_stat, GSS_C_NO_NAME, 0, GSS_C_NO_OID_SET, GSS_C_INITIATE, &client_cred, NULL, NULL); if (GSS_ERROR(maj_stat)) { printf("gss_acquire_cred (client) failed\n"); report_error(mech_type, maj_stat, min_stat); goto out; } maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, client_cred, 1, &enctypes[i]); if (GSS_ERROR(maj_stat)) { printf("gss_krb5_set_allowable_enctypes failed\n"); report_error(mech_type, maj_stat, min_stat); goto out; } res.output_token.length = 0; res.output_token.value = 0; established = 0; while (!established) { maj_stat = gss_init_sec_context(&min_stat, client_cred, &client_context, name, GSS_C_NO_OID, (GSS_C_MUTUAL_FLAG |GSS_C_CONF_FLAG |GSS_C_INTEG_FLAG |GSS_C_SEQUENCE_FLAG |GSS_C_REPLAY_FLAG), 0, GSS_C_NO_CHANNEL_BINDINGS, &res.output_token, &mech_type, &args.input_token, NULL, NULL); if (GSS_ERROR(maj_stat)) { printf("gss_init_sec_context failed\n"); report_error(mech_type, maj_stat, min_stat); goto out; } if (args.input_token.length) { args.step = 1; syscall(syscall_num, 2, &args, &res); gss_release_buffer(&min_stat, &args.input_token); if (res.maj_stat != GSS_S_COMPLETE && res.maj_stat != GSS_S_CONTINUE_NEEDED) { printf("gss_accept_sec_context (kernel) failed\n"); report_error(mech_type, res.maj_stat, res.min_stat); goto out; } } if (maj_stat == GSS_S_COMPLETE) established = 1; } message_buf.value = "Hello world"; message_buf.length = strlen((char *) message_buf.value); maj_stat = gss_get_mic(&min_stat, client_context, GSS_C_QOP_DEFAULT, &message_buf, &args.input_token); if (GSS_ERROR(maj_stat)) { printf("gss_get_mic failed\n"); report_error(mech_type, maj_stat, min_stat); goto out; } args.step = 2; syscall(syscall_num, 2, &args, &res); gss_release_buffer(&min_stat, &args.input_token); if (GSS_ERROR(res.maj_stat)) { printf("kernel gss_verify_mic failed\n"); report_error(mech_type, res.maj_stat, res.min_stat); goto out; } maj_stat = gss_verify_mic(&min_stat, client_context, &message_buf, &res.output_token, NULL); if (GSS_ERROR(maj_stat)) { printf("gss_verify_mic failed\n"); report_error(mech_type, maj_stat, min_stat); goto out; } maj_stat = gss_wrap(&min_stat, client_context, TRUE, GSS_C_QOP_DEFAULT, &message_buf, NULL, &args.input_token); if (GSS_ERROR(maj_stat)) { printf("gss_wrap failed\n"); report_error(mech_type, maj_stat, min_stat); goto out; } args.step = 3; syscall(syscall_num, 2, &args, &res); gss_release_buffer(&min_stat, &args.input_token); if (GSS_ERROR(res.maj_stat)) { printf("kernel gss_unwrap failed\n"); report_error(mech_type, res.maj_stat, res.min_stat); goto out; } maj_stat = gss_unwrap(&min_stat, client_context, &res.output_token, &message_buf, NULL, NULL); if (GSS_ERROR(maj_stat)) { printf("gss_unwrap failed\n"); report_error(mech_type, maj_stat, min_stat); goto out; } gss_release_buffer(&min_stat, &message_buf); maj_stat = gss_wrap(&min_stat, client_context, FALSE, GSS_C_QOP_DEFAULT, &message_buf, NULL, &args.input_token); if (GSS_ERROR(maj_stat)) { printf("gss_wrap failed\n"); report_error(mech_type, maj_stat, min_stat); goto out; } args.step = 4; syscall(syscall_num, 2, &args, &res); gss_release_buffer(&min_stat, &args.input_token); if (GSS_ERROR(res.maj_stat)) { printf("kernel gss_unwrap failed\n"); report_error(mech_type, res.maj_stat, res.min_stat); goto out; } maj_stat = gss_unwrap(&min_stat, client_context, &res.output_token, &message_buf, NULL, NULL); if (GSS_ERROR(maj_stat)) { printf("gss_unwrap failed\n"); report_error(mech_type, maj_stat, min_stat); goto out; } gss_release_buffer(&min_stat, &message_buf); args.step = 5; syscall(syscall_num, 2, &args, &res); gss_release_name(&min_stat, &name); gss_release_cred(&min_stat, &client_cred); gss_delete_sec_context(&min_stat, &client_context, GSS_C_NO_BUFFER); } break; } case 3: syscall(syscall_num, 3, NULL, NULL); break; case 4: syscall(syscall_num, 4, NULL, NULL); break; } return (0); out: return (1); }
bool_t xdr_rpc_gss_wrap_data(XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr, gss_ctx_id_t ctx, gss_qop_t qop, rpc_gss_service_t svc, u_int seq) { gss_buffer_desc databuf, wrapbuf; OM_uint32 maj_stat, min_stat; int start, end, conf_state; u_int len; bool_t xdr_stat; /* Skip databody length. */ start = XDR_GETPOS(xdrs); XDR_SETPOS(xdrs, start + 4); /* Marshal rpc_gss_data_t (sequence number + arguments). */ if (!xdr_u_int(xdrs, &seq) || !xdr_func(xdrs, xdr_ptr)) return (FALSE); end = XDR_GETPOS(xdrs); /* 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); xdr_stat = FALSE; if (svc == rpc_gss_svc_integrity) { /* Marshal databody_integ length. */ XDR_SETPOS(xdrs, start); len = databuf.length; if (!xdr_u_int(xdrs, &len)) return (FALSE); /* Checksum rpc_gss_data_t. */ maj_stat = gss_get_mic(&min_stat, ctx, qop, &databuf, &wrapbuf); if (maj_stat != GSS_S_COMPLETE) { log_debug("gss_get_mic failed"); return (FALSE); } /* Marshal checksum. */ XDR_SETPOS(xdrs, end); xdr_stat = xdr_gss_buffer_desc(xdrs, &wrapbuf); gss_release_buffer(&min_stat, &wrapbuf); } else if (svc == rpc_gss_svc_privacy) { /* Encrypt rpc_gss_data_t. */ maj_stat = gss_wrap(&min_stat, ctx, TRUE, qop, &databuf, &conf_state, &wrapbuf); if (maj_stat != GSS_S_COMPLETE) { log_status("gss_wrap", NULL, maj_stat, min_stat); return (FALSE); } /* Marshal databody_priv. */ XDR_SETPOS(xdrs, start); xdr_stat = xdr_gss_buffer_desc(xdrs, &wrapbuf); gss_release_buffer(&min_stat, &wrapbuf); } return (xdr_stat); }
static OM_uint32 send_accept (OM_uint32 *minor_status, gssspnego_ctx context_handle, gss_buffer_t mech_token, int initial_response, gss_buffer_t mech_buf, gss_buffer_t output_token) { NegotiationToken nt; OM_uint32 ret; gss_buffer_desc mech_mic_buf; size_t size; memset(&nt, 0, sizeof(nt)); nt.element = choice_NegotiationToken_negTokenResp; ALLOC(nt.u.negTokenResp.negResult, 1); if (nt.u.negTokenResp.negResult == NULL) { *minor_status = ENOMEM; return GSS_S_FAILURE; } if (context_handle->open) { if (mech_token != GSS_C_NO_BUFFER && mech_token->length != 0 && mech_buf != GSS_C_NO_BUFFER) *(nt.u.negTokenResp.negResult) = accept_incomplete; else *(nt.u.negTokenResp.negResult) = accept_completed; } else { if (initial_response && context_handle->require_mic) *(nt.u.negTokenResp.negResult) = request_mic; else *(nt.u.negTokenResp.negResult) = accept_incomplete; } if (initial_response) { ALLOC(nt.u.negTokenResp.supportedMech, 1); if (nt.u.negTokenResp.supportedMech == NULL) { free_NegotiationToken(&nt); *minor_status = ENOMEM; return GSS_S_FAILURE; } ret = der_get_oid(context_handle->preferred_mech_type->elements, context_handle->preferred_mech_type->length, nt.u.negTokenResp.supportedMech, NULL); if (ret) { free_NegotiationToken(&nt); *minor_status = ENOMEM; return GSS_S_FAILURE; } } else { nt.u.negTokenResp.supportedMech = NULL; } if (mech_token != GSS_C_NO_BUFFER && mech_token->length != 0) { ALLOC(nt.u.negTokenResp.responseToken, 1); if (nt.u.negTokenResp.responseToken == NULL) { free_NegotiationToken(&nt); *minor_status = ENOMEM; return GSS_S_FAILURE; } nt.u.negTokenResp.responseToken->length = mech_token->length; nt.u.negTokenResp.responseToken->data = mech_token->value; mech_token->length = 0; mech_token->value = NULL; } else { nt.u.negTokenResp.responseToken = NULL; } if (mech_buf != GSS_C_NO_BUFFER) { ret = gss_get_mic(minor_status, context_handle->negotiated_ctx_id, 0, mech_buf, &mech_mic_buf); if (ret == GSS_S_COMPLETE) { ALLOC(nt.u.negTokenResp.mechListMIC, 1); if (nt.u.negTokenResp.mechListMIC == NULL) { gss_release_buffer(minor_status, &mech_mic_buf); free_NegotiationToken(&nt); *minor_status = ENOMEM; return GSS_S_FAILURE; } nt.u.negTokenResp.mechListMIC->length = mech_mic_buf.length; nt.u.negTokenResp.mechListMIC->data = mech_mic_buf.value; } else if (ret == GSS_S_UNAVAILABLE) { nt.u.negTokenResp.mechListMIC = NULL; } else { free_NegotiationToken(&nt); return ret; } } else nt.u.negTokenResp.mechListMIC = NULL; ASN1_MALLOC_ENCODE(NegotiationToken, output_token->value, output_token->length, &nt, &size, ret); if (ret) { free_NegotiationToken(&nt); *minor_status = ret; return GSS_S_FAILURE; } /* * The response should not be encapsulated, because * it is a SubsequentContextToken (note though RFC 1964 * specifies encapsulation for all _Kerberos_ tokens). */ if (*(nt.u.negTokenResp.negResult) == accept_completed) ret = GSS_S_COMPLETE; else ret = GSS_S_CONTINUE_NEEDED; free_NegotiationToken(&nt); return ret; }
/** * @brief Wrap * @ingroup globus_gsi_gssapi * @details * Wrap a message for integrity and protection. * We do this using the SSLv3 routines, by writing to the * SSL bio, and pulling off the buffer from the back * of the write BIO. But we can't do everything SSL * might want, such as control messages, or segment the messages * here, since we are forced to using the GSSAPI tokens, * and can not communicate directly with our peer. * So there maybe some failures which would work with true * SSL. * * @param minor_status * @param context_handle * @param conf_req_flag * @param qop_req * @param input_message_buffer * @param conf_state * @param output_message_buffer * * @return */ OM_uint32 GSS_CALLCONV gss_wrap( OM_uint32 * minor_status, const gss_ctx_id_t context_handle, int conf_req_flag, gss_qop_t qop_req, const gss_buffer_t input_message_buffer, int * conf_state, gss_buffer_t output_message_buffer) { gss_ctx_id_desc * context = (gss_ctx_id_desc *)context_handle; gss_buffer_desc mic_buf_desc; gss_buffer_t mic_buf = (gss_buffer_desc *) &mic_buf_desc; OM_uint32 major_status = GSS_S_COMPLETE; OM_uint32 local_minor_status; unsigned char * message_value; time_t context_goodtill; static char * _function_name_ = "gss_wrap"; GLOBUS_I_GSI_GSSAPI_DEBUG_ENTER; *minor_status = (OM_uint32) GLOBUS_SUCCESS; if(GLOBUS_I_GSI_GSSAPI_DEBUG(3)) { BIO * debug_bio; fprintf(globus_i_gsi_gssapi_debug_fstream, "input message: length = %u\n" " value = \n", (unsigned) input_message_buffer->length); debug_bio = BIO_new_fp(globus_i_gsi_gssapi_debug_fstream, BIO_NOCLOSE); BIO_dump(debug_bio, input_message_buffer->value, input_message_buffer->length); } output_message_buffer->value = NULL; output_message_buffer->length = 0; GLOBUS_I_GSI_GSSAPI_DEBUG_FPRINTF( 2, (globus_i_gsi_gssapi_debug_fstream, "gss_wrap conf_req_flag=%d qop_req=%d\n", conf_req_flag, (int) qop_req)); if (context_handle == GSS_C_NO_CONTEXT) { major_status = GSS_S_NO_CONTEXT; GLOBUS_GSI_GSSAPI_ERROR_RESULT( minor_status, GLOBUS_GSI_GSSAPI_ERROR_BAD_ARGUMENT, (_GGSL("Invalid context handle passed to function"))); goto exit; } /* lock the context mutex */ globus_mutex_lock(&context->mutex); if(context->ctx_flags & GSS_I_PROTECTION_FAIL_ON_CONTEXT_EXPIRATION) { time_t current_time; current_time = time(NULL); major_status = globus_i_gsi_gss_get_context_goodtill( &local_minor_status, context, &context_goodtill); if(GSS_ERROR(major_status)) { GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT( minor_status, local_minor_status, GLOBUS_GSI_GSSAPI_ERROR_WITH_GSS_CONTEXT); goto unlock_mutex_error; } if(current_time > context_goodtill) { major_status = GSS_S_CONTEXT_EXPIRED; GLOBUS_GSI_GSSAPI_ERROR_RESULT( minor_status, GLOBUS_GSI_GSSAPI_ERROR_EXPIRED_CREDENTIAL, (_GGSL("Expired credential: %s < %s"), ctime(&context_goodtill), ctime(¤t_time))); goto unlock_mutex_error; } } if (conf_req_flag == GSS_INTEGRITY_ONLY && qop_req == GSS_C_QOP_GLOBUS_GSSAPI_OPENSSL_BIG) { /* unlock the context mutex */ globus_mutex_unlock(&context->mutex); major_status = gss_get_mic(&local_minor_status, context_handle, qop_req, input_message_buffer, mic_buf); if (GSS_ERROR(major_status)) { GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT( minor_status, local_minor_status, GLOBUS_GSI_GSSAPI_ERROR_WITH_MIC); goto unlock_mutex_error; } /* lock the context mutex */ globus_mutex_lock(&context->mutex); output_message_buffer->value = (char *) malloc(5 + mic_buf->length + input_message_buffer->length); if (output_message_buffer->value == NULL) { GLOBUS_GSI_GSSAPI_MALLOC_ERROR(minor_status); gss_release_buffer(&local_minor_status, mic_buf); major_status = GSS_S_FAILURE; goto unlock_mutex_error; } output_message_buffer->length = 5 + mic_buf->length + input_message_buffer->length; message_value = output_message_buffer->value; *message_value++ = SSL3_RT_GSSAPI_OPENSSL; *message_value++ = 3; *message_value++ = 0; S2N(mic_buf->length, (char *) message_value); message_value += 2; memcpy(message_value, mic_buf->value, mic_buf->length); message_value = message_value + mic_buf->length; memcpy(message_value, input_message_buffer->value, input_message_buffer->length); if (conf_state) { *conf_state = GSS_INTEGRITY_ONLY; } } else { int rc; rc = SSL_write(context->gss_ssl, input_message_buffer->value, input_message_buffer->length); if (rc != input_message_buffer->length) { /* problem, did not take the whole buffer */ GLOBUS_GSI_GSSAPI_ERROR_RESULT( minor_status, GLOBUS_GSI_GSSAPI_ERROR_WRAP_BIO, (_GGSL("SSL failed wrapping entire message: " "SSL_write wrote %d bytes, should be %d bytes"), rc, input_message_buffer->length)); major_status = GSS_S_FAILURE; goto unlock_mutex_error; } if (conf_state) { if (SSL_CIPHER_get_bits( SSL_get_current_cipher(context->gss_ssl), NULL) == 0) { *conf_state = GSS_INTEGRITY_ONLY; } else { *conf_state = GSS_CONFIDENTIALITY; } } /* get the data from the write BIO */ major_status = globus_i_gsi_gss_get_token(&local_minor_status, context, NULL, output_message_buffer); if(GSS_ERROR(major_status)) { GLOBUS_GSI_GSSAPI_ERROR_CHAIN_RESULT( minor_status, local_minor_status, GLOBUS_GSI_GSSAPI_ERROR_TOKEN_FAIL); goto unlock_mutex_error; } } unlock_mutex_error: globus_mutex_unlock(&context->mutex); exit: GLOBUS_I_GSI_GSSAPI_DEBUG_EXIT; return major_status; }
DWORD DNSUpdateGenerateSignature( PCtxtHandle pGSSContext, PDNS_UPDATE_REQUEST pDNSUpdateRequest, PCSTR pszKeyName ) { DWORD dwError = 0; DWORD dwMinorStatus = 0; HANDLE hSendBuffer = (HANDLE)NULL; PBYTE pMessageBuffer = NULL; DWORD dwMessageSize = 0; DWORD dwTimeSigned = 0; WORD wFudge = 0; gss_buffer_desc MsgDesc = {0}; gss_buffer_desc MicDesc = {0}; PDNS_RR_RECORD pDNSTSIGRecord = NULL; dwError = DNSBuildMessageBuffer( pDNSUpdateRequest, pszKeyName, &dwTimeSigned, &wFudge, &pMessageBuffer, &dwMessageSize); BAIL_ON_LWDNS_ERROR(dwError); MsgDesc.value = pMessageBuffer; MsgDesc.length = dwMessageSize; MicDesc.value = NULL; MicDesc.length = 0; dwError = gss_get_mic( (OM_uint32 *)&dwMinorStatus, *pGSSContext, 0, &MsgDesc, &MicDesc); lwdns_display_status("gss_init_context", dwError, dwMinorStatus); BAIL_ON_LWDNS_ERROR(dwError); dwError = DNSCreateTSIGRecord( pszKeyName, dwTimeSigned, wFudge, pDNSUpdateRequest->wIdentification, MicDesc.value, MicDesc.length, &pDNSTSIGRecord); BAIL_ON_LWDNS_ERROR(dwError); dwError = DNSUpdateAddAdditionalSection( pDNSUpdateRequest, pDNSTSIGRecord); BAIL_ON_LWDNS_ERROR(dwError); pDNSTSIGRecord = NULL; cleanup: gss_release_buffer(&dwMinorStatus, &MicDesc); if (pDNSTSIGRecord) { DNSFreeRecord(pDNSTSIGRecord); } if (hSendBuffer) { DNSFreeSendBufferContext(hSendBuffer); } if (pMessageBuffer) { DNSFreeMemory(pMessageBuffer); } return(dwError); error: goto cleanup; }
/* * Send a reply. Note that we only need to send a reply if we * need to send a MIC or a mechanism token. Otherwise, we can * return an empty buffer. * * The return value of this will be returned to the API, so it * must return GSS_S_CONTINUE_NEEDED if a token was generated. */ static OM_uint32 spnego_reply_internal(OM_uint32 *minor_status, gssspnego_ctx context_handle, const gss_buffer_t mech_buf, gss_buffer_t mech_token, gss_buffer_t output_token) { NegTokenResp resp; gss_buffer_desc mic_buf; OM_uint32 ret; gss_buffer_desc data; u_char *buf; if (mech_buf == GSS_C_NO_BUFFER && mech_token->length == 0) { output_token->length = 0; output_token->value = NULL; return context_handle->open ? GSS_S_COMPLETE : GSS_S_FAILURE; } memset(&resp, 0, sizeof(resp)); ALLOC(resp.negResult, 1); if (resp.negResult == NULL) { *minor_status = ENOMEM; return GSS_S_FAILURE; } resp.supportedMech = NULL; output_token->length = 0; output_token->value = NULL; if (mech_token->length == 0) { resp.responseToken = NULL; *(resp.negResult) = accept_completed; } else { ALLOC(resp.responseToken, 1); if (resp.responseToken == NULL) { free_NegTokenResp(&resp); *minor_status = ENOMEM; return GSS_S_FAILURE; } resp.responseToken->length = mech_token->length; resp.responseToken->data = mech_token->value; mech_token->length = 0; mech_token->value = NULL; *(resp.negResult) = accept_incomplete; } if (mech_buf != GSS_C_NO_BUFFER) { ALLOC(resp.mechListMIC, 1); if (resp.mechListMIC == NULL) { free_NegTokenResp(&resp); *minor_status = ENOMEM; return GSS_S_FAILURE; } ret = gss_get_mic(minor_status, context_handle->negotiated_ctx_id, 0, mech_buf, &mic_buf); if (ret) { free_NegTokenResp(&resp); *minor_status = ENOMEM; return GSS_S_FAILURE; } resp.mechListMIC->length = mic_buf.length; resp.mechListMIC->data = mic_buf.value; } else { resp.mechListMIC = NULL; } ret = _gss_spnego_encode_response (minor_status, &resp, &data, &buf); if (ret) { free_NegTokenResp(&resp); return ret; } output_token->value = malloc(data.length); if (output_token->value == NULL) { *minor_status = ENOMEM; ret = GSS_S_FAILURE; } else { output_token->length = data.length; memcpy(output_token->value, data.value, output_token->length); } free(buf); if (*(resp.negResult) == accept_completed) ret = GSS_S_COMPLETE; else ret = GSS_S_CONTINUE_NEEDED; free_NegTokenResp(&resp); return ret; }
bool_t __rpc_gss_wrap(AUTH *auth, void *header, size_t headerlen, XDR* xdrs, xdrproc_t xdr_args, void *args_ptr) { XDR tmpxdrs; char credbuf[MAX_AUTH_BYTES]; char tmpheader[MAX_AUTH_BYTES]; struct opaque_auth creds, verf; struct rpc_gss_data *gd; gss_buffer_desc rpcbuf, checksum; OM_uint32 maj_stat, min_stat; bool_t xdr_stat; log_debug("in rpc_gss_wrap()"); gd = AUTH_PRIVATE(auth); if (gd->gd_state == RPCSEC_GSS_ESTABLISHED) gd->gd_cred.gc_seq++; /* * We need to encode our creds and then put the header and * creds together in a buffer so that we can create a checksum * for the verf. */ xdrmem_create(&tmpxdrs, credbuf, sizeof(credbuf), XDR_ENCODE); if (!xdr_rpc_gss_cred(&tmpxdrs, &gd->gd_cred)) { XDR_DESTROY(&tmpxdrs); _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM); return (FALSE); } creds.oa_flavor = RPCSEC_GSS; creds.oa_base = credbuf; creds.oa_length = XDR_GETPOS(&tmpxdrs); XDR_DESTROY(&tmpxdrs); xdrmem_create(&tmpxdrs, tmpheader, sizeof(tmpheader), XDR_ENCODE); if (!XDR_PUTBYTES(&tmpxdrs, header, headerlen) || !xdr_opaque_auth(&tmpxdrs, &creds)) { XDR_DESTROY(&tmpxdrs); _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM); return (FALSE); } headerlen = XDR_GETPOS(&tmpxdrs); XDR_DESTROY(&tmpxdrs); if (!XDR_PUTBYTES(xdrs, tmpheader, headerlen)) { _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM); return (FALSE); } if (gd->gd_cred.gc_proc == RPCSEC_GSS_INIT || gd->gd_cred.gc_proc == RPCSEC_GSS_CONTINUE_INIT) { if (!xdr_opaque_auth(xdrs, &_null_auth)) { _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM); return (FALSE); } } else { /* * Checksum serialized RPC header, up to and including * credential. */ rpcbuf.length = headerlen; rpcbuf.value = tmpheader; maj_stat = gss_get_mic(&min_stat, gd->gd_ctx, gd->gd_qop, &rpcbuf, &checksum); if (maj_stat != GSS_S_COMPLETE) { log_status("gss_get_mic", gd->gd_mech, maj_stat, min_stat); if (maj_stat == GSS_S_CONTEXT_EXPIRED) { rpc_gss_destroy_context(auth, TRUE); } _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, EPERM); return (FALSE); } verf.oa_flavor = RPCSEC_GSS; verf.oa_base = checksum.value; verf.oa_length = checksum.length; xdr_stat = xdr_opaque_auth(xdrs, &verf); gss_release_buffer(&min_stat, &checksum); if (!xdr_stat) { _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM); return (FALSE); } } if (gd->gd_state != RPCSEC_GSS_ESTABLISHED || gd->gd_cred.gc_svc == rpc_gss_svc_none) { return (xdr_args(xdrs, args_ptr)); } return (xdr_rpc_gss_wrap_data(xdrs, xdr_args, args_ptr, gd->gd_ctx, gd->gd_qop, gd->gd_cred.gc_svc, gd->gd_cred.gc_seq)); }