static krb5_error_code kdc_return_preauth(krb5_context context, krb5_pa_data *padata, struct _krb5_db_entry_new *client, krb5_data *req_pkt, krb5_kdc_req *request, krb5_kdc_rep *reply, struct _krb5_key_data *client_keys, krb5_keyblock *encrypting_key, krb5_pa_data **send_pa, preauth_get_entry_data_proc get_entry_proc, void *pa_module_context, void **pa_request_context) { krb5_error_code retval = 0; krb5_keyblock *challenge_key = *pa_request_context; krb5_pa_enc_ts ts; krb5_data *plain = NULL; krb5_enc_data enc; krb5_data *encoded = NULL; krb5_pa_data *pa = NULL; krb5int_access kaccess; if (krb5int_accessor(&kaccess, KRB5INT_ACCESS_VERSION) != 0) return 0; if (challenge_key == NULL) return 0; * pa_request_context = NULL; /*this function will free the * challenge key*/ enc.ciphertext.data = NULL; /* In case of error pass through */ retval = krb5_us_timeofday(context, &ts.patimestamp, &ts.pausec); if (retval == 0) retval = kaccess.encode_enc_ts(&ts, &plain); if (retval == 0) retval = kaccess.encrypt_helper(context, challenge_key, KRB5_KEYUSAGE_ENC_CHALLENGE_KDC, plain, &enc); if (retval == 0) retval = kaccess.encode_enc_data(&enc, &encoded); if (retval == 0) { pa = calloc(1, sizeof(krb5_pa_data)); if (pa == NULL) retval = ENOMEM; } if (retval == 0) { pa->pa_type = KRB5_PADATA_ENCRYPTED_CHALLENGE; pa->contents = (unsigned char *) encoded->data; pa->length = encoded->length; encoded->data = NULL; *send_pa = pa; pa = NULL; } if (challenge_key) krb5_free_keyblock(context, challenge_key); if (encoded) krb5_free_data(context, encoded); if (plain) krb5_free_data(context, plain); if (enc.ciphertext.data) krb5_free_data_contents(context, &enc.ciphertext); return retval; }
krb5_error_code kg_arcfour_docrypt(const krb5_keyblock *keyblock, int usage, const unsigned char *kd_data, size_t kd_data_len, const unsigned char *input_buf, size_t input_len, unsigned char *output_buf) { krb5_error_code code; krb5_data kd = make_data((char *) kd_data, kd_data_len); krb5_crypto_iov kiov; krb5int_access kaccess; code = krb5int_accessor(&kaccess, KRB5INT_ACCESS_VERSION); if (code) return code; memcpy(output_buf, input_buf, input_len); kiov.flags = KRB5_CRYPTO_TYPE_DATA; kiov.data = make_data(output_buf, input_len); return (*kaccess.arcfour_gsscrypt)(keyblock, usage, &kd, &kiov, 1); }
/* * Grab internal function pointers from the krb5int_accessor * structure and make them available */ krb5_error_code pkinit_accessor_init(void) { krb5_error_code retval; krb5int_access k5int; retval = krb5int_accessor(&k5int, KRB5INT_ACCESS_VERSION); if (retval) return retval; #define SET_PTRS(type) \ k5int_encode_##type = k5int.encode_##type; \ k5int_decode_##type = k5int.decode_##type; SET_PTRS(krb5_auth_pack); SET_PTRS(krb5_auth_pack_draft9); SET_PTRS(krb5_kdc_dh_key_info); SET_PTRS(krb5_pa_pk_as_rep); SET_PTRS(krb5_pa_pk_as_rep_draft9); SET_PTRS(krb5_pa_pk_as_req); SET_PTRS(krb5_pa_pk_as_req_draft9); SET_PTRS(krb5_reply_key_pack); SET_PTRS(krb5_reply_key_pack_draft9); SET_PTRS(krb5_td_dh_parameters); SET_PTRS(krb5_td_trusted_certifiers); SET_PTRS(krb5_typed_data); /* special cases... */ k5int_decode_krb5_principal_name = k5int.decode_krb5_principal_name; k5int_decode_krb5_as_req = k5int.decode_krb5_as_req; k5int_encode_krb5_kdc_req_body = k5int.encode_krb5_kdc_req_body; k5int_krb5_free_kdc_req = k5int.krb5_free_kdc_req; k5int_set_prompt_types = k5int.krb5int_set_prompt_types; k5int_encode_krb5_authdata_elt = k5int.encode_krb5_authdata_elt; k5int_make_srv_query_realm = k5int.make_srv_query_realm; k5int_free_srv_dns_data = k5int.free_srv_dns_data; return 0; }
krb5_error_code kg_arcfour_docrypt_iov(krb5_context context, const krb5_keyblock *keyblock, int usage, const unsigned char *kd_data, size_t kd_data_len, gss_iov_buffer_desc *iov, int iov_count) { krb5_error_code code; krb5_data kd = make_data((char *) kd_data, kd_data_len); krb5int_access kaccess; krb5_crypto_iov *kiov = NULL; size_t kiov_count = 0; code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION); if (code) return code; code = kg_translate_iov(context, 0 /* proto */, 0 /* dce_style */, 0 /* ec */, 0 /* rrc */, keyblock->enctype, iov, iov_count, &kiov, &kiov_count); if (code) return code; code = (*kaccess.arcfour_gsscrypt)(keyblock, usage, &kd, kiov, kiov_count); free(kiov); return code; }
static krb5_error_code process_preauth(krb5_context context, void *plugin_context, void *request_context, krb5_get_init_creds_opt *opt, preauth_get_client_data_proc get_data_proc, struct _krb5_preauth_client_rock *rock, krb5_kdc_req *request, krb5_data *encoded_request_body, krb5_data *encoded_previous_request, krb5_pa_data *padata, krb5_prompter_fct prompter, void *prompter_data, preauth_get_as_key_proc gak_fct, void *gak_data, krb5_data *salt, krb5_data *s2kparams, krb5_keyblock *as_key, krb5_pa_data ***out_padata) { krb5_error_code retval = 0; krb5_enctype enctype = 0; krb5_keyblock *challenge_key = NULL, *armor_key = NULL; krb5_data *etype_data = NULL; krb5int_access kaccess; if (krb5int_accessor(&kaccess, KRB5INT_ACCESS_VERSION) != 0) return 0; retval = fast_get_armor_key(context, get_data_proc, rock, &armor_key); if (retval || armor_key == NULL) return 0; retval = get_data_proc(context, rock, krb5plugin_preauth_client_get_etype, &etype_data); if (retval == 0) { enctype = *((krb5_enctype *)etype_data->data); if (as_key->length == 0 ||as_key->enctype != enctype) retval = gak_fct(context, request->client, enctype, prompter, prompter_data, salt, s2kparams, as_key, gak_data); } if (retval == 0 && padata->length) { krb5_enc_data *enc = NULL; krb5_data scratch; scratch.length = padata->length; scratch.data = (char *) padata->contents; retval = krb5_c_fx_cf2_simple(context,armor_key, "kdcchallengearmor", as_key, "challengelongterm", &challenge_key); if (retval == 0) retval =kaccess.decode_enc_data(&scratch, &enc); scratch.data = NULL; if (retval == 0) { scratch.data = malloc(enc->ciphertext.length); scratch.length = enc->ciphertext.length; if (scratch.data == NULL) retval = ENOMEM; } if (retval == 0) retval = krb5_c_decrypt(context, challenge_key, KRB5_KEYUSAGE_ENC_CHALLENGE_KDC, NULL, enc, &scratch); /* * Per draft 11 of the preauth framework, the client MAY but is not * required to actually check the timestamp from the KDC other than to * confirm it decrypts. This code does not perform that check. */ if (scratch.data) krb5_free_data_contents(context, &scratch); if (retval == 0) fast_set_kdc_verified(context, get_data_proc, rock); if (enc) kaccess.free_enc_data(context, enc); } else if (retval == 0) { /*No padata; we send*/ krb5_enc_data enc; krb5_pa_data *pa = NULL; krb5_pa_data **pa_array = NULL; krb5_data *encoded_ts = NULL; krb5_pa_enc_ts ts; enc.ciphertext.data = NULL; retval = krb5_us_timeofday(context, &ts.patimestamp, &ts.pausec); if (retval == 0) retval = kaccess.encode_enc_ts(&ts, &encoded_ts); if (retval == 0) retval = krb5_c_fx_cf2_simple(context, armor_key, "clientchallengearmor", as_key, "challengelongterm", &challenge_key); if (retval == 0) retval = kaccess.encrypt_helper(context, challenge_key, KRB5_KEYUSAGE_ENC_CHALLENGE_CLIENT, encoded_ts, &enc); if (encoded_ts) krb5_free_data(context, encoded_ts); encoded_ts = NULL; if (retval == 0) { retval = kaccess.encode_enc_data(&enc, &encoded_ts); krb5_free_data_contents(context, &enc.ciphertext); } if (retval == 0) { pa = calloc(1, sizeof(krb5_pa_data)); if (pa == NULL) retval = ENOMEM; } if (retval == 0) { pa_array = calloc(2, sizeof(krb5_pa_data *)); if (pa_array == NULL) retval = ENOMEM; } if (retval == 0) { pa->length = encoded_ts->length; pa->contents = (unsigned char *) encoded_ts->data; pa->pa_type = KRB5_PADATA_ENCRYPTED_CHALLENGE; free(encoded_ts); encoded_ts = NULL; pa_array[0] = pa; pa = NULL; *out_padata = pa_array; pa_array = NULL; } if (pa) free(pa); if (encoded_ts) krb5_free_data(context, encoded_ts); if (pa_array) free(pa_array); } if (challenge_key) krb5_free_keyblock(context, challenge_key); if (armor_key) krb5_free_keyblock(context, armor_key); if (etype_data != NULL) get_data_proc(context, rock, krb5plugin_preauth_client_free_etype, &etype_data); return retval; }
static krb5_error_code kdc_verify_preauth(krb5_context context, struct _krb5_db_entry_new *client, krb5_data *req_pkt, krb5_kdc_req *request, krb5_enc_tkt_part *enc_tkt_reply, krb5_pa_data *data, preauth_get_entry_data_proc get_entry_proc, void *pa_module_context, void **pa_request_context, krb5_data **e_data, krb5_authdata ***authz_data) { krb5_error_code retval = 0; krb5_timestamp now; krb5_enc_data *enc = NULL; krb5_data scratch, plain; krb5_keyblock *armor_key = NULL; krb5_pa_enc_ts *ts = NULL; krb5int_access kaccess; krb5_keyblock *client_keys = NULL; krb5_data *client_data = NULL; krb5_keyblock *challenge_key = NULL; int i = 0; plain.data = NULL; if (krb5int_accessor(&kaccess, KRB5INT_ACCESS_VERSION) != 0) return 0; retval = fast_kdc_get_armor_key(context, get_entry_proc, request, client, &armor_key); if (retval == 0 &&armor_key == NULL) { retval = ENOENT; krb5_set_error_message(context, ENOENT, "Encrypted Challenge used outside of FAST tunnel"); } scratch.data = (char *) data->contents; scratch.length = data->length; if (retval == 0) retval = kaccess.decode_enc_data(&scratch, &enc); if (retval == 0) { plain.data = malloc(enc->ciphertext.length); plain.length = enc->ciphertext.length; if (plain.data == NULL) retval = ENOMEM; } if (retval == 0) retval = get_entry_proc(context, request, client, krb5plugin_preauth_keys, &client_data); if (retval == 0) { client_keys = (krb5_keyblock *) client_data->data; for (i = 0; client_keys[i].enctype&& (retval == 0); i++ ) { retval = krb5_c_fx_cf2_simple(context, armor_key, "clientchallengearmor", &client_keys[i], "challengelongterm", &challenge_key); if (retval == 0) retval = krb5_c_decrypt(context, challenge_key, KRB5_KEYUSAGE_ENC_CHALLENGE_CLIENT, NULL, enc, &plain); if (challenge_key) krb5_free_keyblock(context, challenge_key); challenge_key = NULL; if (retval == 0) break; /*We failed to decrypt. Try next key*/ retval = 0; krb5_free_keyblock_contents(context, &client_keys[i]); } if (client_keys[i].enctype == 0) { retval = KRB5KDC_ERR_PREAUTH_FAILED; krb5_set_error_message(context, retval, "Incorrect password in encrypted challenge"); } else { /*not run out of keys*/ int j; assert (retval == 0); for (j = i+1; client_keys[j].enctype; j++) krb5_free_keyblock_contents(context, &client_keys[j]); } } if (retval == 0) retval = kaccess.decode_enc_ts(&plain, &ts); if (retval == 0) retval = krb5_timeofday(context, &now); if (retval == 0) { if (labs(now-ts->patimestamp) < context->clockskew) { enc_tkt_reply->flags |= TKT_FLG_PRE_AUTH; /* * If this fails, we won't generate a reply to the client. That * may cause the client to fail, but at this point the KDC has * considered this a success, so the return value is ignored. */ fast_kdc_replace_reply_key(context, get_entry_proc, request); krb5_c_fx_cf2_simple(context, armor_key, "kdcchallengearmor", &client_keys[i], "challengelongterm", (krb5_keyblock **) pa_request_context); } else { /*skew*/ retval = KRB5KRB_AP_ERR_SKEW; } } if (client_keys) { if (client_keys[i].enctype) krb5_free_keyblock_contents(context, &client_keys[i]); krb5_free_data(context, client_data); } if (armor_key) krb5_free_keyblock(context, armor_key); if (plain.data) free(plain.data); if (enc) kaccess.free_enc_data(context, enc); if (ts) kaccess.free_enc_ts(context, ts); return retval; }
int krb4int_send_to_kdc_addr( KTEXT pkt, KTEXT rpkt, char *realm, struct sockaddr *addr, socklen_t *addrlen) { struct addrlist al = ADDRLIST_INIT; char lrealm[REALM_SZ]; krb5int_access internals; krb5_error_code retval; struct servent *sp; int krb_udp_port = 0; int krbsec_udp_port = 0; char krbhst[MAXHOSTNAMELEN]; char *scol; int i; int err; krb5_data message, reply; /* * If "realm" is non-null, use that, otherwise get the * local realm. */ if (realm) strncpy(lrealm, realm, sizeof(lrealm) - 1); else { if (krb_get_lrealm(lrealm, 1)) { DEB (("%s: can't get local realm\n", prog)); return SKDC_CANT; } } lrealm[sizeof(lrealm) - 1] = '\0'; DEB (("lrealm is %s\n", lrealm)); retval = krb5int_accessor(&internals, KRB5INT_ACCESS_VERSION); if (retval) return KFAILURE; /* The first time, decide what port to use for the KDC. */ if (cached_krb_udp_port == 0) { sp = getservbyname("kerberos","udp"); if (sp) cached_krb_udp_port = sp->s_port; else cached_krb_udp_port = htons(KERBEROS_PORT); /* kerberos/udp */ DEB (("cached_krb_udp_port is %d\n", cached_krb_udp_port)); } /* If kerberos/udp isn't 750, try using kerberos-sec/udp (or 750) as a fallback. */ if (cached_krbsec_udp_port == 0 && cached_krb_udp_port != htons(KERBEROS_PORT)) { sp = getservbyname("kerberos-sec","udp"); if (sp) cached_krbsec_udp_port = sp->s_port; else cached_krbsec_udp_port = htons(KERBEROS_PORT); /* kerberos/udp */ DEB (("cached_krbsec_udp_port is %d\n", cached_krbsec_udp_port)); } for (i = 1; krb_get_krbhst(krbhst, lrealm, i) == KSUCCESS; ++i) { #ifdef DEBUG if (krb_debug) { DEB (("Getting host entry for %s...",krbhst)); (void) fflush(stdout); } #endif if (0 != (scol = strchr(krbhst,':'))) { krb_udp_port = htons(atoi(scol+1)); *scol = 0; if (krb_udp_port == 0) { #ifdef DEBUG if (krb_debug) { DEB (("bad port number %s\n",scol+1)); (void) fflush(stdout); } #endif continue; } krbsec_udp_port = 0; } else { krb_udp_port = cached_krb_udp_port; krbsec_udp_port = cached_krbsec_udp_port; } err = internals.add_host_to_list(&al, krbhst, krb_udp_port, krbsec_udp_port, SOCK_DGRAM, PF_INET); if (err) { retval = SKDC_CANT; goto free_al; } } if (al.naddrs == 0) { DEB (("%s: can't find any Kerberos host.\n", prog)); retval = SKDC_CANT; } message.length = pkt->length; message.data = (char *)pkt->dat; /* XXX yuck */ retval = internals.sendto_udp(NULL, &message, &al, NULL, &reply, addr, addrlen, NULL, 0, NULL); DEB(("sendto_udp returns %d\n", retval)); free_al: internals.free_addrlist(&al); if (retval) return SKDC_CANT; DEB(("reply.length=%d\n", reply.length)); if (reply.length > sizeof(rpkt->dat)) retval = SKDC_CANT; rpkt->length = 0; if (!retval) { memcpy(rpkt->dat, reply.data, reply.length); rpkt->length = reply.length; } krb5_free_data_contents(NULL, &reply); return retval; }
krb5_error_code kg_setup_keys(krb5_context context, krb5_gss_ctx_id_rec *ctx, krb5_key subkey, krb5_cksumtype *cksumtype) { krb5_error_code code; krb5int_access kaccess; assert(ctx != NULL); assert(subkey != NULL); *cksumtype = 0; ctx->proto = 0; if (ctx->enc == NULL) { ctx->signalg = -1; ctx->sealalg = -1; } code = krb5int_accessor(&kaccess, KRB5INT_ACCESS_VERSION); if (code != 0) return code; code = (*kaccess.mandatory_cksumtype)(context, subkey->keyblock.enctype, cksumtype); if (code != 0) return code; switch (subkey->keyblock.enctype) { case ENCTYPE_DES_CBC_MD5: case ENCTYPE_DES_CBC_MD4: case ENCTYPE_DES_CBC_CRC: krb5_k_free_key(context, ctx->seq); code = krb5_k_create_key(context, &subkey->keyblock, &ctx->seq); if (code != 0) return code; krb5_k_free_key(context, ctx->enc); code = kg_derive_des_enc_key(context, subkey, &ctx->enc); if (code != 0) return code; ctx->enc->keyblock.enctype = ENCTYPE_DES_CBC_RAW; ctx->seq->keyblock.enctype = ENCTYPE_DES_CBC_RAW; ctx->signalg = SGN_ALG_DES_MAC_MD5; ctx->cksum_size = 8; ctx->sealalg = SEAL_ALG_DES; break; case ENCTYPE_DES3_CBC_SHA1: code = kg_copy_keys(context, ctx, subkey); if (code != 0) return code; ctx->enc->keyblock.enctype = ENCTYPE_DES3_CBC_RAW; ctx->seq->keyblock.enctype = ENCTYPE_DES3_CBC_RAW; ctx->signalg = SGN_ALG_HMAC_SHA1_DES3_KD; ctx->cksum_size = 20; ctx->sealalg = SEAL_ALG_DES3KD; break; case ENCTYPE_ARCFOUR_HMAC: case ENCTYPE_ARCFOUR_HMAC_EXP: code = kg_copy_keys(context, ctx, subkey); if (code != 0) return code; ctx->signalg = SGN_ALG_HMAC_MD5; ctx->cksum_size = 8; ctx->sealalg = SEAL_ALG_MICROSOFT_RC4; break; default: ctx->proto = 1; break; } return 0; }