From 333471097d280a68cb1883f9b88b2b5f57c35905 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Thu, 12 May 2011 21:10:52 -0700 Subject: [PATCH] break out fast unwrap --- kdc/fast.c | 228 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 228 insertions(+) diff --git a/kdc/fast.c b/kdc/fast.c index b0089d36d..9d5aa1b0c 100644 --- a/kdc/fast.c +++ b/kdc/fast.c @@ -192,3 +192,231 @@ _kdc_fast_mk_error(krb5_context context, return ret; } + + +krb5_error_code +_kdc_fast_unwrap_request(kdc_request_t r) +{ + krb5_crypto crypto_subkey = NULL, crypto_session = NULL; + krb5_principal armor_server = NULL; + hdb_entry_ex *armor_user = NULL; + krb5_data pepper1, pepper2; + PA_FX_FAST_REQUEST fxreq; + krb5_auth_context ac = NULL; + krb5_ticket *ticket = NULL; + krb5_flags ap_req_options; + Key *armor_key = NULL; + krb5_keyblock armorkey; + krb5_error_code ret; + krb5_ap_req ap_req; + unsigned char *buf; + KrbFastReq fastreq; + size_t len, size; + krb5_data data; + const PA_DATA *pa; + int i = 0; + + pa = _kdc_find_padata(&r->req, &i, KRB5_PADATA_FX_FAST); + if (pa == NULL) + return 0; + + ret = decode_PA_FX_FAST_REQUEST(pa->padata_value.data, + pa->padata_value.length, + &fxreq, + &len); + if (ret) + goto out; + if (len != pa->padata_value.length) { + ret = KRB5KDC_ERR_PREAUTH_FAILED; + goto out; + } + + if (fxreq.element != choice_PA_FX_FAST_REQUEST_armored_data) { + kdc_log(r->context, r->config, 0, + "AS-REQ FAST contain unknown type"); + ret = KRB5KDC_ERR_PREAUTH_FAILED; + goto out; + } + + /* pull out armor key */ + if (fxreq.u.armored_data.armor == NULL) { + kdc_log(r->context, r->config, 0, + "AS-REQ armor missing"); + ret = KRB5KDC_ERR_PREAUTH_FAILED; + goto out; + } + + if (fxreq.u.armored_data.armor->armor_type != 1) { + kdc_log(r->context, r->config, 0, + "AS-REQ armor type not ap-req"); + ret = KRB5KDC_ERR_PREAUTH_FAILED; + goto out; + } + + ret = krb5_decode_ap_req(r->context, + &fxreq.u.armored_data.armor->armor_value, + &ap_req); + if(ret) { + kdc_log(r->context, r->config, 0, "AP-REQ decode failed"); + goto out; + } + + /* Save that principal that was in the request */ + ret = _krb5_principalname2krb5_principal(r->context, + &armor_server, + ap_req.ticket.sname, + ap_req.ticket.realm); + if (ret) { + free_AP_REQ(&ap_req); + goto out; + } + + ret = _kdc_db_fetch(r->context, r->config, armor_server, + HDB_F_GET_SERVER, NULL, NULL, &armor_user); + if(ret == HDB_ERR_NOT_FOUND_HERE) { + kdc_log(r->context, r->config, 5, + "armor key does not have secrets at this KDC, " + "need to proxy"); + ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; + goto out; + } if(ret){ + free_AP_REQ(&ap_req); + ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; + goto out; + } + + ret = hdb_enctype2key(r->context, &armor_user->entry, + ap_req.ticket.enc_part.etype, + &armor_key); + if (ret) { + free_AP_REQ(&ap_req); + goto out; + } + + ret = krb5_verify_ap_req2(r->context, &ac, + &ap_req, + armor_server, + &armor_key->key, + 0, + &ap_req_options, + &ticket, + KRB5_KU_AP_REQ_AUTH); + free_AP_REQ(&ap_req); + if (ret) + goto out; + + if (ac->remote_subkey == NULL) { + krb5_auth_con_free(r->context, ac); + kdc_log(r->context, r->config, 0, + "FAST AP-REQ remote subkey missing"); + ret = KRB5KDC_ERR_PREAUTH_FAILED; + goto out; + } + + ret = krb5_crypto_init(r->context, ac->remote_subkey, + 0, &crypto_subkey); + if (ret) { + krb5_auth_con_free(r->context, ac); + krb5_free_ticket(r->context, ticket); + goto out; + } + ret = krb5_crypto_init(r->context, &ticket->ticket.key, + 0, &crypto_session); + krb5_free_ticket(r->context, ticket); + if (ret) { + krb5_auth_con_free(r->context, ac); + krb5_crypto_destroy(r->context, crypto_subkey); + goto out; + } + + pepper1.data = "subkeyarmor"; + pepper1.length = strlen(pepper1.data); + pepper2.data = "ticketarmor"; + pepper2.length = strlen(pepper2.data); + + ret = krb5_crypto_fx_cf2(r->context, crypto_subkey, crypto_session, + &pepper1, &pepper2, + ac->remote_subkey->keytype, + &armorkey); + krb5_crypto_destroy(r->context, crypto_subkey); + krb5_crypto_destroy(r->context, crypto_session); + krb5_auth_con_free(r->context, ac); + if (ret) + goto out; + + ret = krb5_crypto_init(r->context, &armorkey, 0, &r->armor_crypto); + if (ret) + goto out; + krb5_free_keyblock_contents(r->context, &armorkey); + + /* verify req-checksum of the outer body */ + + ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, len, &r->req.req_body, &size, ret); + if (ret) + goto out; + if (size != len) { + ret = KRB5KDC_ERR_PREAUTH_FAILED; + goto out; + } + + ret = krb5_verify_checksum(r->context, r->armor_crypto, + KRB5_KU_FAST_REQ_CHKSUM, + buf, len, + &fxreq.u.armored_data.req_checksum); + free(buf); + if (ret) + goto out; + + ret = krb5_decrypt_EncryptedData(r->context, r->armor_crypto, + KRB5_KU_FAST_ENC, + &fxreq.u.armored_data.enc_fast_req, + &data); + if (ret) + goto out; + + ret = decode_KrbFastReq(data.data, data.length, &fastreq, &size); + if (ret) { + krb5_data_free(&data); + goto out; + } + if (data.length != size) { + krb5_data_free(&data); + ret = KRB5KDC_ERR_PREAUTH_FAILED; + goto out; + } + krb5_data_free(&data); + + free_KDC_REQ_BODY(&r->req.req_body); + ret = copy_KDC_REQ_BODY(&fastreq.req_body, &r->req.req_body); + if (ret) + goto out; + + /* check for unsupported mandatory options */ + if (FastOptions2int(fastreq.fast_options) & 0xfffc) { + kdc_log(r->context, r->config, 0, + "FAST unsupported mandatory option set"); + ret = KRB5KDC_ERR_PREAUTH_FAILED; + goto out; + } + + /* KDC MUST ignore outer pa data preauth-14 - 6.5.5 */ + if (r->req.padata) + free_METHOD_DATA(r->req.padata); + else + ALLOC(r->req.padata); + + ret = copy_METHOD_DATA(&fastreq.padata, r->req.padata); + if (ret) + goto out; + + free_KrbFastReq(&fastreq); + free_PA_FX_FAST_REQUEST(&fxreq); + + out: + if (armor_server) + krb5_free_principal(r->context, armor_server); + if(armor_user) + _kdc_free_ent(r->context, armor_user); + + return ret; +}