static krb5_error_code init_tgs_req (krb5_context context, krb5_ccache ccache, krb5_addresses *addresses, krb5_kdc_flags flags, Ticket *second_ticket, krb5_creds *in_creds, krb5_creds *krbtgt, unsigned nonce, const METHOD_DATA *padata, krb5_keyblock **subkey, TGS_REQ *t) { krb5_auth_context ac = NULL; krb5_error_code ret = 0; memset(t, 0, sizeof(*t)); t->pvno = 5; t->msg_type = krb_tgs_req; if (in_creds->session.keytype) { ALLOC_SEQ(&t->req_body.etype, 1); if(t->req_body.etype.val == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } t->req_body.etype.val[0] = in_creds->session.keytype; } else { ret = krb5_init_etype(context, &t->req_body.etype.len, &t->req_body.etype.val, NULL); } if (ret) goto fail; t->req_body.addresses = addresses; t->req_body.kdc_options = flags.b; ret = copy_Realm(&in_creds->server->realm, &t->req_body.realm); if (ret) goto fail; ALLOC(t->req_body.sname, 1); if (t->req_body.sname == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } /* some versions of some code might require that the client be present in TGS-REQs, but this is clearly against the spec */ ret = copy_PrincipalName(&in_creds->server->name, t->req_body.sname); if (ret) goto fail; /* req_body.till should be NULL if there is no endtime specified, but old MIT code (like DCE secd) doesn't like that */ ALLOC(t->req_body.till, 1); if(t->req_body.till == NULL){ ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } *t->req_body.till = in_creds->times.endtime; t->req_body.nonce = nonce; if(second_ticket){ ALLOC(t->req_body.additional_tickets, 1); if (t->req_body.additional_tickets == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } ALLOC_SEQ(t->req_body.additional_tickets, 1); if (t->req_body.additional_tickets->val == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } ret = copy_Ticket(second_ticket, t->req_body.additional_tickets->val); if (ret) goto fail; } ALLOC(t->padata, 1); if (t->padata == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } ALLOC_SEQ(t->padata, 1 + padata->len); if (t->padata->val == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } { int i; for (i = 0; i < padata->len; i++) { ret = copy_PA_DATA(&padata->val[i], &t->padata->val[i + 1]); if (ret) { krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } } } ret = krb5_auth_con_init(context, &ac); if(ret) goto fail; ret = krb5_auth_con_generatelocalsubkey(context, ac, &krbtgt->session); if (ret) goto fail; ret = set_auth_data (context, &t->req_body, &in_creds->authdata, ac->local_subkey); if (ret) goto fail; ret = make_pa_tgs_req(context, ac, &t->req_body, &t->padata->val[0], krbtgt); if(ret) goto fail; ret = krb5_auth_con_getlocalsubkey(context, ac, subkey); if (ret) goto fail; fail: if (ac) krb5_auth_con_free(context, ac); if (ret) { t->req_body.addresses = NULL; free_TGS_REQ (t); } return ret; }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_mk_rep(krb5_context context, krb5_auth_context auth_context, krb5_data *outbuf) { krb5_error_code ret; AP_REP ap; EncAPRepPart body; u_char *buf = NULL; size_t buf_size; size_t len = 0; krb5_crypto crypto; ap.pvno = 5; ap.msg_type = krb_ap_rep; memset (&body, 0, sizeof(body)); body.ctime = auth_context->authenticator->ctime; body.cusec = auth_context->authenticator->cusec; if (auth_context->flags & KRB5_AUTH_CONTEXT_USE_SUBKEY) { if (auth_context->local_subkey == NULL) { ret = krb5_auth_con_generatelocalsubkey(context, auth_context, auth_context->keyblock); if(ret) { free_EncAPRepPart(&body); return ret; } } ret = krb5_copy_keyblock(context, auth_context->local_subkey, &body.subkey); if (ret) { free_EncAPRepPart(&body); return krb5_enomem(context); } } else body.subkey = NULL; if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) { if(auth_context->local_seqnumber == 0) krb5_generate_seq_number (context, auth_context->keyblock, &auth_context->local_seqnumber); ALLOC(body.seq_number, 1); if (body.seq_number == NULL) { free_EncAPRepPart(&body); return krb5_enomem(context); } *(body.seq_number) = auth_context->local_seqnumber; } else body.seq_number = NULL; ap.enc_part.etype = auth_context->keyblock->keytype; ap.enc_part.kvno = NULL; ASN1_MALLOC_ENCODE(EncAPRepPart, buf, buf_size, &body, &len, ret); free_EncAPRepPart (&body); if(ret) return ret; if (buf_size != len) krb5_abortx(context, "internal error in ASN.1 encoder"); ret = krb5_crypto_init(context, auth_context->keyblock, 0 /* ap.enc_part.etype */, &crypto); if (ret) { free (buf); return ret; } ret = krb5_encrypt (context, crypto, KRB5_KU_AP_REQ_ENC_PART, buf + buf_size - len, len, &ap.enc_part.cipher); krb5_crypto_destroy(context, crypto); free(buf); if (ret) return ret; ASN1_MALLOC_ENCODE(AP_REP, outbuf->data, outbuf->length, &ap, &len, ret); if (ret == 0 && outbuf->length != len) krb5_abortx(context, "internal error in ASN.1 encoder"); free_AP_REP (&ap); return ret; }
krb5_error_code _krb5_init_tgs_req(krb5_context context, krb5_ccache ccache, krb5_addresses *addresses, krb5_kdc_flags flags, krb5_const_principal impersonate_principal, Ticket *second_ticket, krb5_creds *in_creds, krb5_creds *krbtgt, unsigned nonce, METHOD_DATA *padata, krb5_keyblock **subkey, TGS_REQ *t) { krb5_auth_context ac = NULL; krb5_error_code ret = 0; /* inherit the forwardable/proxyable flags from the krbtgt */ flags.b.forwardable = krbtgt->flags.b.forwardable; flags.b.proxiable = krbtgt->flags.b.proxiable; if (ccache->ops->tgt_req) { KERB_TGS_REQ_OUT out; KERB_TGS_REQ_IN in; memset(&in, 0, sizeof(in)); memset(&out, 0, sizeof(out)); ret = ccache->ops->tgt_req(context, ccache, &in, &out); if (ret) return ret; free_KERB_TGS_REQ_OUT(&out); return 0; } memset(t, 0, sizeof(*t)); if (impersonate_principal) { krb5_crypto crypto; PA_S4U2Self self; krb5_data data; void *buf; size_t size, len; self.name = impersonate_principal->name; self.realm = impersonate_principal->realm; self.auth = rk_UNCONST("Kerberos"); ret = _krb5_s4u2self_to_checksumdata(context, &self, &data); if (ret) goto fail; ret = krb5_crypto_init(context, &krbtgt->session, 0, &crypto); if (ret) { krb5_data_free(&data); goto fail; } ret = krb5_create_checksum(context, crypto, KRB5_KU_OTHER_CKSUM, 0, data.data, data.length, &self.cksum); krb5_crypto_destroy(context, crypto); krb5_data_free(&data); if (ret) goto fail; ASN1_MALLOC_ENCODE(PA_S4U2Self, buf, len, &self, &size, ret); free_Checksum(&self.cksum); if (ret) goto fail; if (len != size) krb5_abortx(context, "internal asn1 error"); ret = krb5_padata_add(context, padata, KRB5_PADATA_FOR_USER, buf, len); if (ret) goto fail; } t->pvno = 5; t->msg_type = krb_tgs_req; if (in_creds->session.keytype) { ALLOC_SEQ(&t->req_body.etype, 1); if(t->req_body.etype.val == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } t->req_body.etype.val[0] = in_creds->session.keytype; } else { ret = _krb5_init_etype(context, KRB5_PDU_TGS_REQUEST, &t->req_body.etype.len, &t->req_body.etype.val, NULL); } if (ret) goto fail; t->req_body.addresses = addresses; t->req_body.kdc_options = flags.b; ret = copy_Realm(&in_creds->server->realm, &t->req_body.realm); if (ret) goto fail; ALLOC(t->req_body.sname, 1); if (t->req_body.sname == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } /* some versions of some code might require that the client be present in TGS-REQs, but this is clearly against the spec */ ret = copy_PrincipalName(&in_creds->server->name, t->req_body.sname); if (ret) goto fail; /* req_body.till should be NULL if there is no endtime specified, but old MIT code (like DCE secd) doesn't like that */ ALLOC(t->req_body.till, 1); if(t->req_body.till == NULL){ ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } *t->req_body.till = in_creds->times.endtime; t->req_body.nonce = nonce; if(second_ticket){ ALLOC(t->req_body.additional_tickets, 1); if (t->req_body.additional_tickets == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } ALLOC_SEQ(t->req_body.additional_tickets, 1); if (t->req_body.additional_tickets->val == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } ret = copy_Ticket(second_ticket, t->req_body.additional_tickets->val); if (ret) goto fail; } ALLOC(t->padata, 1); if (t->padata == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } ALLOC_SEQ(t->padata, 1 + padata->len); if (t->padata->val == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } { size_t i; for (i = 0; i < padata->len; i++) { ret = copy_PA_DATA(&padata->val[i], &t->padata->val[i + 1]); if (ret) { krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); goto fail; } } } ret = krb5_auth_con_init(context, &ac); if(ret) goto fail; ret = krb5_auth_con_generatelocalsubkey(context, ac, &krbtgt->session); if (ret) goto fail; ret = set_auth_data (context, &t->req_body, &in_creds->authdata, ac->local_subkey); if (ret) goto fail; ret = make_pa_tgs_req(context, ac, &t->req_body, &t->padata->val[0], ccache, krbtgt); if(ret) goto fail; ret = krb5_auth_con_getlocalsubkey(context, ac, subkey); if (ret) goto fail; fail: if (ac) krb5_auth_con_free(context, ac); if (ret) { t->req_body.addresses = NULL; free_TGS_REQ (t); } return ret; }
static OM_uint32 init_auth (OM_uint32 * minor_status, gsskrb5_cred initiator_cred_handle, gsskrb5_ctx ctx, krb5_const_principal name, const gss_OID mech_type, OM_uint32 req_flags, OM_uint32 time_req, const gss_channel_bindings_t input_chan_bindings, const gss_buffer_t input_token, gss_OID * actual_mech_type, gss_buffer_t output_token, OM_uint32 * ret_flags, OM_uint32 * time_rec ) { OM_uint32 ret = GSS_S_FAILURE; krb5_error_code kret; krb5_flags ap_options; krb5_creds *cred = NULL; krb5_data outbuf; krb5_ccache ccache = NULL; uint32_t flags; krb5_data authenticator; Checksum cksum; krb5_enctype enctype; krb5_data fwd_data; OM_uint32 lifetime_rec; krb5_data_zero(&outbuf); krb5_data_zero(&fwd_data); *minor_status = 0; if (actual_mech_type) *actual_mech_type = GSS_KRB5_MECHANISM; if (initiator_cred_handle == NULL) { kret = krb5_cc_default (_gsskrb5_context, &ccache); if (kret) { _gsskrb5_set_error_string (); *minor_status = kret; ret = GSS_S_FAILURE; goto failure; } } else ccache = initiator_cred_handle->ccache; kret = krb5_cc_get_principal (_gsskrb5_context, ccache, &ctx->source); if (kret) { _gsskrb5_set_error_string (); *minor_status = kret; ret = GSS_S_FAILURE; goto failure; } kret = krb5_copy_principal (_gsskrb5_context, name, &ctx->target); if (kret) { _gsskrb5_set_error_string (); *minor_status = kret; ret = GSS_S_FAILURE; goto failure; } ret = _gss_DES3_get_mic_compat(minor_status, ctx); if (ret) goto failure; ret = gsskrb5_get_creds(minor_status, ccache, ctx, ctx->target, time_req, time_rec, &cred); if (ret) goto failure; ctx->lifetime = cred->times.endtime; ret = _gsskrb5_lifetime_left(minor_status, ctx->lifetime, &lifetime_rec); if (ret) { goto failure; } if (lifetime_rec == 0) { *minor_status = 0; ret = GSS_S_CONTEXT_EXPIRED; goto failure; } krb5_auth_con_setkey(_gsskrb5_context, ctx->auth_context, &cred->session); kret = krb5_auth_con_generatelocalsubkey(_gsskrb5_context, ctx->auth_context, &cred->session); if(kret) { _gsskrb5_set_error_string (); *minor_status = kret; ret = GSS_S_FAILURE; goto failure; } /* * If the credential doesn't have ok-as-delegate, check what local * policy say about ok-as-delegate, default is FALSE that makes * code ignore the KDC setting and follow what the application * requested. If its TRUE, strip of the GSS_C_DELEG_FLAG if the * KDC doesn't set ok-as-delegate. */ if (!cred->flags.b.ok_as_delegate) { krb5_boolean delegate; krb5_appdefault_boolean(_gsskrb5_context, "gssapi", name->realm, "ok-as-delegate", FALSE, &delegate); if (delegate) req_flags &= ~GSS_C_DELEG_FLAG; } flags = 0; ap_options = 0; if (req_flags & GSS_C_DELEG_FLAG) do_delegation (ctx->auth_context, ccache, cred, name, &fwd_data, &flags); if (req_flags & GSS_C_MUTUAL_FLAG) { flags |= GSS_C_MUTUAL_FLAG; ap_options |= AP_OPTS_MUTUAL_REQUIRED; } if (req_flags & GSS_C_REPLAY_FLAG) flags |= GSS_C_REPLAY_FLAG; if (req_flags & GSS_C_SEQUENCE_FLAG) flags |= GSS_C_SEQUENCE_FLAG; if (req_flags & GSS_C_ANON_FLAG) ; /* XXX */ if (req_flags & GSS_C_DCE_STYLE) { /* GSS_C_DCE_STYLE implies GSS_C_MUTUAL_FLAG */ flags |= GSS_C_DCE_STYLE | GSS_C_MUTUAL_FLAG; ap_options |= AP_OPTS_MUTUAL_REQUIRED; } if (req_flags & GSS_C_IDENTIFY_FLAG) flags |= GSS_C_IDENTIFY_FLAG; if (req_flags & GSS_C_EXTENDED_ERROR_FLAG) flags |= GSS_C_EXTENDED_ERROR_FLAG; flags |= GSS_C_CONF_FLAG; flags |= GSS_C_INTEG_FLAG; flags |= GSS_C_TRANS_FLAG; if (ret_flags) *ret_flags = flags; ctx->flags = flags; ctx->more_flags |= LOCAL; ret = _gsskrb5_create_8003_checksum (minor_status, input_chan_bindings, flags, &fwd_data, &cksum); krb5_data_free (&fwd_data); if (ret) goto failure; enctype = ctx->auth_context->keyblock->keytype; kret = krb5_build_authenticator (_gsskrb5_context, ctx->auth_context, enctype, cred, &cksum, NULL, &authenticator, KRB5_KU_AP_REQ_AUTH); if (kret) { _gsskrb5_set_error_string (); *minor_status = kret; ret = GSS_S_FAILURE; goto failure; } kret = krb5_build_ap_req (_gsskrb5_context, enctype, cred, ap_options, authenticator, &outbuf); if (kret) { _gsskrb5_set_error_string (); *minor_status = kret; ret = GSS_S_FAILURE; goto failure; } ret = _gsskrb5_encapsulate (minor_status, &outbuf, output_token, (u_char *)"\x01\x00", GSS_KRB5_MECHANISM); if (ret) goto failure; krb5_data_free (&outbuf); krb5_free_creds(_gsskrb5_context, cred); free_Checksum(&cksum); if (initiator_cred_handle == NULL) krb5_cc_close(_gsskrb5_context, ccache); if (flags & GSS_C_MUTUAL_FLAG) { ctx->state = INITIATOR_WAIT_FOR_MUTAL; return GSS_S_CONTINUE_NEEDED; } return gsskrb5_initiator_ready(minor_status, ctx); failure: if(cred) krb5_free_creds(_gsskrb5_context, cred); if (ccache && initiator_cred_handle == NULL) krb5_cc_close(_gsskrb5_context, ccache); return ret; }
krb5_error_code _krb5_mk_req_internal(krb5_context context, krb5_auth_context *auth_context, const krb5_flags ap_req_options, krb5_data *in_data, krb5_creds *in_creds, krb5_data *outbuf, krb5_key_usage checksum_usage, krb5_key_usage encrypt_usage) { krb5_error_code ret; krb5_data authenticator; Checksum c; Checksum *c_opt; krb5_auth_context ac; if(auth_context) { if(*auth_context == NULL) ret = krb5_auth_con_init(context, auth_context); else ret = 0; ac = *auth_context; } else ret = krb5_auth_con_init(context, &ac); if(ret) return ret; if(ac->local_subkey == NULL && (ap_req_options & AP_OPTS_USE_SUBKEY)) { ret = krb5_auth_con_generatelocalsubkey(context, ac, &in_creds->session); if(ret) goto out; } krb5_free_keyblock(context, ac->keyblock); ret = krb5_copy_keyblock(context, &in_creds->session, &ac->keyblock); if (ret) goto out; /* it's unclear what type of checksum we can use. try the best one, except: * a) if it's configured differently for the current realm, or * b) if the session key is des-cbc-crc */ if (in_data) { if(ac->keyblock->keytype == ETYPE_DES_CBC_CRC) { /* this is to make DCE secd (and older MIT kdcs?) happy */ ret = krb5_create_checksum(context, NULL, 0, CKSUMTYPE_RSA_MD4, in_data->data, in_data->length, &c); } else if(ac->keyblock->keytype == ETYPE_ARCFOUR_HMAC_MD5 || ac->keyblock->keytype == ETYPE_ARCFOUR_HMAC_MD5_56 || ac->keyblock->keytype == ETYPE_DES_CBC_MD4 || ac->keyblock->keytype == ETYPE_DES_CBC_MD5) { /* this is to make MS kdc happy */ ret = krb5_create_checksum(context, NULL, 0, CKSUMTYPE_RSA_MD5, in_data->data, in_data->length, &c); } else { krb5_crypto crypto; ret = krb5_crypto_init(context, ac->keyblock, 0, &crypto); if (ret) goto out; ret = krb5_create_checksum(context, crypto, checksum_usage, 0, in_data->data, in_data->length, &c); krb5_crypto_destroy(context, crypto); } c_opt = &c; } else { c_opt = NULL; } if (ret) goto out; ret = _krb5_build_authenticator(context, ac, ac->keyblock->keytype, in_creds, c_opt, &authenticator, encrypt_usage); if (c_opt) free_Checksum (c_opt); if (ret) goto out; ret = krb5_build_ap_req (context, ac->keyblock->keytype, in_creds, ap_req_options, authenticator, outbuf); out: if(auth_context == NULL) krb5_auth_con_free(context, ac); return ret; }
krb5_error_code _krb5_mk_req_internal(krb5_context context, krb5_auth_context *auth_context, const krb5_flags ap_req_options, krb5_data *in_data, krb5_creds *in_creds, krb5_data *outbuf, krb5_key_usage checksum_usage, krb5_key_usage encrypt_usage) { krb5_error_code ret; krb5_data authenticator; Checksum c; Checksum *c_opt; krb5_auth_context ac; if(auth_context) { if(*auth_context == NULL) ret = krb5_auth_con_init(context, auth_context); else ret = 0; ac = *auth_context; } else ret = krb5_auth_con_init(context, &ac); if(ret) return ret; if(ac->local_subkey == NULL && (ap_req_options & AP_OPTS_USE_SUBKEY)) { ret = krb5_auth_con_generatelocalsubkey(context, ac, &in_creds->session); if(ret) goto out; } #if 0 { /* This is somewhat bogus since we're possibly overwriting a value specified by the user, but it's the easiest way to make the code use a compatible enctype */ Ticket ticket; krb5_keytype ticket_keytype; ret = decode_Ticket(in_creds->ticket.data, in_creds->ticket.length, &ticket, NULL); krb5_enctype_to_keytype (context, ticket.enc_part.etype, &ticket_keytype); if (ticket_keytype == in_creds->session.keytype) krb5_auth_setenctype(context, ac, ticket.enc_part.etype); free_Ticket(&ticket); } #endif krb5_free_keyblock(context, ac->keyblock); ret = krb5_copy_keyblock(context, &in_creds->session, &ac->keyblock); if (ret) goto out; /* it's unclear what type of checksum we can use. try the best one, except: * a) if it's configured differently for the current realm, or * b) if the session key is des-cbc-crc */ if (in_data) { if(ac->keyblock->keytype == ETYPE_DES_CBC_CRC) { /* this is to make DCE secd (and older MIT kdcs?) happy */ ret = krb5_create_checksum(context, NULL, 0, CKSUMTYPE_RSA_MD4, in_data->data, in_data->length, &c); } else if(ac->keyblock->keytype == ETYPE_ARCFOUR_HMAC_MD5 || ac->keyblock->keytype == ETYPE_ARCFOUR_HMAC_MD5_56) { /* this is to make MS kdc happy */ ret = krb5_create_checksum(context, NULL, 0, CKSUMTYPE_RSA_MD5, in_data->data, in_data->length, &c); } else { krb5_crypto crypto; ret = krb5_crypto_init(context, ac->keyblock, 0, &crypto); if (ret) goto out; ret = krb5_create_checksum(context, crypto, checksum_usage, 0, in_data->data, in_data->length, &c); krb5_crypto_destroy(context, crypto); } c_opt = &c; } else { c_opt = NULL; } if (ret) goto out; ret = krb5_build_authenticator (context, ac, ac->keyblock->keytype, in_creds, c_opt, NULL, &authenticator, encrypt_usage); if (c_opt) free_Checksum (c_opt); if (ret) goto out; ret = krb5_build_ap_req (context, ac->keyblock->keytype, in_creds, ap_req_options, authenticator, outbuf); out: if(auth_context == NULL) krb5_auth_con_free(context, ac); return ret; }