From a5e342f8bab0494252f77e9e6b177de6fa320ebd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Wed, 3 Jun 2009 12:00:26 -0700 Subject: [PATCH 001/119] Add fast_state. --- lib/krb5/init_creds_pw.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/krb5/init_creds_pw.c b/lib/krb5/init_creds_pw.c index 6c874126a..bd3f60220 100644 --- a/lib/krb5/init_creds_pw.c +++ b/lib/krb5/init_creds_pw.c @@ -76,6 +76,14 @@ typedef struct krb5_get_init_creds_ctx { void *prompter_data; struct pa_info_data *ppaid; + struct fast_state { + int flags; +#define KRB5_FAST_REPLY_KEY_USE_TO_ENCRYPT_THE_REPLY 1 +#define KRB5_FAST_REPLY_KEY_USE_IN_TRANSACTION 2 +#define KRB5_FAST_KDC_REPLY_KEY_REPLACED 4 +#define KRB5_FAST_REPLY_REPLY_VERIFED 8 +#define KRB5_FAST_STRONG 16 + }; } krb5_get_init_creds_ctx; From fd7c870550a2eebd4ff750ca0ff9bebee31bca01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Wed, 3 Jun 2009 12:04:52 -0700 Subject: [PATCH 002/119] add reply reply_key --- lib/krb5/init_creds_pw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/krb5/init_creds_pw.c b/lib/krb5/init_creds_pw.c index bd3f60220..91b010676 100644 --- a/lib/krb5/init_creds_pw.c +++ b/lib/krb5/init_creds_pw.c @@ -83,6 +83,7 @@ typedef struct krb5_get_init_creds_ctx { #define KRB5_FAST_KDC_REPLY_KEY_REPLACED 4 #define KRB5_FAST_REPLY_REPLY_VERIFED 8 #define KRB5_FAST_STRONG 16 + krb5_keyblock reply_key; }; } krb5_get_init_creds_ctx; From 04128ac081f2db9a9d6bb48795b66921af37cd3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Wed, 3 Jun 2009 12:13:05 -0700 Subject: [PATCH 003/119] Use reply_key from fast layer. --- lib/krb5/init_creds_pw.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/krb5/init_creds_pw.c b/lib/krb5/init_creds_pw.c index 91b010676..8da8f7e2b 100644 --- a/lib/krb5/init_creds_pw.c +++ b/lib/krb5/init_creds_pw.c @@ -83,7 +83,7 @@ typedef struct krb5_get_init_creds_ctx { #define KRB5_FAST_KDC_REPLY_KEY_REPLACED 4 #define KRB5_FAST_REPLY_REPLY_VERIFED 8 #define KRB5_FAST_STRONG 16 - krb5_keyblock reply_key; + krb5_keyblock *reply_key; }; } krb5_get_init_creds_ctx; @@ -1704,7 +1704,8 @@ krb5_init_creds_step(krb5_context context, eflags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH; ret = process_pa_data_to_key(context, ctx, &ctx->cred, - &ctx->as_req, &rep.kdc_rep, hostinfo, &key); + &ctx->as_req, &rep.kdc_rep, + hostinfo, &ctx->reply_key); if (ret) { free_AS_REP(&rep.kdc_rep); goto out; @@ -1715,7 +1716,7 @@ krb5_init_creds_step(krb5_context context, ret = _krb5_extract_ticket(context, &rep, &ctx->cred, - key, + ctx->reply_key, NULL, KRB5_KU_AS_REP_ENC_PART, NULL, @@ -1723,8 +1724,8 @@ krb5_init_creds_step(krb5_context context, eflags, NULL, NULL); - krb5_free_keyblock(context, key); - + krb5_free_keyblock(context, ctx->reply_key); + ctx->reply_key = NULL; *flags = 0; if (ret == 0) From 1879af9e43dcb3eaaa624e9ed98a899154d3d05a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Wed, 3 Jun 2009 15:25:44 -0700 Subject: [PATCH 004/119] Break out fast state, shuffle around state so that as-req is inited earlier --- lib/krb5/init_creds_pw.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/lib/krb5/init_creds_pw.c b/lib/krb5/init_creds_pw.c index 8da8f7e2b..571351e42 100644 --- a/lib/krb5/init_creds_pw.c +++ b/lib/krb5/init_creds_pw.c @@ -84,8 +84,7 @@ typedef struct krb5_get_init_creds_ctx { #define KRB5_FAST_REPLY_REPLY_VERIFED 8 #define KRB5_FAST_STRONG 16 krb5_keyblock *reply_key; - }; - + } fast_state; } krb5_get_init_creds_ctx; @@ -1386,6 +1385,13 @@ krb5_init_creds_init(krb5_context context, ctx->prompter = prompter; ctx->prompter_data = prompter_data; + ret = init_as_req(context, ctx->flags, &ctx->cred, + ctx->addrs, ctx->etypes, &ctx->as_req); + if (ret) { + free_init_creds_ctx(context, ctx); + return ret; + } + *rctx = ctx; return ret; @@ -1662,15 +1668,6 @@ krb5_init_creds_step(krb5_context context, krb5_data_zero(out); - if (ctx->as_req.req_body.cname == NULL) { - ret = init_as_req(context, ctx->flags, &ctx->cred, - ctx->addrs, ctx->etypes, &ctx->as_req); - if (ret) { - free_init_creds_ctx(context, ctx); - return ret; - } - } - #define MAX_PA_COUNTER 10 if (ctx->pa_counter > MAX_PA_COUNTER) { krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP, @@ -1705,7 +1702,7 @@ krb5_init_creds_step(krb5_context context, ret = process_pa_data_to_key(context, ctx, &ctx->cred, &ctx->as_req, &rep.kdc_rep, - hostinfo, &ctx->reply_key); + hostinfo, &ctx->fast_state.reply_key); if (ret) { free_AS_REP(&rep.kdc_rep); goto out; @@ -1716,7 +1713,7 @@ krb5_init_creds_step(krb5_context context, ret = _krb5_extract_ticket(context, &rep, &ctx->cred, - ctx->reply_key, + ctx->fast_state.reply_key, NULL, KRB5_KU_AS_REP_ENC_PART, NULL, @@ -1724,8 +1721,8 @@ krb5_init_creds_step(krb5_context context, eflags, NULL, NULL); - krb5_free_keyblock(context, ctx->reply_key); - ctx->reply_key = NULL; + krb5_free_keyblock(context, ctx->fast_state.reply_key); + ctx->fast_state.reply_key = NULL; *flags = 0; if (ret == 0) From a41439d52bac720cdf71a0e473f14be894fb4c29 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Sat, 16 Jan 2010 20:16:21 +0100 Subject: [PATCH 005/119] spelling --- lib/asn1/krb5.asn1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/asn1/krb5.asn1 b/lib/asn1/krb5.asn1 index 568fe0cd0..771b9981f 100644 --- a/lib/asn1/krb5.asn1 +++ b/lib/asn1/krb5.asn1 @@ -766,7 +766,7 @@ PA-ServerReferralData ::= SEQUENCE { FastOptions ::= BIT STRING { reserved(0), hide-client-names(1), - kdc-follow--referrals(16) + kdc-follow-referrals(16) } KrbFastReq ::= SEQUENCE { From 580ba6aa729433a297d0aa36ed450290cc145e54 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Sat, 16 Jan 2010 20:21:34 +0100 Subject: [PATCH 006/119] KU bits for fast --- lib/krb5/krb5.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/krb5/krb5.h b/lib/krb5/krb5.h index 9c0f56694..6d63cd26c 100644 --- a/lib/krb5/krb5.h +++ b/lib/krb5/krb5.h @@ -274,6 +274,10 @@ typedef enum krb5_key_usage { /* Encryption type of the kdc session contribution in pk-init */ KRB5_KU_AS_REQ = 56, /* Checksum of over the AS-REQ send by the KDC in PA-REQ-ENC-PA-REP */ + KRB5_KU_FAST_REQ_CHKSUM = 50, + /* FAST armor checksum */ + KRB5_KU_FAST_ENC = 51, + /* FAST armor encryption */ KRB5_KU_DIGEST_ENCRYPT = -18, /* Encryption key usage used in the digest encryption field */ KRB5_KU_DIGEST_OPAQUE = -19, From f2c73706095464cdceda7e4776e6ad66de2cb87d Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Sat, 16 Jan 2010 17:37:35 -0800 Subject: [PATCH 007/119] announce fx-fast --- kdc/kerberos5.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 4bc161917..27c9ff96d 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -1388,6 +1388,17 @@ _kdc_as_rep(krb5_context context, pa->padata_value.length = 0; pa->padata_value.data = NULL; #endif + /* + * Announce FX-FAST + */ + ret = realloc_method_data(&method_data); + if (ret) { + free_METHOD_DATA(&method_data); + goto out; + } + pa = &method_data.val[method_data.len-1]; + pa->padata_type = KRB5_PADATA_FX_FAST; + pa->padata_value.length = 0; /* * If there is a client key, send ETYPE_INFO{,2} From 7802e241702dffde8e434ba526a474f7183e0bcf Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Tue, 19 Jan 2010 02:26:53 +0000 Subject: [PATCH 008/119] first drop of the AS-REQ FAST + krb-error FAST codepath --- kdc/kerberos5.c | 341 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 300 insertions(+), 41 deletions(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 27c9ff96d..6df04ba30 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -962,13 +962,12 @@ _kdc_as_rep(krb5_context context, struct sockaddr *from_addr, int datagram_reply) { - KDC_REQ_BODY *b = &req->req_body; + KDC_REQ_BODY *b; AS_REP rep; - KDCOptions f = b->kdc_options; + KDCOptions f; hdb_entry_ex *client = NULL, *server = NULL; HDB *clientdb; krb5_enctype setype, sessionetype; - krb5_data e_data; EncTicketPart et; EncKDCRepPart ek; krb5_principal client_princ = NULL, server_princ = NULL; @@ -982,15 +981,175 @@ _kdc_as_rep(krb5_context context, #ifdef PKINIT pk_client_params *pkp = NULL; #endif + METHOD_DATA error_method; memset(&rep, 0, sizeof(rep)); memset(&session_key, 0, sizeof(session_key)); - krb5_data_zero(&e_data); + error_method.len = 0; + error_method.val = NULL; ALLOC(rep.padata); rep.padata->len = 0; rep.padata->val = NULL; + /* + * Look for FAST armor and unwrap + */ + { + const PA_DATA *pa; + size_t len; + + pa = _kdc_find_padata(req, &i, KRB5_PADATA_FX_FAST)); + if (pa != NULL) { + PA_FX_FAST_REQUEST fxreq; + 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 = KDC_ERR_PREAUTH_FAILED; + goto out; + } + + if (fxreq.choice != armored_data) { + kdc_log(context, config, 0, + "AS-REQ FAST contain unknown type"); + ret = KDC_ERR_PREAUTH_FAILED; + goto out; + } + + /* pull out armor key */ + if (fxreq.u.armored_data.armor == NULL) { + kdc_log(context, config, 0, + "AS-REQ armor missing"); + ret = KDC_ERR_PREAUTH_FAILED; + goto out; + } + + if (fxreq.u.armored_data.armor->armor_type != 1) { + kdc_log(context, config, 0, + "AS-REQ armor type not ap-req"); + ret = KDC_ERR_PREAUTH_FAILED; + goto out; + } + + krb5_ap_req ap_req; + + ret = krb5_decode_ap_req(context, fxreq.u.armored_data.armor->armor_value, &ap_req); + if(ret) { + kdc_log(context, config, 0, "AP-REQ decode failed"); + goto out; + } + + krb5_principal server; + + /* Save that principal that was in the request */ + ret = _krb5_principalname2krb5_principal(context, + &server, + ap_req.ticket.sname, + ap_req.ticket.realm); + if (ret) { + free_AP_REQ(&ap_req); + goto out; + } + + krb5_keyblock *keyblock = NULL; + krb5_ticket *ticket = NULL; + krb5_flags ap_req_options; + + /* XXX get keyblock */ + + krb5_auth_context ac = NULL; + + ret = krb5_verify_ap_req2(context, &ac, + &ap_req, + server, + keyblock, + 0, + &ap_req_options, + &ticket, + KRB5_KU_AP_REQ_AUTH); + free_AP_REQ(&ap_req); + if (ret) + goto out; + + if (ac->remote_subkey == NULL) { + kdc_log(context, config, 0, + "FAST AP-REQ remote subkey missing"); + ret = KDC_ERR_PREAUTH_FAILED; + goto out; + } + + krb5_keyblock armorkey; + + ret = krb5_crypto_fx_cf2(context, subkey, sessionkey, + ac->remote_subkey->keytype, &armorkey); + if (ret) + goto out; + + /* verify req-checksum of the outer body */ + + ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, len, &req->req_body, &size, ret); + if (ret) + goto out; + if (size != len) { + ret = KDC_ERR_PREAUTH_FAILED; + goto out; + } + + ret = krb5_verify_checksum(context, fastcrypto, + KRB5_KU_FAST_REQ_CHKSUM, + buf, len, + &fxreq.u.armored_data.req_checksum); + free(buf); + if (ret) + goto out; + + ret = krb5_decrypt_EncryptedData(crypto, fastcrypto, + 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) + goto out; + if (data.length != size) { + ret = KDC_ERR_PREAUTH_FAILED; + goto out; + } + + free_KDC_REQ_BODY(&req->req_body); + ret = copy_KDC_REQ_BODY(&fastreq.req_body, &req->req_body); + if (ret) + goto out; + + /* check for unsupported mandatory options */ + if (FastOptions2int(fastreq.fast_options) & 0xfffc) { + kdc_log(context, config, 0, + "FAST unsupported mandatory option set"); + ret = KDC_ERR_PREAUTH_FAILED; + goto out; + } + + /* KDC MUST ignore outer pa data preauth-14 - 6.5.5 */ + + free_METHOD_DATA(req->padata); + ret = copy_METHOD_DATA(&fastreq.padata, pa->padata); + if (ret) + goto out; + + free_KrbFastReq(&fastreq); + free_PA_FX_FAST_REQUEST(&fxreq); + } + } + + b = &req->req_body; + f = b->kdc_options; + if (f.canonicalize) flags |= HDB_F_CANON; @@ -1128,6 +1287,13 @@ _kdc_as_rep(krb5_context context, e_text = "No PKINIT PA found"; + i = 0; + pa = _kdc_find_padata(req, &i, KRB5_PADATA_ENCRYPTED_CHALLENGE); + if (pa && armor_key) { + /* XXX handle encrypted challange */ + } + + pkinit: i = 0; pa = _kdc_find_padata(req, &i, KRB5_PADATA_PK_AS_REQ); if (pa == NULL) { @@ -1348,42 +1514,39 @@ _kdc_as_rep(krb5_context context, || b->kdc_options.request_anonymous /* hack to force anon */ || client->entry.flags.require_preauth || server->entry.flags.require_preauth) { - METHOD_DATA method_data; PA_DATA *pa; unsigned char *buf; size_t len; use_pa: - method_data.len = 0; - method_data.val = NULL; - ret = realloc_method_data(&method_data); + ret = realloc_method_data(&error_method); if (ret) { - free_METHOD_DATA(&method_data); + free_METHOD_DATA(&error_method); goto out; } - pa = &method_data.val[method_data.len-1]; + pa = &error_method.val[error_method.len-1]; pa->padata_type = KRB5_PADATA_ENC_TIMESTAMP; pa->padata_value.length = 0; pa->padata_value.data = NULL; #ifdef PKINIT - ret = realloc_method_data(&method_data); + ret = realloc_method_data(&error_method); if (ret) { - free_METHOD_DATA(&method_data); + free_METHOD_DATA(&error_method); goto out; } - pa = &method_data.val[method_data.len-1]; + pa = &error_method.val[error_method.len-1]; pa->padata_type = KRB5_PADATA_PK_AS_REQ; pa->padata_value.length = 0; pa->padata_value.data = NULL; - ret = realloc_method_data(&method_data); + ret = realloc_method_data(&error_method); if (ret) { - free_METHOD_DATA(&method_data); + free_METHOD_DATA(&error_method); goto out; } - pa = &method_data.val[method_data.len-1]; + pa = &error_method.val[error_method.len-1]; pa->padata_type = KRB5_PADATA_PK_AS_REQ_WIN; pa->padata_value.length = 0; pa->padata_value.data = NULL; @@ -1391,12 +1554,12 @@ _kdc_as_rep(krb5_context context, /* * Announce FX-FAST */ - ret = realloc_method_data(&method_data); + ret = realloc_method_data(&error_method); if (ret) { - free_METHOD_DATA(&method_data); + free_METHOD_DATA(&error_method); goto out; } - pa = &method_data.val[method_data.len-1]; + pa = &error_method.val[error_method.len-1]; pa->padata_type = KRB5_PADATA_FX_FAST; pa->padata_value.length = 0; @@ -1422,28 +1585,22 @@ _kdc_as_rep(krb5_context context, if (older_enctype(ckey->key.keytype)) { ret = get_pa_etype_info(context, config, - &method_data, ckey); + &error_method, ckey); if (ret) { - free_METHOD_DATA(&method_data); + free_METHOD_DATA(&error_method); goto out; } } ret = get_pa_etype_info2(context, config, - &method_data, ckey); + &error_method, ckey); if (ret) { - free_METHOD_DATA(&method_data); + free_METHOD_DATA(&error_method); goto out; } } - ASN1_MALLOC_ENCODE(METHOD_DATA, buf, len, &method_data, &len, ret); - free_METHOD_DATA(&method_data); - - e_data.data = buf; - e_data.length = len; - e_text ="Need to use PA-ENC-TIMESTAMP/PA-PK-AS-REQ", - ret = KRB5KDC_ERR_PREAUTH_REQUIRED; + e_text ="Need to use PA-ENC-TIMESTAMP/PA-PK-AS-REQ", kdc_log(context, config, 0, "No preauth found, returning PREAUTH-REQUIRED -- %s", @@ -1462,7 +1619,7 @@ _kdc_as_rep(krb5_context context, ret = _kdc_check_access(context, config, client, client_name, server, server_name, - req, &e_data); + req, &error_method); if(ret) goto out; @@ -1834,18 +1991,120 @@ _kdc_as_rep(krb5_context context, out: free_AS_REP(&rep); + if(ret != 0 && ret != HDB_ERR_NOT_FOUND_HERE){ - krb5_mk_error(context, - ret, - e_text, - (e_data.data ? &e_data : NULL), - client_princ, - server_princ, - NULL, - NULL, - reply); - ret = 0; + krb5_data e_data; + krb5_const_principal error_client = client_princ; + krb5_const_principal error_server = server_princ; + + krb5_data_zero(&e_data); + + if (armor_key) { + PA_FX_FAST_REPLY fxfastrep; + KRBFastResponse fastrep; + + memeset(&fxfastrep, 0, sizeof(fxfastrep)); + memset(&fastrep, 0, sizeof(fastrep)); + + /* first add the KRB-ERROR to the fast errors */ + + ret = krb5_mk_error(context, + ret, + e_text, + NULL, + error_client, + error_client, + NULL, + NULL, + &e_data); + + if (/* hide_principal */ 0) { + error_client = NULL; + error_server = NULL; + e_text = NULL; + ret = KRB5KDC_ERR_PREAUTH_REQUIRED; + } + + ret = realloc_method_data(&error_method); + if (ret) + goto out2; + + pa = &error_method.val[error_method.len-1]; + pa->padata_type = KRB5_PADATA_FX_FAST_ERROR; + pa->padata_value.length = e_data.length; + pa->padata_value.length = e_data.data; + + krb5_data_zero(&e_data); + + fastrep.padata = error_method; + error_method.val = 0; + error_method.len = 0; + fastrep.strengthen_key = NULL; + fastrep.finished = NULL; + fastrep.nonce = b->nonce; + + ASN1_MALLOC_ENCODE(KRBFastResponse, e_data.data, e_data.length, + &fastrep, &len, ret); + free_KRBFastResponse(&fastrep); + if (ret) + goto out2; + if (e_data.length != len) + krb5_abortx(context, "internal asn.1 error"); + + fxfastrep.choice = armored_data_choice_PA_FX_FAST_REPLY; + + ret = krb5_encrypt_EncryptedData(context, + crypto, + KRB5_KU_USAGE_REP, + e_data.data, + e_data.length, + NULL, + &fxfastrep.u.armored_data.enc_fast_rep); + krb5_data_free(&e_data); + if (ret) + goto out2; + + ASN1_MALLOC_ENCODE(PA_FX_FAST_REPLY, e_data.data, e_data.length, + &fxfastrep, &len, ret); + if (ret) + goto out2; + if (e_data.length != len) + krb5_abortx(context, "internal asn.1 error"); + + + ret = realloc_method_data(&error_method); + if (ret) { + free_METHOD_DATA(&error_method); + goto out; + } + pa = &error_method.val[error_method.len-1]; + pa->padata_type = KRB5_PADATA_FX_FAST; + pa->padata_value = e_data; + krb5_data_zero(&e_data); + } + + if (error_method.len) { + ASN1_MALLOC_ENCODE(METHOD_DATA, e_data.data, e_data.length, + &error_method, &len, ret); + free_METHOD_DATA(&error_method); + if (ret) + goto out2; + if (e_data.length != len) + krb5_abortx(context, "internal asn.1 error"); + } + + ret = krb5_mk_error(context, + ret, + e_text, + (e_data.length ? &e_data : NULL), + error_client, + error_server, + NULL, + NULL, + reply); + krb5_data_free(&e_data); } +out2: #ifdef PKINIT if (pkp) _kdc_pk_free_client_param(context, pkp); From 86c4089df1207096b54451cb88b34ad486188faf Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Tue, 19 Jan 2010 02:49:13 +0000 Subject: [PATCH 009/119] export more --- lib/asn1/krb5.asn1 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/asn1/krb5.asn1 b/lib/asn1/krb5.asn1 index 771b9981f..8010b9b79 100644 --- a/lib/asn1/krb5.asn1 +++ b/lib/asn1/krb5.asn1 @@ -63,6 +63,8 @@ EXPORTS PA-ServerReferralData, PA-SvrReferralData, PADATA-TYPE, + PA-FX-FAST-REQUEST, + PA-FX-FAST-REPLY, Principal, PrincipalName, Principals, @@ -72,7 +74,9 @@ EXPORTS Ticket, TicketFlags, TransitedEncoding, - TypedData + TypedData, + KrbFastResponse, + KrbFastFinished ; NAME-TYPE ::= INTEGER { From 22cb2c1a1a1bbd2cd74aa231c9a7065d63ac6963 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Tue, 19 Jan 2010 03:06:19 +0000 Subject: [PATCH 010/119] export one more --- lib/asn1/krb5.asn1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/asn1/krb5.asn1 b/lib/asn1/krb5.asn1 index 8010b9b79..3fbcce441 100644 --- a/lib/asn1/krb5.asn1 +++ b/lib/asn1/krb5.asn1 @@ -76,7 +76,8 @@ EXPORTS TransitedEncoding, TypedData, KrbFastResponse, - KrbFastFinished + KrbFastFinished, + KrbFastReq ; NAME-TYPE ::= INTEGER { From 3b034b231d9fcc19ecdb184ea919d9e6d520eaca Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Tue, 19 Jan 2010 03:06:32 +0000 Subject: [PATCH 011/119] more bits --- kdc/kerberos5.c | 64 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 17 deletions(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 6df04ba30..0ae3e250f 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -998,10 +998,13 @@ _kdc_as_rep(krb5_context context, { const PA_DATA *pa; size_t len; + int i = 0; - pa = _kdc_find_padata(req, &i, KRB5_PADATA_FX_FAST)); + pa = _kdc_find_padata(req, &i, KRB5_PADATA_FX_FAST); if (pa != NULL) { PA_FX_FAST_REQUEST fxreq; + krb5_keyblock armorkey; + ret = decode_PA_FX_FAST_REQUEST(pa->padata_value.data, pa->padata_value.length, &fxreq, @@ -1009,14 +1012,14 @@ _kdc_as_rep(krb5_context context, if (ret) goto out; if (len != pa->padata_value.length) { - ret = KDC_ERR_PREAUTH_FAILED; + ret = KRB5KDC_ERR_PREAUTH_FAILED; goto out; } - if (fxreq.choice != armored_data) { + if (fxreq.element != choice_PA_FX_FAST_REQUEST_armored_data) { kdc_log(context, config, 0, "AS-REQ FAST contain unknown type"); - ret = KDC_ERR_PREAUTH_FAILED; + ret = KRB5KDC_ERR_PREAUTH_FAILED; goto out; } @@ -1024,20 +1027,22 @@ _kdc_as_rep(krb5_context context, if (fxreq.u.armored_data.armor == NULL) { kdc_log(context, config, 0, "AS-REQ armor missing"); - ret = KDC_ERR_PREAUTH_FAILED; + ret = KRB5KDC_ERR_PREAUTH_FAILED; goto out; } if (fxreq.u.armored_data.armor->armor_type != 1) { kdc_log(context, config, 0, "AS-REQ armor type not ap-req"); - ret = KDC_ERR_PREAUTH_FAILED; + ret = KRB5KDC_ERR_PREAUTH_FAILED; goto out; } krb5_ap_req ap_req; - ret = krb5_decode_ap_req(context, fxreq.u.armored_data.armor->armor_value, &ap_req); + ret = krb5_decode_ap_req(context, + &fxreq.u.armored_data.armor->armor_value, + &ap_req); if(ret) { kdc_log(context, config, 0, "AP-REQ decode failed"); goto out; @@ -1078,28 +1083,47 @@ _kdc_as_rep(krb5_context context, if (ac->remote_subkey == NULL) { kdc_log(context, config, 0, "FAST AP-REQ remote subkey missing"); - ret = KDC_ERR_PREAUTH_FAILED; + ret = KRB5KDC_ERR_PREAUTH_FAILED; goto out; } - krb5_keyblock armorkey; + krb5_crypto crypto_subkey, crypto_session, armor_crypto = NULL; - ret = krb5_crypto_fx_cf2(context, subkey, sessionkey, + krb5_crypto_init(context, ac->remote_subkey, 0, &crypto_subkey); + krb5_crypto_init(context, ac->keyblock, 0, &crypto_session); + + krb5_data pepper1, pepper2; + pepper1.data = "subkeyarmor"; + pepper1.length = strlen(pepper1.data); + pepper2.data = "ticketarmor"; + pepper2.length = strlen(pepper2.data); + + ret = krb5_crypto_fx_cf2(context, crypto_subkey, crypto_session, + &pepper1, &pepper2, ac->remote_subkey->keytype, &armorkey); + krb5_crypto_destroy(context, crypto_subkey); + krb5_crypto_destroy(context, crypto_session); + if (ret) goto out; + krb5_crypto_init(context, &armorkey, 0, &armor_crypto); + krb5_free_keyblock_contents(context, &armorkey); + /* verify req-checksum of the outer body */ + unsigned char *buf; + size_t len, size; + ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, len, &req->req_body, &size, ret); if (ret) goto out; if (size != len) { - ret = KDC_ERR_PREAUTH_FAILED; + ret = KRB5KDC_ERR_PREAUTH_FAILED; goto out; } - ret = krb5_verify_checksum(context, fastcrypto, + ret = krb5_verify_checksum(context, armor_crypto, KRB5_KU_FAST_REQ_CHKSUM, buf, len, &fxreq.u.armored_data.req_checksum); @@ -1107,7 +1131,9 @@ _kdc_as_rep(krb5_context context, if (ret) goto out; - ret = krb5_decrypt_EncryptedData(crypto, fastcrypto, + krb5_data data; + + ret = krb5_decrypt_EncryptedData(context, armor_crypto, KRB5_KU_FAST_ENC, &fxreq.u.armored_data.enc_fast_req, &data); @@ -1115,12 +1141,16 @@ _kdc_as_rep(krb5_context context, goto out; ret = decode_KrbFastReq(data.data, data.length, &fastreq, &size); - if (ret) + if (ret) { + krb5_data_free(&data); goto out; + } if (data.length != size) { - ret = KDC_ERR_PREAUTH_FAILED; + krb5_data_free(&data); + ret = KRB5KDC_ERR_PREAUTH_FAILED; goto out; } + krb5_data_free(&data); free_KDC_REQ_BODY(&req->req_body); ret = copy_KDC_REQ_BODY(&fastreq.req_body, &req->req_body); @@ -1131,7 +1161,7 @@ _kdc_as_rep(krb5_context context, if (FastOptions2int(fastreq.fast_options) & 0xfffc) { kdc_log(context, config, 0, "FAST unsupported mandatory option set"); - ret = KDC_ERR_PREAUTH_FAILED; + ret = KRB5KDC_ERR_PREAUTH_FAILED; goto out; } @@ -2051,7 +2081,7 @@ out: if (e_data.length != len) krb5_abortx(context, "internal asn.1 error"); - fxfastrep.choice = armored_data_choice_PA_FX_FAST_REPLY; + fxfastrep.element = choice_PA_FX_FAST_REPLY_armored_data; ret = krb5_encrypt_EncryptedData(context, crypto, From 7d30fc38d7e8a6c5f5c6bada3388fdcec92f881e Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Tue, 19 Jan 2010 04:08:50 +0000 Subject: [PATCH 012/119] use METHOD-DATA for type compat in kdc/kerberos5.c --- lib/asn1/krb5.asn1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/asn1/krb5.asn1 b/lib/asn1/krb5.asn1 index 3fbcce441..b52f933c4 100644 --- a/lib/asn1/krb5.asn1 +++ b/lib/asn1/krb5.asn1 @@ -776,7 +776,7 @@ FastOptions ::= BIT STRING { KrbFastReq ::= SEQUENCE { fast-options [0] FastOptions, - padata [1] SEQUENCE OF PA-DATA, + padata [1] METHOD-DATA, req-body [2] KDC-REQ-BODY, ... } From 60c713221d860d0d260946d7b90c84b1376a977f Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Tue, 19 Jan 2010 04:17:27 +0000 Subject: [PATCH 013/119] match draft-preauth-framework-14 better --- lib/asn1/krb5.asn1 | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/asn1/krb5.asn1 b/lib/asn1/krb5.asn1 index b52f933c4..155d3c5be 100644 --- a/lib/asn1/krb5.asn1 +++ b/lib/asn1/krb5.asn1 @@ -809,9 +809,10 @@ KrbFastFinished ::= SEQUENCE { } KrbFastResponse ::= SEQUENCE { - padata [0] SEQUENCE OF PA-DATA, - rep-key [1] EncryptionKey OPTIONAL, - finished [2] KrbFastFinished OPTIONAL, + padata [0] METHOD-DATA, + strengthen-key [1] EncryptionKey OPTIONAL, + finished [2] KrbFastFinished OPTIONAL, + nonce [3] krb5uint32, ... } From c148c2b432192b7fcd32325403533a4ee5f801cd Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Tue, 19 Jan 2010 04:21:56 +0000 Subject: [PATCH 014/119] unused key --- lib/krb5/init_creds_pw.c | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/krb5/init_creds_pw.c b/lib/krb5/init_creds_pw.c index 571351e42..dc4d9d0f3 100644 --- a/lib/krb5/init_creds_pw.c +++ b/lib/krb5/init_creds_pw.c @@ -1690,7 +1690,6 @@ krb5_init_creds_step(krb5_context context, ret = decode_AS_REP(in->data, in->length, &rep.kdc_rep, &size); if (ret == 0) { - krb5_keyblock *key = NULL; unsigned eflags = EXTRACT_TICKET_AS_REQ | EXTRACT_TICKET_TIMESYNC; if (ctx->flags.canonicalize) { From 96299ac2bbfda25db80596d1d00f3ab84a82f9fc Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Tue, 19 Jan 2010 04:28:48 +0000 Subject: [PATCH 015/119] no warnings --- kdc/kerberos5.c | 95 +++++++++++++++++++++++-------------------------- 1 file changed, 44 insertions(+), 51 deletions(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 0ae3e250f..580ff8e0a 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -962,7 +962,7 @@ _kdc_as_rep(krb5_context context, struct sockaddr *from_addr, int datagram_reply) { - KDC_REQ_BODY *b; + KDC_REQ_BODY *b = NULL; AS_REP rep; KDCOptions f; hdb_entry_ex *client = NULL, *server = NULL; @@ -982,6 +982,7 @@ _kdc_as_rep(krb5_context context, pk_client_params *pkp = NULL; #endif METHOD_DATA error_method; + krb5_crypto armor_crypto = NULL; memset(&rep, 0, sizeof(rep)); memset(&session_key, 0, sizeof(session_key)); @@ -1087,7 +1088,7 @@ _kdc_as_rep(krb5_context context, goto out; } - krb5_crypto crypto_subkey, crypto_session, armor_crypto = NULL; + krb5_crypto crypto_subkey, crypto_session; krb5_crypto_init(context, ac->remote_subkey, 0, &crypto_subkey); krb5_crypto_init(context, ac->keyblock, 0, &crypto_session); @@ -1140,6 +1141,8 @@ _kdc_as_rep(krb5_context context, if (ret) goto out; + KrbFastReq fastreq; + ret = decode_KrbFastReq(data.data, data.length, &fastreq, &size); if (ret) { krb5_data_free(&data); @@ -1168,7 +1171,7 @@ _kdc_as_rep(krb5_context context, /* KDC MUST ignore outer pa data preauth-14 - 6.5.5 */ free_METHOD_DATA(req->padata); - ret = copy_METHOD_DATA(&fastreq.padata, pa->padata); + ret = copy_METHOD_DATA(&fastreq.padata, req->padata); if (ret) goto out; @@ -1319,8 +1322,12 @@ _kdc_as_rep(krb5_context context, i = 0; pa = _kdc_find_padata(req, &i, KRB5_PADATA_ENCRYPTED_CHALLENGE); - if (pa && armor_key) { + if (pa && armor_crypto) { /* XXX handle encrypted challange */ + + if (1) + goto pkinit; + } pkinit: @@ -1545,16 +1552,12 @@ _kdc_as_rep(krb5_context context, || client->entry.flags.require_preauth || server->entry.flags.require_preauth) { PA_DATA *pa; - unsigned char *buf; - size_t len; use_pa: ret = realloc_method_data(&error_method); - if (ret) { - free_METHOD_DATA(&error_method); + if (ret) goto out; - } pa = &error_method.val[error_method.len-1]; pa->padata_type = KRB5_PADATA_ENC_TIMESTAMP; pa->padata_value.length = 0; @@ -1562,20 +1565,16 @@ _kdc_as_rep(krb5_context context, #ifdef PKINIT ret = realloc_method_data(&error_method); - if (ret) { - free_METHOD_DATA(&error_method); + if (ret) goto out; - } pa = &error_method.val[error_method.len-1]; pa->padata_type = KRB5_PADATA_PK_AS_REQ; pa->padata_value.length = 0; pa->padata_value.data = NULL; ret = realloc_method_data(&error_method); - if (ret) { - free_METHOD_DATA(&error_method); + if (ret) goto out; - } pa = &error_method.val[error_method.len-1]; pa->padata_type = KRB5_PADATA_PK_AS_REQ_WIN; pa->padata_value.length = 0; @@ -1585,10 +1584,8 @@ _kdc_as_rep(krb5_context context, * Announce FX-FAST */ ret = realloc_method_data(&error_method); - if (ret) { - free_METHOD_DATA(&error_method); + if (ret) goto out; - } pa = &error_method.val[error_method.len-1]; pa->padata_type = KRB5_PADATA_FX_FAST; pa->padata_value.length = 0; @@ -1616,17 +1613,13 @@ _kdc_as_rep(krb5_context context, if (older_enctype(ckey->key.keytype)) { ret = get_pa_etype_info(context, config, &error_method, ckey); - if (ret) { - free_METHOD_DATA(&error_method); + if (ret) goto out; - } } ret = get_pa_etype_info2(context, config, &error_method, ckey); - if (ret) { - free_METHOD_DATA(&error_method); + if (ret) goto out; - } } ret = KRB5KDC_ERR_PREAUTH_REQUIRED; @@ -2024,16 +2017,18 @@ out: if(ret != 0 && ret != HDB_ERR_NOT_FOUND_HERE){ krb5_data e_data; - krb5_const_principal error_client = client_princ; - krb5_const_principal error_server = server_princ; + krb5_principal error_client = client_princ; + krb5_principal error_server = server_princ; + size_t size; krb5_data_zero(&e_data); - if (armor_key) { + if (armor_crypto) { PA_FX_FAST_REPLY fxfastrep; - KRBFastResponse fastrep; + KrbFastResponse fastrep; + PA_DATA *pa; - memeset(&fxfastrep, 0, sizeof(fxfastrep)); + memset(&fxfastrep, 0, sizeof(fxfastrep)); memset(&fastrep, 0, sizeof(fastrep)); /* first add the KRB-ERROR to the fast errors */ @@ -2043,7 +2038,7 @@ out: e_text, NULL, error_client, - error_client, + error_server, NULL, NULL, &e_data); @@ -2060,9 +2055,8 @@ out: goto out2; pa = &error_method.val[error_method.len-1]; - pa->padata_type = KRB5_PADATA_FX_FAST_ERROR; - pa->padata_value.length = e_data.length; - pa->padata_value.length = e_data.data; + pa->padata_type = KRB5_PADATA_FX_ERROR; + pa->padata_value = e_data; krb5_data_zero(&e_data); @@ -2071,42 +2065,40 @@ out: error_method.len = 0; fastrep.strengthen_key = NULL; fastrep.finished = NULL; - fastrep.nonce = b->nonce; + fastrep.nonce = req->req_body.nonce; - ASN1_MALLOC_ENCODE(KRBFastResponse, e_data.data, e_data.length, - &fastrep, &len, ret); - free_KRBFastResponse(&fastrep); + ASN1_MALLOC_ENCODE(KrbFastResponse, e_data.data, e_data.length, + &fastrep, &size, ret); + free_KrbFastResponse(&fastrep); if (ret) goto out2; - if (e_data.length != len) + if (e_data.length != size) krb5_abortx(context, "internal asn.1 error"); fxfastrep.element = choice_PA_FX_FAST_REPLY_armored_data; ret = krb5_encrypt_EncryptedData(context, - crypto, - KRB5_KU_USAGE_REP, + armor_crypto, + KRB5_KU_FAST_REP, e_data.data, e_data.length, - NULL, + 0, &fxfastrep.u.armored_data.enc_fast_rep); krb5_data_free(&e_data); if (ret) goto out2; ASN1_MALLOC_ENCODE(PA_FX_FAST_REPLY, e_data.data, e_data.length, - &fxfastrep, &len, ret); + &fxfastrep, &size, ret); if (ret) goto out2; - if (e_data.length != len) + if (e_data.length != size) krb5_abortx(context, "internal asn.1 error"); ret = realloc_method_data(&error_method); - if (ret) { - free_METHOD_DATA(&error_method); + if (ret) goto out; - } pa = &error_method.val[error_method.len-1]; pa->padata_type = KRB5_PADATA_FX_FAST; pa->padata_value = e_data; @@ -2115,11 +2107,10 @@ out: if (error_method.len) { ASN1_MALLOC_ENCODE(METHOD_DATA, e_data.data, e_data.length, - &error_method, &len, ret); - free_METHOD_DATA(&error_method); + &error_method, &size, ret); if (ret) goto out2; - if (e_data.length != len) + if (e_data.length != size) krb5_abortx(context, "internal asn.1 error"); } @@ -2135,12 +2126,14 @@ out: krb5_data_free(&e_data); } out2: + if (armor_crypto) + krb5_crypto_destroy(context, armor_crypto); #ifdef PKINIT if (pkp) _kdc_pk_free_client_param(context, pkp); #endif - if (e_data.data) - free(e_data.data); + if (error_method.len) + free_METHOD_DATA(&error_method); if (client_princ) krb5_free_principal(context, client_princ); free(client_name); From d04289855e16c097bb6dd2f7c4b9e7731dc316eb Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Tue, 19 Jan 2010 04:31:01 +0000 Subject: [PATCH 016/119] more bits --- kdc/kerberos5.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 580ff8e0a..d4aa2ee15 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -1082,6 +1082,7 @@ _kdc_as_rep(krb5_context context, goto out; if (ac->remote_subkey == NULL) { + krb5_auth_con_free(context, ac); kdc_log(context, config, 0, "FAST AP-REQ remote subkey missing"); ret = KRB5KDC_ERR_PREAUTH_FAILED; @@ -1102,6 +1103,7 @@ _kdc_as_rep(krb5_context context, ret = krb5_crypto_fx_cf2(context, crypto_subkey, crypto_session, &pepper1, &pepper2, ac->remote_subkey->keytype, &armorkey); + krb5_auth_con_free(context, ac); krb5_crypto_destroy(context, crypto_subkey); krb5_crypto_destroy(context, crypto_session); @@ -1996,6 +1998,8 @@ _kdc_as_rep(krb5_context context, log_as_req(context, config, reply_key->keytype, setype, b); + /* XXX handle fast reply */ + ret = _kdc_encode_reply(context, config, &rep, &et, &ek, setype, server->entry.kvno, &skey->key, client->entry.kvno, From a1feab396eea5d0ffcf9b98aca0ab7b75adb4435 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Tue, 19 Jan 2010 04:33:19 +0000 Subject: [PATCH 017/119] more ticket bits --- kdc/kerberos5.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index d4aa2ee15..d758c0dab 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -1092,7 +1092,9 @@ _kdc_as_rep(krb5_context context, krb5_crypto crypto_subkey, crypto_session; krb5_crypto_init(context, ac->remote_subkey, 0, &crypto_subkey); - krb5_crypto_init(context, ac->keyblock, 0, &crypto_session); + krb5_crypto_init(context, &ticket->ticket.key, 0, &crypto_session); + + krb5_free_ticket(context, ticket); krb5_data pepper1, pepper2; pepper1.data = "subkeyarmor"; From 1af9487bff68be0b3715f0cfc637e04f30eee8f9 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Tue, 19 Jan 2010 04:41:46 +0000 Subject: [PATCH 018/119] got fetch armor key --- kdc/kerberos5.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index d758c0dab..b23671eba 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -965,7 +965,7 @@ _kdc_as_rep(krb5_context context, KDC_REQ_BODY *b = NULL; AS_REP rep; KDCOptions f; - hdb_entry_ex *client = NULL, *server = NULL; + hdb_entry_ex *client = NULL, *server = NULL, *armor_user = NULL; HDB *clientdb; krb5_enctype setype, sessionetype; EncTicketPart et; @@ -1049,11 +1049,11 @@ _kdc_as_rep(krb5_context context, goto out; } - krb5_principal server; + krb5_principal armor_server; /* Save that principal that was in the request */ ret = _krb5_principalname2krb5_principal(context, - &server, + &armor_server, ap_req.ticket.sname, ap_req.ticket.realm); if (ret) { @@ -1061,18 +1061,30 @@ _kdc_as_rep(krb5_context context, goto out; } - krb5_keyblock *keyblock = NULL; + Key *armor_key = NULL; krb5_ticket *ticket = NULL; krb5_flags ap_req_options; - /* XXX get keyblock */ + ret = _kdc_db_fetch(context, config, armor_server, + HDB_F_GET_SERVER, NULL, &armor_user); + if(ret){ + ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; + goto out; + } + + ret = hdb_enctype2key(context, &armor_user->entry, + ap_req.ticket.enc_part.etype, + &armor_key); + if (ret) { + goto out; + } krb5_auth_context ac = NULL; ret = krb5_verify_ap_req2(context, &ac, &ap_req, - server, - keyblock, + armor_server, + &armor_key->key, 0, &ap_req_options, &ticket, @@ -2132,8 +2144,6 @@ out: krb5_data_free(&e_data); } out2: - if (armor_crypto) - krb5_crypto_destroy(context, armor_crypto); #ifdef PKINIT if (pkp) _kdc_pk_free_client_param(context, pkp); @@ -2150,6 +2160,10 @@ out2: _kdc_free_ent(context, client); if(server) _kdc_free_ent(context, server); + if(armor_user) + _kdc_free_ent(context, armor_user); + if (armor_crypto) + krb5_crypto_destroy(context, armor_crypto); return ret; } From e372cc6b8a0554dcde84cea505e7126caa2427b2 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Tue, 19 Jan 2010 05:24:02 +0000 Subject: [PATCH 019/119] re-shuffle to make c90 compatible --- kdc/kerberos5.c | 57 ++++++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index b23671eba..7c74032f4 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -998,13 +998,25 @@ _kdc_as_rep(krb5_context context, */ { const PA_DATA *pa; - size_t len; int i = 0; pa = _kdc_find_padata(req, &i, KRB5_PADATA_FX_FAST); if (pa != NULL) { + krb5_crypto crypto_subkey = NULL, crypto_session = NULL; + krb5_data pepper1, pepper2; PA_FX_FAST_REQUEST fxreq; + krb5_principal armor_server; + krb5_auth_context ac = NULL; + krb5_ticket *ticket = NULL; + krb5_flags ap_req_options; + Key *armor_key = NULL; krb5_keyblock armorkey; + krb5_ap_req ap_req; + unsigned char *buf; + KrbFastReq fastreq; + size_t len, size; + krb5_data data; + ret = decode_PA_FX_FAST_REQUEST(pa->padata_value.data, pa->padata_value.length, @@ -1039,8 +1051,6 @@ _kdc_as_rep(krb5_context context, goto out; } - krb5_ap_req ap_req; - ret = krb5_decode_ap_req(context, &fxreq.u.armored_data.armor->armor_value, &ap_req); @@ -1049,8 +1059,6 @@ _kdc_as_rep(krb5_context context, goto out; } - krb5_principal armor_server; - /* Save that principal that was in the request */ ret = _krb5_principalname2krb5_principal(context, &armor_server, @@ -1061,13 +1069,10 @@ _kdc_as_rep(krb5_context context, goto out; } - Key *armor_key = NULL; - krb5_ticket *ticket = NULL; - krb5_flags ap_req_options; - ret = _kdc_db_fetch(context, config, armor_server, HDB_F_GET_SERVER, NULL, &armor_user); if(ret){ + free_AP_REQ(&ap_req); ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; goto out; } @@ -1076,11 +1081,10 @@ _kdc_as_rep(krb5_context context, ap_req.ticket.enc_part.etype, &armor_key); if (ret) { + free_AP_REQ(&ap_req); goto out; } - krb5_auth_context ac = NULL; - ret = krb5_verify_ap_req2(context, &ac, &ap_req, armor_server, @@ -1101,14 +1105,21 @@ _kdc_as_rep(krb5_context context, goto out; } - krb5_crypto crypto_subkey, crypto_session; - - krb5_crypto_init(context, ac->remote_subkey, 0, &crypto_subkey); - krb5_crypto_init(context, &ticket->ticket.key, 0, &crypto_session); - + ret = krb5_crypto_init(context, ac->remote_subkey, + 0, &crypto_subkey); + krb5_auth_con_free(context, ac); + if (ret) { + krb5_free_ticket(context, ticket); + goto out; + } + ret = krb5_crypto_init(context, &ticket->ticket.key, + 0, &crypto_session); krb5_free_ticket(context, ticket); + if (ret) { + krb5_crypto_destroy(context, crypto_subkey); + goto out; + } - krb5_data pepper1, pepper2; pepper1.data = "subkeyarmor"; pepper1.length = strlen(pepper1.data); pepper2.data = "ticketarmor"; @@ -1116,8 +1127,8 @@ _kdc_as_rep(krb5_context context, ret = krb5_crypto_fx_cf2(context, crypto_subkey, crypto_session, &pepper1, &pepper2, - ac->remote_subkey->keytype, &armorkey); - krb5_auth_con_free(context, ac); + ac->remote_subkey->keytype, + &armorkey); krb5_crypto_destroy(context, crypto_subkey); krb5_crypto_destroy(context, crypto_session); @@ -1129,9 +1140,6 @@ _kdc_as_rep(krb5_context context, /* verify req-checksum of the outer body */ - unsigned char *buf; - size_t len, size; - ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, len, &req->req_body, &size, ret); if (ret) goto out; @@ -1148,8 +1156,6 @@ _kdc_as_rep(krb5_context context, if (ret) goto out; - krb5_data data; - ret = krb5_decrypt_EncryptedData(context, armor_crypto, KRB5_KU_FAST_ENC, &fxreq.u.armored_data.enc_fast_req, @@ -1157,8 +1163,6 @@ _kdc_as_rep(krb5_context context, if (ret) goto out; - KrbFastReq fastreq; - ret = decode_KrbFastReq(data.data, data.length, &fastreq, &size); if (ret) { krb5_data_free(&data); @@ -1185,7 +1189,6 @@ _kdc_as_rep(krb5_context context, } /* KDC MUST ignore outer pa data preauth-14 - 6.5.5 */ - free_METHOD_DATA(req->padata); ret = copy_METHOD_DATA(&fastreq.padata, req->padata); if (ret) From 6a74bba8f9605d9d31144e2373982c69e0ef1a6a Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Tue, 19 Jan 2010 16:37:38 +0000 Subject: [PATCH 020/119] move out generic fast packet building into fast.c --- kdc/kerberos5.c | 66 +++++++++++++++---------------------------------- 1 file changed, 20 insertions(+), 46 deletions(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 7c74032f4..6ff1e06a8 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -2016,6 +2016,9 @@ _kdc_as_rep(krb5_context context, log_as_req(context, config, reply_key->keytype, setype, b); /* XXX handle fast reply */ + if (armor_crypto) { + + } ret = _kdc_encode_reply(context, config, &rep, &et, &ek, setype, server->entry.kvno, @@ -2063,6 +2066,8 @@ out: NULL, NULL, &e_data); + if (ret) + goto out2; if (/* hide_principal */ 0) { error_client = NULL; @@ -2071,59 +2076,28 @@ out: ret = KRB5KDC_ERR_PREAUTH_REQUIRED; } - ret = realloc_method_data(&error_method); - if (ret) + ret = krb5_padata_add(context, &error_method, + KRB5_PADATA_FX_FAST, + e_data.data, e_data.length); + if (ret) { + krb5_free_data(&e_data); goto out2; - - pa = &error_method.val[error_method.len-1]; - pa->padata_type = KRB5_PADATA_FX_ERROR; - pa->padata_value = e_data; - + } krb5_data_zero(&e_data); - fastrep.padata = error_method; - error_method.val = 0; - error_method.len = 0; - fastrep.strengthen_key = NULL; - fastrep.finished = NULL; - fastrep.nonce = req->req_body.nonce; - - ASN1_MALLOC_ENCODE(KrbFastResponse, e_data.data, e_data.length, - &fastrep, &size, ret); - free_KrbFastResponse(&fastrep); - if (ret) - goto out2; - if (e_data.length != size) - krb5_abortx(context, "internal asn.1 error"); - - fxfastrep.element = choice_PA_FX_FAST_REPLY_armored_data; - - ret = krb5_encrypt_EncryptedData(context, - armor_crypto, - KRB5_KU_FAST_REP, - e_data.data, - e_data.length, - 0, - &fxfastrep.u.armored_data.enc_fast_rep); - krb5_data_free(&e_data); + ret = _kdc_fast_mk_responce(context, armor_crypto, + &error_method, NULL, NULL, + req->req_body.nonce, &e_data); + free_METHOD_DATA(&error_method); if (ret) goto out2; - ASN1_MALLOC_ENCODE(PA_FX_FAST_REPLY, e_data.data, e_data.length, - &fxfastrep, &size, ret); - if (ret) - goto out2; - if (e_data.length != size) - krb5_abortx(context, "internal asn.1 error"); - - - ret = realloc_method_data(&error_method); - if (ret) - goto out; - pa = &error_method.val[error_method.len-1]; - pa->padata_type = KRB5_PADATA_FX_FAST; - pa->padata_value = e_data; + ret = krb5_padata_add(context, &error_method, + KRB5_PADATA_FX_FAST, + e_data.data, e_data.length); krb5_data_zero(&e_data); + if (ret) + goto out2; } if (error_method.len) { From 5edb5d02759edd5a6169907eb895b100806f79d4 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Tue, 19 Jan 2010 16:38:35 +0000 Subject: [PATCH 021/119] move out generic fast packet building into fast.c --- kdc/fast.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 kdc/fast.c diff --git a/kdc/fast.c b/kdc/fast.c new file mode 100644 index 000000000..719bac212 --- /dev/null +++ b/kdc/fast.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 1997-2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kdc_locl.h" + +krb5_error_code +_kdc_fast_mk_response(krb5_context context, + krb5_crypto armor_crypto, + METHOD_DATA *pa_data, + krb5_keyblock *strengthen_key, + KrbFastFinished *finished, + krb5uint32 nonce, + krb5_data *data) +{ + PA_FX_FAST_REPLY fxfastrep; + KrbFastResponse fastrep; + krb5_error_code ret; + krb5_data buf; + size_t size; + + memset(&fxfastrep, 0, sizeof(fxfastrep)); + krb5_data_zero(data); + + fastrep.padata.val = pa_data->val; + fastrep.padata.len = pa_data->len; + fastrep.strengthen_key = strengthen_key; + fastrep.finished = finished; + fastrep.nonce = nonce; + + ASN1_MALLOC_ENCODE(KrbFastResponse, buf.data, buf.length, + &fastrep, &size, ret); + if (ret) + return ret; + if (buf.length != size) + krb5_abortx(context, "internal asn.1 error"); + + fxfastrep.element = choice_PA_FX_FAST_REPLY_armored_data; + + ret = krb5_encrypt_EncryptedData(context, + armor_crypto, + KRB5_KU_FAST_REP, + buf.data, + buf.length, + 0, + &fxfastrep.u.armored_data.enc_fast_rep); + krb5_data_free(&buf); + if (ret) + return ret; + + ASN1_MALLOC_ENCODE(PA_FX_FAST_REPLY, data->data, data->length, + &fxfastrep, &size, ret); + free_PA_FX_FAST_REPLY(&fxfastrep); + if (ret) + return ret; + if (data->length != size) + krb5_abortx(context, "internal asn.1 error"); + + return 0; +} From c6a9bdb14067125031ddbd86de1e7686cf6d2d21 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Tue, 19 Jan 2010 16:38:59 +0000 Subject: [PATCH 022/119] spelling --- kdc/kerberos5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 6ff1e06a8..16df8da5b 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -2085,7 +2085,7 @@ out: } krb5_data_zero(&e_data); - ret = _kdc_fast_mk_responce(context, armor_crypto, + ret = _kdc_fast_mk_response(context, armor_crypto, &error_method, NULL, NULL, req->req_body.nonce, &e_data); free_METHOD_DATA(&error_method); From 580b370e087339596fa0a8064678d4c7c9dcba66 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Tue, 19 Jan 2010 16:40:48 +0000 Subject: [PATCH 023/119] make pa-data optional --- kdc/fast.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/kdc/fast.c b/kdc/fast.c index 719bac212..dff78d0a3 100644 --- a/kdc/fast.c +++ b/kdc/fast.c @@ -51,10 +51,13 @@ _kdc_fast_mk_response(krb5_context context, size_t size; memset(&fxfastrep, 0, sizeof(fxfastrep)); + memset(&fastrep, 0, sizeof(fastrep)); krb5_data_zero(data); - fastrep.padata.val = pa_data->val; - fastrep.padata.len = pa_data->len; + if (pa_data) { + fastrep.padata.val = pa_data->val; + fastrep.padata.len = pa_data->len; + } fastrep.strengthen_key = strengthen_key; fastrep.finished = finished; fastrep.nonce = nonce; From 35d4b23a22c70bf1af14635e4c1dda058e3fa56e Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Tue, 19 Jan 2010 17:05:45 +0000 Subject: [PATCH 024/119] start error codes finish message --- kdc/kerberos5.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 16df8da5b..a2a375a59 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -2017,7 +2017,17 @@ _kdc_as_rep(krb5_context context, /* XXX handle fast reply */ if (armor_crypto) { + krb5_data data; + krb5_keyblock *strengthen_key = NULL; + KrbFastFinished finished; + memset(&finished, 0, sizeof(finished)); + + ret = _kdc_fast_mk_response(context, armor_crypto, + rep.padata, strengthen_key, &finished, + req->req_body.nonce, &data); + if (ret) + goto out2; } ret = _kdc_encode_reply(context, config, @@ -2050,7 +2060,6 @@ out: if (armor_crypto) { PA_FX_FAST_REPLY fxfastrep; KrbFastResponse fastrep; - PA_DATA *pa; memset(&fxfastrep, 0, sizeof(fxfastrep)); memset(&fastrep, 0, sizeof(fastrep)); @@ -2080,7 +2089,7 @@ out: KRB5_PADATA_FX_FAST, e_data.data, e_data.length); if (ret) { - krb5_free_data(&e_data); + krb5_data_free(&e_data); goto out2; } krb5_data_zero(&e_data); From dfd7a43e4422e2fbc79176685e9cdf4dba99581f Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Tue, 19 Jan 2010 17:05:59 +0000 Subject: [PATCH 025/119] change client access message --- kdc/windc_plugin.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kdc/windc_plugin.h b/kdc/windc_plugin.h index fa4ba434f..4401500e6 100644 --- a/kdc/windc_plugin.h +++ b/kdc/windc_plugin.h @@ -68,9 +68,9 @@ typedef krb5_error_code (*krb5plugin_windc_client_access)( void *, krb5_context, krb5_kdc_configuration *config, - hdb_entry_ex *, const char *, - hdb_entry_ex *, const char *, - KDC_REQ *, krb5_data *); + hdb_entry_ex *, const char *, + hdb_entry_ex *, const char *, + KDC_REQ *, METHOD_DATA *); #define KRB5_WINDC_PLUGIN_MINOR 6 From 2f5d801156013126cd88a6528f56ab09be9294ed Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Tue, 19 Jan 2010 17:06:08 +0000 Subject: [PATCH 026/119] change client access message --- kdc/windc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/kdc/windc.c b/kdc/windc.c index ba87abb7c..7cd64ca9f 100644 --- a/kdc/windc.c +++ b/kdc/windc.c @@ -111,7 +111,7 @@ _kdc_check_access(krb5_context context, hdb_entry_ex *client_ex, const char *client_name, hdb_entry_ex *server_ex, const char *server_name, KDC_REQ *req, - krb5_data *e_data) + METHOD_DATA *method_data) { if (windcft == NULL) return kdc_check_flags(context, config, @@ -119,9 +119,9 @@ _kdc_check_access(krb5_context context, server_ex, server_name, req->msg_type == krb_as_req); - return (windcft->client_access)(windcctx, - context, config, - client_ex, client_name, - server_ex, server_name, - req, e_data); + return (windcft->client_access)(windcctx, + context, config, + client_ex, client_name, + server_ex, server_name, + req, method_data); } From a4a42a4bd3b4b4c1036933c609a7aefc1b42fc31 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Tue, 19 Jan 2010 17:10:03 +0000 Subject: [PATCH 027/119] Only ticket checksum in FastFinished --- lib/asn1/krb5.asn1 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/asn1/krb5.asn1 b/lib/asn1/krb5.asn1 index 155d3c5be..31a4c767d 100644 --- a/lib/asn1/krb5.asn1 +++ b/lib/asn1/krb5.asn1 @@ -803,8 +803,7 @@ KrbFastFinished ::= SEQUENCE { usec [1] krb5int32, crealm [2] Realm, cname [3] PrincipalName, - checksum [4] Checksum, - ticket-checksum [5] Checksum, + ticket-checksum [4] Checksum, ... } From bcbcc67ab76c349f524ce23d136e34b74a1196f7 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Tue, 19 Jan 2010 17:21:23 +0000 Subject: [PATCH 028/119] try handle finished message, ticket processing missing --- kdc/kerberos5.c | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index a2a375a59..dcdf5c4e1 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -985,6 +985,8 @@ _kdc_as_rep(krb5_context context, krb5_crypto armor_crypto = NULL; memset(&rep, 0, sizeof(rep)); + memset(&et, 0, sizeof(et)); + memset(&ek, 0, sizeof(ek)); memset(&session_key, 0, sizeof(session_key)); error_method.len = 0; error_method.val = NULL; @@ -2023,19 +2025,48 @@ _kdc_as_rep(krb5_context context, memset(&finished, 0, sizeof(finished)); + finished.timestamp = kdc_time; + finished.usec = 0; + finished.crealm = client_princ->realm; + finished.cname = client_princ->name; + + krb5_data_zero(&data); + + ret = krb5_create_checksum(context, armor_crypto, + KRB5_KU_FAST_FINISHED, 0, + data.data, data.length, + &finished.ticket_checksum); + if (ret) + goto out; + ret = _kdc_fast_mk_response(context, armor_crypto, rep.padata, strengthen_key, &finished, req->req_body.nonce, &data); + free_Checksum(&finished.ticket_checksum); if (ret) - goto out2; + goto out; + + if (rep.padata) { + free_METHOD_DATA(rep.padata); + } else { + rep.padata = calloc(1, sizeof(*rep.padata)); + if (rep.padata == NULL) { + ret = ENOMEM; + goto out; + } + } + + ret = krb5_padata_add(context, rep.padata, + KRB5_PADATA_FX_FAST, + data.data, data.length); + if (ret) + goto out; } ret = _kdc_encode_reply(context, config, &rep, &et, &ek, setype, server->entry.kvno, &skey->key, client->entry.kvno, reply_key, 0, &e_text, reply); - free_EncTicketPart(&et); - free_EncKDCRepPart(&ek); if (ret) goto out; @@ -2134,6 +2165,9 @@ out2: if (pkp) _kdc_pk_free_client_param(context, pkp); #endif + free_EncTicketPart(&et); + free_EncKDCRepPart(&ek); + if (error_method.len) free_METHOD_DATA(&error_method); if (client_princ) From deed0642d0907687de270f1ae39eeef5906b36c8 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Tue, 19 Jan 2010 17:37:17 +0000 Subject: [PATCH 029/119] Handle ticket checksum --- kdc/kerberos5.c | 101 ++++++++++++++++++++++++++---------------------- 1 file changed, 54 insertions(+), 47 deletions(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index dcdf5c4e1..919fca238 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -321,6 +321,7 @@ log_patypes(krb5_context context, krb5_error_code _kdc_encode_reply(krb5_context context, krb5_kdc_configuration *config, + krb5_crypto armor_crypto, uint32_t nonce, KDC_REP *rep, const EncTicketPart *et, EncKDCRepPart *ek, krb5_enctype etype, int skvno, const EncryptionKey *skey, @@ -375,6 +376,58 @@ _kdc_encode_reply(krb5_context context, return ret; } + if (armor_crypto) { + krb5_data data; + krb5_keyblock *strengthen_key = NULL; + KrbFastFinished finished; + + memset(&finished, 0, sizeof(finished)); + krb5_data_zero(&data); + + finished.timestamp = kdc_time; + finished.usec = 0; + finished.crealm = et->crealm; + finished.cname = et->cname; + + ASN1_MALLOC_ENCODE(Ticket, data.data, data.length, + &rep->ticket, &len, ret); + if (ret) + return ret; + if (data.length != len) + krb5_abortx(context, "internal asn.1 error"); + + ret = krb5_create_checksum(context, armor_crypto, + KRB5_KU_FAST_FINISHED, 0, + data.data, data.length, + &finished.ticket_checksum); + krb5_data_free(&data); + if (ret) + return ret; + + ret = _kdc_fast_mk_response(context, armor_crypto, + rep->padata, strengthen_key, &finished, + nonce, &data); + free_Checksum(&finished.ticket_checksum); + if (ret) + return ret; + + if (rep->padata) { + free_METHOD_DATA(rep->padata); + } else { + rep->padata = calloc(1, sizeof(*(rep->padata))); + if (rep->padata == NULL) { + krb5_data_free(&data); + return ENOMEM; + } + } + + ret = krb5_padata_add(context, rep->padata, + KRB5_PADATA_FX_FAST, + data.data, data.length); + if (ret) + return ret; + } + if(rep->msg_type == krb_as_rep && !config->encode_as_rep_as_tgs_rep) ASN1_MALLOC_ENCODE(EncASRepPart, buf, buf_size, ek, &len, ret); else @@ -2017,53 +2070,7 @@ _kdc_as_rep(krb5_context context, log_as_req(context, config, reply_key->keytype, setype, b); - /* XXX handle fast reply */ - if (armor_crypto) { - krb5_data data; - krb5_keyblock *strengthen_key = NULL; - KrbFastFinished finished; - - memset(&finished, 0, sizeof(finished)); - - finished.timestamp = kdc_time; - finished.usec = 0; - finished.crealm = client_princ->realm; - finished.cname = client_princ->name; - - krb5_data_zero(&data); - - ret = krb5_create_checksum(context, armor_crypto, - KRB5_KU_FAST_FINISHED, 0, - data.data, data.length, - &finished.ticket_checksum); - if (ret) - goto out; - - ret = _kdc_fast_mk_response(context, armor_crypto, - rep.padata, strengthen_key, &finished, - req->req_body.nonce, &data); - free_Checksum(&finished.ticket_checksum); - if (ret) - goto out; - - if (rep.padata) { - free_METHOD_DATA(rep.padata); - } else { - rep.padata = calloc(1, sizeof(*rep.padata)); - if (rep.padata == NULL) { - ret = ENOMEM; - goto out; - } - } - - ret = krb5_padata_add(context, rep.padata, - KRB5_PADATA_FX_FAST, - data.data, data.length); - if (ret) - goto out; - } - - ret = _kdc_encode_reply(context, config, + ret = _kdc_encode_reply(context, config, armor_crypto, req->req_body.nonce, &rep, &et, &ek, setype, server->entry.kvno, &skey->key, client->entry.kvno, reply_key, 0, &e_text, reply); From 91fce795afdaf04a4e7d42a7e8d96cf38ce613ee Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Tue, 19 Jan 2010 21:20:20 +0000 Subject: [PATCH 030/119] add more key usage for fast --- lib/krb5/krb5.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/krb5/krb5.h b/lib/krb5/krb5.h index 6d63cd26c..0e88101e3 100644 --- a/lib/krb5/krb5.h +++ b/lib/krb5/krb5.h @@ -278,6 +278,10 @@ typedef enum krb5_key_usage { /* FAST armor checksum */ KRB5_KU_FAST_ENC = 51, /* FAST armor encryption */ + KRB5_KU_FAST_REP = 52, + /* FAST armor reply */ + KRB5_KU_FAST_FINISHED = 53, + /* FAST finished checksum */ KRB5_KU_DIGEST_ENCRYPT = -18, /* Encryption key usage used in the digest encryption field */ KRB5_KU_DIGEST_OPAQUE = -19, From 78bef36409efb50f0fdc7112d0e28806c32c7470 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Tue, 19 Jan 2010 21:20:33 +0000 Subject: [PATCH 031/119] include fast.c --- kdc/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/kdc/Makefile.am b/kdc/Makefile.am index 5ef3cbec5..b794efd0a 100644 --- a/kdc/Makefile.am +++ b/kdc/Makefile.am @@ -37,6 +37,7 @@ libkdc_la_SOURCES = \ default_config.c \ set_dbinfo.c \ digest.c \ + fast.c \ kdc_locl.h \ kerberos5.c \ krb5tgs.c \ From 30cca73765315e348ffd194fac2d638ab48e8a13 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Tue, 19 Jan 2010 21:21:06 +0000 Subject: [PATCH 032/119] more fast bits --- kdc/krb5tgs.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kdc/krb5tgs.c b/kdc/krb5tgs.c index b0d545508..0a96bc914 100644 --- a/kdc/krb5tgs.c +++ b/kdc/krb5tgs.c @@ -987,7 +987,7 @@ tgs_make_reply(krb5_context context, CAST session key. Should the DES3 etype be added to the etype list, even if we don't want a session key with DES3? */ - ret = _kdc_encode_reply(context, config, + ret = _kdc_encode_reply(context, config, NULL, 0, &rep, &et, &ek, et.key.keytype, kvno, serverkey, 0, replykey, rk_is_subkey, @@ -2347,7 +2347,10 @@ _kdc_tgs_rep(krb5_context context, out: if (replykey) krb5_free_keyblock(context, replykey); + if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){ + /* XXX add fast wrapping on the error */ + krb5_mk_error(context, ret, NULL, From 1fac725de488ec206f2bc26d317d5f8435da11b7 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Tue, 19 Jan 2010 22:04:20 +0000 Subject: [PATCH 033/119] send cookie on error and send right error message --- kdc/kerberos5.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 919fca238..631058367 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -2116,26 +2116,25 @@ out: if (ret) goto out2; - if (/* hide_principal */ 0) { - error_client = NULL; - error_server = NULL; - e_text = NULL; - ret = KRB5KDC_ERR_PREAUTH_REQUIRED; - } - ret = krb5_padata_add(context, &error_method, - KRB5_PADATA_FX_FAST, + KRB5_PADATA_FX_ERROR, e_data.data, e_data.length); if (ret) { krb5_data_free(&e_data); goto out2; } - krb5_data_zero(&e_data); + + if (/* hide_principal */ 0) { + error_client = NULL; + error_server = NULL; + e_text = NULL; + } ret = _kdc_fast_mk_response(context, armor_crypto, &error_method, NULL, NULL, req->req_body.nonce, &e_data); free_METHOD_DATA(&error_method); + krb5_data_free(&e_data); if (ret) goto out2; @@ -2145,6 +2144,12 @@ out: krb5_data_zero(&e_data); if (ret) goto out2; + + ret = krb5_padata_add(context, &error_method, + KRB5_PADATA_FX_COOKIE, + NULL, 0); + if (ret) + goto out2; } if (error_method.len) { From 7d1a059f9eb28f39e98c09e9ac6a1f5a86ff5c7c Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Tue, 19 Jan 2010 22:32:09 +0000 Subject: [PATCH 034/119] comment why we add cookie --- kdc/kerberos5.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 631058367..6e80145de 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -2145,6 +2145,10 @@ out: if (ret) goto out2; + /* + * Set cookie to let client know we want conversation to + * continue. + */ ret = krb5_padata_add(context, &error_method, KRB5_PADATA_FX_COOKIE, NULL, 0); From 7151d4e66c07b42c15187becd61fb20e0666458a Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Wed, 20 Jan 2010 01:30:01 +0000 Subject: [PATCH 035/119] partial handling of ENC-CHALLANGE --- kdc/kerberos5.c | 132 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 120 insertions(+), 12 deletions(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 6e80145de..1d790715e 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -1388,23 +1388,130 @@ _kdc_as_rep(krb5_context context, log_patypes(context, config, req->padata); + kdc_log(context, config, 5, + "Looking for ENCRYPTED-CHALLANGE pa-data -- %s", client_name); + + e_text = "No FAST ENCRYPTED CHALLANGE found"; + + i = 0; + pa = _kdc_find_padata(req, &i, KRB5_PADATA_ENCRYPTED_CHALLENGE); + if (pa && armor_crypto) { + krb5_data ts_data; + struct Key *k; + size_t size; + + if (b->kdc_options.request_anonymous) { + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + kdc_log(context, config, 0, "ENC-CHALL doesn't support anon"); + goto out; + } + + EncryptedData enc_data; + + ret = decode_EncryptedData(pa->padata_value.data, + pa->padata_value.length, + &enc_data, + &size); + if (ret) { + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + kdc_log(context, config, 5, "Failed to decode PA-DATA -- %s", + client_name); + goto out; + } + + krb5_data pepper1, pepper2; + + pepper1.data = "clientchallengearmor"; + pepper1.length = strlen(pepper1.data); + pepper2.data = "challengelongterm"; + pepper2.length = strlen(pepper2.data); + + krb5_enctype aenctype; + krb5_crypto_getenctype(context, armor_crypto, &aenctype); + + for (i = 0; i < client->entry.keys.len; i++) { + krb5_crypto challangecrypto, longtermcrypto; + krb5_keyblock challangekey; + PA_ENC_TS_ENC p; + + k = &client->entry.keys.val[i]; + + ret = krb5_crypto_init(context, &k->key, 0, &longtermcrypto); + if (ret) + continue; + + ret = krb5_crypto_fx_cf2(context, armor_crypto, longtermcrypto, + &pepper1, &pepper2, aenctype, + &challangekey); + krb5_crypto_destroy(context, longtermcrypto); + if (ret) + continue; + + ret = krb5_crypto_init(context, &challangekey, 0, + &challangecrypto); + if (ret) + continue; + + ret = krb5_decrypt_EncryptedData(context, challangecrypto, + KRB5_KU_ENC_CHALLENGE_CLIENT, + &enc_data, + &ts_data); + krb5_crypto_destroy(context, challangecrypto); + if (ret) + continue; + + ret = decode_PA_ENC_TS_ENC(ts_data.data, + ts_data.length, + &p, + &size); + krb5_data_free(&ts_data); + if(ret){ + e_text = "Failed to decode PA-ENC-TS-ENC"; + ret = KRB5KDC_ERR_PREAUTH_FAILED; + kdc_log(context, config, + 5, "Failed to decode PA-ENC-TS_ENC -- %s", + client_name); + continue; + } + + if (abs(kdc_time - p.patimestamp) > context->max_skew) { + char client_time[100]; + + krb5_format_time(context, p.patimestamp, + client_time, sizeof(client_time), TRUE); + + ret = KRB5KRB_AP_ERR_SKEW; + kdc_log(context, config, 0, + "Too large time skew, " + "client time %s is out by %u > %u seconds -- %s", + client_time, + (unsigned)abs(kdc_time - p.patimestamp), + context->max_skew, + client_name); + + free_PA_ENC_TS_ENC(&p); + goto out; + } + + free_PA_ENC_TS_ENC(&p); + et.flags.pre_authent = 1; + + /* XXX add kdc reply */ + + set_salt_padata(rep.padata, k->salt); + reply_key = &k->key; + + goto preauth_done; + } + free_EncryptedData(&enc_data); + } + #ifdef PKINIT kdc_log(context, config, 5, "Looking for PKINIT pa-data -- %s", client_name); e_text = "No PKINIT PA found"; - i = 0; - pa = _kdc_find_padata(req, &i, KRB5_PADATA_ENCRYPTED_CHALLENGE); - if (pa && armor_crypto) { - /* XXX handle encrypted challange */ - - if (1) - goto pkinit; - - } - - pkinit: i = 0; pa = _kdc_find_padata(req, &i, KRB5_PADATA_PK_AS_REQ); if (pa == NULL) { @@ -1569,7 +1676,6 @@ _kdc_as_rep(krb5_context context, client_name); continue; } - free_PA_ENC_TS_ENC(&p); if (abs(kdc_time - p.patimestamp) > context->max_skew) { char client_time[100]; @@ -1591,8 +1697,10 @@ _kdc_as_rep(krb5_context context, * there is a e_text, they become unhappy. */ e_text = NULL; + free_PA_ENC_TS_ENC(&p); goto out; } + free_PA_ENC_TS_ENC(&p); et.flags.pre_authent = 1; set_salt_padata(rep.padata, pa_key->salt); From 8eb256ea004ed94b3f7913cd3a9c683a3167e918 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Wed, 20 Jan 2010 08:34:08 +0000 Subject: [PATCH 036/119] send enc challange in KDC reply --- kdc/kerberos5.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 1d790715e..e2c97135f 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -1001,6 +1001,54 @@ _kdc_is_anonymous(krb5_context context, krb5_principal principal) return 1; } +static krb5_error_code +make_pa_enc_challange(krb5_context context, METHOD_DATA *md, + krb5_crypto crypto) +{ + PA_ENC_TS_ENC p; + unsigned char *buf; + size_t buf_size; + size_t len; + EncryptedData encdata; + krb5_error_code ret; + int32_t usec; + int usec2; + + krb5_us_timeofday (context, &p.patimestamp, &usec); + usec2 = usec; + p.pausec = &usec2; + + ASN1_MALLOC_ENCODE(PA_ENC_TS_ENC, buf, buf_size, &p, &len, ret); + if (ret) + return ret; + if(buf_size != len) + krb5_abortx(context, "internal error in ASN.1 encoder"); + + ret = krb5_encrypt_EncryptedData(context, + crypto, + KRB5_KU_ENC_CHALLENGE_KDC, + buf, + len, + 0, + &encdata); + free(buf); + if (ret) + return ret; + + ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_size, &encdata, &len, ret); + free_EncryptedData(&encdata); + if (ret) + return ret; + if(buf_size != len) + krb5_abortx(context, "internal error in ASN.1 encoder"); + + ret = krb5_padata_add(context, md, KRB5_PADATA_ENCRYPTED_CHALLENGE, buf, len); + if (ret) + free(buf); + return ret; +} + + /* * */ @@ -1496,8 +1544,11 @@ _kdc_as_rep(krb5_context context, free_PA_ENC_TS_ENC(&p); et.flags.pre_authent = 1; - /* XXX add kdc reply */ - + ret = make_pa_enc_challange(context, rep.padata, + challangecrypto); + if (ret) + goto out; + set_salt_padata(rep.padata, k->salt); reply_key = &k->key; From 7bc5fe72fb3c91b134902b23f9fe8de175a596cb Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Wed, 20 Jan 2010 17:58:51 +0000 Subject: [PATCH 037/119] more keyusage --- lib/krb5/krb5.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/krb5/krb5.h b/lib/krb5/krb5.h index 0e88101e3..f0f08a8d4 100644 --- a/lib/krb5/krb5.h +++ b/lib/krb5/krb5.h @@ -282,6 +282,10 @@ typedef enum krb5_key_usage { /* FAST armor reply */ KRB5_KU_FAST_FINISHED = 53, /* FAST finished checksum */ + KRB5_KU_ENC_CHALLENGE_CLIENT = 54, + /* fast challange from client */ + KRB5_KU_ENC_CHALLENGE_KDC = 55, + /* fast challange from kdc */ KRB5_KU_DIGEST_ENCRYPT = -18, /* Encryption key usage used in the digest encryption field */ KRB5_KU_DIGEST_OPAQUE = -19, From 79703dc3cc1676504d973e5d9104fde01bd64b1a Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Wed, 20 Jan 2010 17:59:08 +0000 Subject: [PATCH 038/119] memory management --- kdc/kerberos5.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index e2c97135f..d988e2ff6 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -1504,7 +1504,6 @@ _kdc_as_rep(krb5_context context, KRB5_KU_ENC_CHALLENGE_CLIENT, &enc_data, &ts_data); - krb5_crypto_destroy(context, challangecrypto); if (ret) continue; @@ -1514,6 +1513,7 @@ _kdc_as_rep(krb5_context context, &size); krb5_data_free(&ts_data); if(ret){ + krb5_crypto_destroy(context, challangecrypto); e_text = "Failed to decode PA-ENC-TS-ENC"; ret = KRB5KDC_ERR_PREAUTH_FAILED; kdc_log(context, config, @@ -1525,6 +1525,8 @@ _kdc_as_rep(krb5_context context, if (abs(kdc_time - p.patimestamp) > context->max_skew) { char client_time[100]; + krb5_crypto_destroy(context, challangecrypto); + krb5_format_time(context, p.patimestamp, client_time, sizeof(client_time), TRUE); @@ -1546,6 +1548,7 @@ _kdc_as_rep(krb5_context context, ret = make_pa_enc_challange(context, rep.padata, challangecrypto); + krb5_crypto_destroy(context, challangecrypto); if (ret) goto out; From 4561012998a56e70fa96e45a166e6dd30161083e Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Sat, 7 May 2011 07:03:40 -0700 Subject: [PATCH 039/119] fix up to update kdc_db_fetch --- kdc/kerberos5.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index d988e2ff6..3b4bb780e 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -1173,8 +1173,13 @@ _kdc_as_rep(krb5_context context, } ret = _kdc_db_fetch(context, config, armor_server, - HDB_F_GET_SERVER, NULL, &armor_user); - if(ret){ + HDB_F_GET_SERVER, NULL, NULL, &armor_user); + if(ret == HDB_ERR_NOT_FOUND_HERE) { + kdc_log(context, config, 5, + "armor key does not have secrets at this KDC, " + "need to proxy"); + goto out; + } if(ret){ free_AP_REQ(&ap_req); ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; goto out; From 04983dfd94bb5c8c8d9a0a04613303b50de45e6b Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Sun, 8 May 2011 14:15:37 -0700 Subject: [PATCH 040/119] Preserve outer error --- kdc/kerberos5.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 3b4bb780e..ab127565b 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -1178,6 +1178,7 @@ _kdc_as_rep(krb5_context context, kdc_log(context, 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); @@ -1824,12 +1825,10 @@ _kdc_as_rep(krb5_context context, /* * Announce FX-FAST */ - ret = realloc_method_data(&error_method); + ret = krb5_padata_add(context, &error_method, + KRB5_PADATA_FX_FAST, NULL, 0); if (ret) goto out; - pa = &error_method.val[error_method.len-1]; - pa->padata_type = KRB5_PADATA_FX_FAST; - pa->padata_value.length = 0; /* * If there is a client key, send ETYPE_INFO{,2} @@ -2255,6 +2254,7 @@ out: free_AS_REP(&rep); if(ret != 0 && ret != HDB_ERR_NOT_FOUND_HERE){ + krb5_error_code outer_error = ret; krb5_data e_data; krb5_principal error_client = client_princ; krb5_principal error_server = server_princ; @@ -2272,7 +2272,7 @@ out: /* first add the KRB-ERROR to the fast errors */ ret = krb5_mk_error(context, - ret, + outer_error, e_text, NULL, error_client, @@ -2281,7 +2281,7 @@ out: NULL, &e_data); if (ret) - goto out2; + goto out; ret = krb5_padata_add(context, &error_method, KRB5_PADATA_FX_ERROR, @@ -2333,7 +2333,7 @@ out: } ret = krb5_mk_error(context, - ret, + outer_error, e_text, (e_data.length ? &e_data : NULL), error_client, From 4f3d3723f4e8efcc70ef67db819cd9ac15008626 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Sun, 8 May 2011 14:40:08 -0700 Subject: [PATCH 041/119] fail if kinit failes --- tests/kdc/check-kdc.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/kdc/check-kdc.in b/tests/kdc/check-kdc.in index 05f7689d2..09d13dd3e 100644 --- a/tests/kdc/check-kdc.in +++ b/tests/kdc/check-kdc.in @@ -292,7 +292,7 @@ ${klist} | grep "Principal: ${server}" > /dev/null || \ ${kdestroy} echo "Getting key for key that are a subset in keytab compared to kdb" -${kinit} --keytab=${keytab} kt-des3@${R} +${kinit} --keytab=${keytab} kt-des3@${R} || { ec=1; eval "${testfailed}"; } ${klist} | grep "Principal: kt-des3" > /dev/null || \ { ec=1 ; eval "${testfailed}"; } ${kdestroy} From 16d16588d2ce26455984e448a0b10b69dc09a757 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Sun, 8 May 2011 15:56:20 -0700 Subject: [PATCH 042/119] move back init_as_req when building packet --- lib/krb5/init_creds_pw.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/krb5/init_creds_pw.c b/lib/krb5/init_creds_pw.c index dc4d9d0f3..f34fc30cf 100644 --- a/lib/krb5/init_creds_pw.c +++ b/lib/krb5/init_creds_pw.c @@ -1385,13 +1385,6 @@ krb5_init_creds_init(krb5_context context, ctx->prompter = prompter; ctx->prompter_data = prompter_data; - ret = init_as_req(context, ctx->flags, &ctx->cred, - ctx->addrs, ctx->etypes, &ctx->as_req); - if (ret) { - free_init_creds_ctx(context, ctx); - return ret; - } - *rctx = ctx; return ret; @@ -1668,6 +1661,15 @@ krb5_init_creds_step(krb5_context context, krb5_data_zero(out); + if (ctx->as_req.req_body.cname == NULL) { + ret = init_as_req(context, ctx->flags, &ctx->cred, + ctx->addrs, ctx->etypes, &ctx->as_req); + if (ret) { + free_init_creds_ctx(context, ctx); + return ret; + } + } + #define MAX_PA_COUNTER 10 if (ctx->pa_counter > MAX_PA_COUNTER) { krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP, From a2bcf8bbdd8ac75dfeed07141a80cf8777b7cd0e Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Sun, 8 May 2011 20:43:16 -0700 Subject: [PATCH 043/119] break out mk_error --- kdc/fast.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++ kdc/kerberos5.c | 102 +++++++----------------------------------------- kdc/krb5tgs.c | 22 ++++++----- 3 files changed, 128 insertions(+), 98 deletions(-) diff --git a/kdc/fast.c b/kdc/fast.c index dff78d0a3..2a41c72ee 100644 --- a/kdc/fast.c +++ b/kdc/fast.c @@ -92,3 +92,105 @@ _kdc_fast_mk_response(krb5_context context, return 0; } + + +krb5_error_code +_kdc_fast_mk_error(krb5_context context, + METHOD_DATA *error_method, + krb5_crypto armor_crypto, + const KDC_REQ_BODY *req_body, + krb5_error_code outer_error, + const char *e_text, + krb5_principal error_client, + krb5_principal error_server, + time_t *csec, int *cusec, + krb5_data *error_msg) +{ + krb5_error_code ret; + krb5_data e_data; + size_t size; + + krb5_data_zero(&e_data); + + if (armor_crypto) { + PA_FX_FAST_REPLY fxfastrep; + KrbFastResponse fastrep; + + memset(&fxfastrep, 0, sizeof(fxfastrep)); + memset(&fastrep, 0, sizeof(fastrep)); + + /* first add the KRB-ERROR to the fast errors */ + + ret = krb5_mk_error(context, + outer_error, + e_text, + NULL, + error_client, + error_server, + NULL, + NULL, + &e_data); + if (ret) + return ret; + + ret = krb5_padata_add(context, error_method, + KRB5_PADATA_FX_ERROR, + e_data.data, e_data.length); + if (ret) { + krb5_data_free(&e_data); + return ret; + } + + if (/* hide_principal */ 0) { + error_client = NULL; + error_server = NULL; + e_text = NULL; + } + + ret = _kdc_fast_mk_response(context, armor_crypto, + error_method, NULL, NULL, + req_body->nonce, &e_data); + free_METHOD_DATA(error_method); + if (ret) + return ret; + + ret = krb5_padata_add(context, error_method, + KRB5_PADATA_FX_FAST, + e_data.data, e_data.length); + krb5_data_zero(&e_data); + if (ret) + return ret; + + /* + * Set cookie to let client know we want conversation to + * continue. + */ + ret = krb5_padata_add(context, error_method, + KRB5_PADATA_FX_COOKIE, + NULL, 0); + if (ret) + return ret; + } + + if (error_method && error_method->len) { + ASN1_MALLOC_ENCODE(METHOD_DATA, e_data.data, e_data.length, + error_method, &size, ret); + if (ret) + return ret; + if (e_data.length != size) + krb5_abortx(context, "internal asn.1 error"); + } + + ret = krb5_mk_error(context, + outer_error, + e_text, + (e_data.length ? &e_data : NULL), + error_client, + error_server, + csec, + cusec, + error_msg); + krb5_data_free(&e_data); + + return ret; +} diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index ab127565b..7971a2a11 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -2253,95 +2253,21 @@ _kdc_as_rep(krb5_context context, out: free_AS_REP(&rep); + /* + * In case of a non proxy error, build an error message. + */ if(ret != 0 && ret != HDB_ERR_NOT_FOUND_HERE){ - krb5_error_code outer_error = ret; - krb5_data e_data; - krb5_principal error_client = client_princ; - krb5_principal error_server = server_princ; - size_t size; - - krb5_data_zero(&e_data); - - if (armor_crypto) { - PA_FX_FAST_REPLY fxfastrep; - KrbFastResponse fastrep; - - memset(&fxfastrep, 0, sizeof(fxfastrep)); - memset(&fastrep, 0, sizeof(fastrep)); - - /* first add the KRB-ERROR to the fast errors */ - - ret = krb5_mk_error(context, - outer_error, - e_text, - NULL, - error_client, - error_server, - NULL, - NULL, - &e_data); - if (ret) - goto out; - - ret = krb5_padata_add(context, &error_method, - KRB5_PADATA_FX_ERROR, - e_data.data, e_data.length); - if (ret) { - krb5_data_free(&e_data); - goto out2; - } - - if (/* hide_principal */ 0) { - error_client = NULL; - error_server = NULL; - e_text = NULL; - } - - ret = _kdc_fast_mk_response(context, armor_crypto, - &error_method, NULL, NULL, - req->req_body.nonce, &e_data); - free_METHOD_DATA(&error_method); - krb5_data_free(&e_data); - if (ret) - goto out2; - - ret = krb5_padata_add(context, &error_method, - KRB5_PADATA_FX_FAST, - e_data.data, e_data.length); - krb5_data_zero(&e_data); - if (ret) - goto out2; - - /* - * Set cookie to let client know we want conversation to - * continue. - */ - ret = krb5_padata_add(context, &error_method, - KRB5_PADATA_FX_COOKIE, - NULL, 0); - if (ret) - goto out2; - } - - if (error_method.len) { - ASN1_MALLOC_ENCODE(METHOD_DATA, e_data.data, e_data.length, - &error_method, &size, ret); - if (ret) - goto out2; - if (e_data.length != size) - krb5_abortx(context, "internal asn.1 error"); - } - - ret = krb5_mk_error(context, - outer_error, - e_text, - (e_data.length ? &e_data : NULL), - error_client, - error_server, - NULL, - NULL, - reply); - krb5_data_free(&e_data); + kdc_log(context, config, 10, "as-req: sending error: %d to client", ret); + ret = _kdc_fast_mk_error(context, + &error_method, + armor_crypto, + &req->req_body, + ret, e_text, + client_princ, server_princ, + NULL, NULL, + reply); + if (ret) + goto out2; } out2: #ifdef PKINIT diff --git a/kdc/krb5tgs.c b/kdc/krb5tgs.c index 0a96bc914..f513dfbff 100644 --- a/kdc/krb5tgs.c +++ b/kdc/krb5tgs.c @@ -2350,17 +2350,19 @@ out: if(ret && ret != HDB_ERR_NOT_FOUND_HERE && data->data == NULL){ /* XXX add fast wrapping on the error */ + METHOD_DATA error_method = { 0, NULL }; + - krb5_mk_error(context, - ret, - NULL, - NULL, - NULL, - NULL, - csec, - cusec, - data); - ret = 0; + kdc_log(context, config, 10, "tgs-req: sending error: %d to client", ret); + ret = _kdc_fast_mk_error(context, + &error_method, + NULL, + NULL, + ret, NULL, + NULL, NULL, + csec, cusec, + data); + free_METHOD_DATA(&error_method); } free(csec); free(cusec); From 6c31f5a95fc303c9d20dfbd0e08d231b3fb6acae Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Sun, 8 May 2011 21:44:31 -0700 Subject: [PATCH 044/119] free ac after its used --- kdc/kerberos5.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 7971a2a11..e859a9867 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -1216,8 +1216,8 @@ _kdc_as_rep(krb5_context context, ret = krb5_crypto_init(context, ac->remote_subkey, 0, &crypto_subkey); - krb5_auth_con_free(context, ac); if (ret) { + krb5_auth_con_free(context, ac); krb5_free_ticket(context, ticket); goto out; } @@ -1225,6 +1225,7 @@ _kdc_as_rep(krb5_context context, 0, &crypto_session); krb5_free_ticket(context, ticket); if (ret) { + krb5_auth_con_free(context, ac); krb5_crypto_destroy(context, crypto_subkey); goto out; } @@ -1240,11 +1241,13 @@ _kdc_as_rep(krb5_context context, &armorkey); krb5_crypto_destroy(context, crypto_subkey); krb5_crypto_destroy(context, crypto_session); - + krb5_auth_con_free(context, ac); if (ret) goto out; - krb5_crypto_init(context, &armorkey, 0, &armor_crypto); + ret = krb5_crypto_init(context, &armorkey, 0, &armor_crypto); + if (ret) + goto out; krb5_free_keyblock_contents(context, &armorkey); /* verify req-checksum of the outer body */ From 17d5f8d19e8ba3e638a0136dc7bcb7a62f659791 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Mon, 9 May 2011 20:46:31 -0700 Subject: [PATCH 045/119] make AS work with FAST --- kdc/fast.c | 14 +- kdc/kerberos5.c | 617 ++++++++++++++++++++++------------------ kdc/krb5tgs.c | 2 +- tests/kdc/Makefile.am | 6 + tests/kdc/check-fast.in | 150 ++++++++++ 5 files changed, 500 insertions(+), 289 deletions(-) create mode 100644 tests/kdc/check-fast.in diff --git a/kdc/fast.c b/kdc/fast.c index 2a41c72ee..b0089d36d 100644 --- a/kdc/fast.c +++ b/kdc/fast.c @@ -147,6 +147,12 @@ _kdc_fast_mk_error(krb5_context context, e_text = NULL; } + ret = krb5_padata_add(context, error_method, + KRB5_PADATA_FX_COOKIE, + NULL, 0); + if (ret) + return ret; + ret = _kdc_fast_mk_response(context, armor_crypto, error_method, NULL, NULL, req_body->nonce, &e_data); @@ -157,17 +163,9 @@ _kdc_fast_mk_error(krb5_context context, ret = krb5_padata_add(context, error_method, KRB5_PADATA_FX_FAST, e_data.data, e_data.length); - krb5_data_zero(&e_data); if (ret) return ret; - /* - * Set cookie to let client know we want conversation to - * continue. - */ - ret = krb5_padata_add(context, error_method, - KRB5_PADATA_FX_COOKIE, - NULL, 0); if (ret) return ret; } diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index e859a9867..1ff6714d9 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -271,6 +271,30 @@ _kdc_log_timestamp(krb5_context context, type, authtime_str, starttime_str, endtime_str, renewtime_str); } +struct kdc_patypes { + int type; + char *name; + unsigned int flags; +#define PA_ANNOUNCE 1 +#ifdef PKINIT +#define PA_ANNOUNCE_PKINIT PA_ANNOUNCE +#else +#define PA_ANNOUNCE_PKINIT 0 +#endif +}; + +static const struct kdc_patypes pat[] = { + { KRB5_PADATA_PK_AS_REQ, "PK-INIT(ietf)", PA_ANNOUNCE_PKINIT }, + { KRB5_PADATA_PK_AS_REQ_WIN, "PK-INIT(win2k)", PA_ANNOUNCE_PKINIT }, + { KRB5_PADATA_PA_PK_OCSP_RESPONSE , "OCSP", 0 }, + { KRB5_PADATA_ENC_TIMESTAMP , "ENC-TS", PA_ANNOUNCE }, + { KRB5_PADATA_ENCRYPTED_CHALLENGE , "ENC-CHAL", PA_ANNOUNCE }, + { KRB5_PADATA_REQ_ENC_PA_REP , "REQ-ENC-PA-REP", 0 }, + { KRB5_PADATA_FX_FAST, "FX-FAST", PA_ANNOUNCE }, + { KRB5_PADATA_FX_ERROR, "FX-ERROR", 0 }, + { KRB5_PADATA_FX_COOKIE, "FX-COOKIE", 0 } +}; + static void log_patypes(krb5_context context, krb5_kdc_configuration *config, @@ -278,27 +302,18 @@ log_patypes(krb5_context context, { struct rk_strpool *p = NULL; char *str; - size_t i; - - for (i = 0; i < padata->len; i++) { - switch(padata->val[i].padata_type) { - case KRB5_PADATA_PK_AS_REQ: - p = rk_strpoolprintf(p, "PK-INIT(ietf)"); - break; - case KRB5_PADATA_PK_AS_REQ_WIN: - p = rk_strpoolprintf(p, "PK-INIT(win2k)"); - break; - case KRB5_PADATA_PA_PK_OCSP_RESPONSE: - p = rk_strpoolprintf(p, "OCSP"); - break; - case KRB5_PADATA_ENC_TIMESTAMP: - p = rk_strpoolprintf(p, "encrypted-timestamp"); - break; - default: - p = rk_strpoolprintf(p, "%d", padata->val[i].padata_type); - break; + size_t n, m; + + for (n = 0; n < padata->len; n++) { + for (m = 0; m < sizeof(pat) / sizeof(pat[0]); m++) { + if (padata->val[n].padata_type == pat[m].type) { + p = rk_strpoolprintf(p, "%s", pat[m].name); + break; + } } - if (p && i + 1 < padata->len) + if (m == sizeof(pat) / sizeof(pat[0])) + p = rk_strpoolprintf(p, "%d", padata->val[n].padata_type); + if (p && n + 1 < padata->len) p = rk_strpoolprintf(p, ", "); if (p == NULL) { kdc_log(context, config, 0, "out of memory"); @@ -321,8 +336,9 @@ log_patypes(krb5_context context, krb5_error_code _kdc_encode_reply(krb5_context context, krb5_kdc_configuration *config, + const krb5_data *req_buffer, krb5_crypto armor_crypto, uint32_t nonce, - KDC_REP *rep, const EncTicketPart *et, EncKDCRepPart *ek, + KDC_REP *rep, EncTicketPart *et, EncKDCRepPart *ek, krb5_enctype etype, int skvno, const EncryptionKey *skey, int ckvno, const EncryptionKey *reply_key, @@ -336,25 +352,62 @@ _kdc_encode_reply(krb5_context context, krb5_error_code ret; krb5_crypto crypto; + if (rep->msg_type == krb_as_rep && req_buffer) { + Checksum checksum; + krb5_data cdata; + + et->flags.enc_pa_rep = 1; + ek->flags.enc_pa_rep = 1; + + ret = krb5_crypto_init(context, reply_key, 0, &crypto); + if (ret) { + const char *msg = krb5_get_error_message(context, ret); + free(buf); + kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg); + krb5_free_error_message(context, msg); + return ret; + } + + ret = krb5_create_checksum(context, crypto, + KRB5_KU_AS_REQ, 0, + req_buffer->data, req_buffer->length, + &checksum); + krb5_crypto_destroy(context, crypto); + if (ret) { + return ret; + } + ASN1_MALLOC_ENCODE(Checksum, cdata.data, cdata.length, + &checksum, &len, ret); + free_Checksum(&checksum); + if (ret) { + return ret; + } + ek->encrypted_pa_data = calloc(1, sizeof(*ek->encrypted_pa_data)); + ret = krb5_padata_add(context, ek->encrypted_pa_data, + KRB5_PADATA_REQ_ENC_PA_REP, cdata.data, cdata.length); + if (ret) { + return ret; + } + ret = krb5_padata_add(context, ek->encrypted_pa_data, + KRB5_PADATA_FX_FAST, NULL, 0); + if (ret) + return ret; + } + ASN1_MALLOC_ENCODE(EncTicketPart, buf, buf_size, et, &len, ret); if(ret) { const char *msg = krb5_get_error_message(context, ret); kdc_log(context, config, 0, "Failed to encode ticket: %s", msg); krb5_free_error_message(context, msg); + krb5_crypto_destroy(context, crypto); return ret; } - if(buf_size != len) { - free(buf); - kdc_log(context, config, 0, "Internal error in ASN.1 encoder"); - *e_text = "KDC internal error"; - return KRB5KRB_ERR_GENERIC; - } + if(buf_size != len) + krb5_abortx(context, "Internal error in ASN.1 encoder"); ret = krb5_crypto_init(context, skey, etype, &crypto); if (ret) { - const char *msg; - free(buf); - msg = krb5_get_error_message(context, ret); + const char *msg = krb5_get_error_message(context, ret); kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg); krb5_free_error_message(context, msg); return ret; @@ -381,6 +434,8 @@ _kdc_encode_reply(krb5_context context, krb5_keyblock *strengthen_key = NULL; KrbFastFinished finished; + kdc_log(context, config, 0, "FAST armor protection"); + memset(&finished, 0, sizeof(finished)); krb5_data_zero(&data); @@ -1048,6 +1103,234 @@ make_pa_enc_challange(krb5_context context, METHOD_DATA *md, return ret; } +static krb5_error_code +unwrap_fast(krb5_context context, + krb5_kdc_configuration *config, + KDC_REQ *req, + krb5_crypto *armor_crypto) +{ + 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(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(context, 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(context, config, 0, + "AS-REQ armor missing"); + ret = KRB5KDC_ERR_PREAUTH_FAILED; + goto out; + } + + if (fxreq.u.armored_data.armor->armor_type != 1) { + kdc_log(context, config, 0, + "AS-REQ armor type not ap-req"); + ret = KRB5KDC_ERR_PREAUTH_FAILED; + goto out; + } + + ret = krb5_decode_ap_req(context, + &fxreq.u.armored_data.armor->armor_value, + &ap_req); + if(ret) { + kdc_log(context, config, 0, "AP-REQ decode failed"); + goto out; + } + + /* Save that principal that was in the request */ + ret = _krb5_principalname2krb5_principal(context, + &armor_server, + ap_req.ticket.sname, + ap_req.ticket.realm); + if (ret) { + free_AP_REQ(&ap_req); + goto out; + } + + ret = _kdc_db_fetch(context, config, armor_server, + HDB_F_GET_SERVER, NULL, NULL, &armor_user); + if(ret == HDB_ERR_NOT_FOUND_HERE) { + kdc_log(context, 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(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(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(context, ac); + kdc_log(context, config, 0, + "FAST AP-REQ remote subkey missing"); + ret = KRB5KDC_ERR_PREAUTH_FAILED; + goto out; + } + + ret = krb5_crypto_init(context, ac->remote_subkey, + 0, &crypto_subkey); + if (ret) { + krb5_auth_con_free(context, ac); + krb5_free_ticket(context, ticket); + goto out; + } + ret = krb5_crypto_init(context, &ticket->ticket.key, + 0, &crypto_session); + krb5_free_ticket(context, ticket); + if (ret) { + krb5_auth_con_free(context, ac); + krb5_crypto_destroy(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(context, crypto_subkey, crypto_session, + &pepper1, &pepper2, + ac->remote_subkey->keytype, + &armorkey); + krb5_crypto_destroy(context, crypto_subkey); + krb5_crypto_destroy(context, crypto_session); + krb5_auth_con_free(context, ac); + if (ret) + goto out; + + ret = krb5_crypto_init(context, &armorkey, 0, armor_crypto); + if (ret) + goto out; + krb5_free_keyblock_contents(context, &armorkey); + + /* verify req-checksum of the outer body */ + + ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, len, &req->req_body, &size, ret); + if (ret) + goto out; + if (size != len) { + ret = KRB5KDC_ERR_PREAUTH_FAILED; + goto out; + } + + ret = krb5_verify_checksum(context, *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(context, *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(&req->req_body); + ret = copy_KDC_REQ_BODY(&fastreq.req_body, &req->req_body); + if (ret) + goto out; + + /* check for unsupported mandatory options */ + if (FastOptions2int(fastreq.fast_options) & 0xfffc) { + kdc_log(context, 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 */ + free_METHOD_DATA(req->padata); + ret = copy_METHOD_DATA(&fastreq.padata, req->padata); + if (ret) + goto out; + + free_KrbFastReq(&fastreq); + free_PA_FX_FAST_REQUEST(&fxreq); + + out: + if (armor_server) + krb5_free_principal(context, armor_server); + if(armor_user) + _kdc_free_ent(context, armor_user); + + return ret; +} + /* * @@ -1066,7 +1349,7 @@ _kdc_as_rep(krb5_context context, KDC_REQ_BODY *b = NULL; AS_REP rep; KDCOptions f; - hdb_entry_ex *client = NULL, *server = NULL, *armor_user = NULL; + hdb_entry_ex *client = NULL, *server = NULL; HDB *clientdb; krb5_enctype setype, sessionetype; EncTicketPart et; @@ -1099,217 +1382,9 @@ _kdc_as_rep(krb5_context context, /* * Look for FAST armor and unwrap */ - { - const PA_DATA *pa; - int i = 0; - - pa = _kdc_find_padata(req, &i, KRB5_PADATA_FX_FAST); - if (pa != NULL) { - krb5_crypto crypto_subkey = NULL, crypto_session = NULL; - krb5_data pepper1, pepper2; - PA_FX_FAST_REQUEST fxreq; - krb5_principal armor_server; - krb5_auth_context ac = NULL; - krb5_ticket *ticket = NULL; - krb5_flags ap_req_options; - Key *armor_key = NULL; - krb5_keyblock armorkey; - krb5_ap_req ap_req; - unsigned char *buf; - KrbFastReq fastreq; - size_t len, size; - krb5_data data; - - - 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(context, 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(context, config, 0, - "AS-REQ armor missing"); - ret = KRB5KDC_ERR_PREAUTH_FAILED; - goto out; - } - - if (fxreq.u.armored_data.armor->armor_type != 1) { - kdc_log(context, config, 0, - "AS-REQ armor type not ap-req"); - ret = KRB5KDC_ERR_PREAUTH_FAILED; - goto out; - } - - ret = krb5_decode_ap_req(context, - &fxreq.u.armored_data.armor->armor_value, - &ap_req); - if(ret) { - kdc_log(context, config, 0, "AP-REQ decode failed"); - goto out; - } - - /* Save that principal that was in the request */ - ret = _krb5_principalname2krb5_principal(context, - &armor_server, - ap_req.ticket.sname, - ap_req.ticket.realm); - if (ret) { - free_AP_REQ(&ap_req); - goto out; - } - - ret = _kdc_db_fetch(context, config, armor_server, - HDB_F_GET_SERVER, NULL, NULL, &armor_user); - if(ret == HDB_ERR_NOT_FOUND_HERE) { - kdc_log(context, 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(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(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(context, ac); - kdc_log(context, config, 0, - "FAST AP-REQ remote subkey missing"); - ret = KRB5KDC_ERR_PREAUTH_FAILED; - goto out; - } - - ret = krb5_crypto_init(context, ac->remote_subkey, - 0, &crypto_subkey); - if (ret) { - krb5_auth_con_free(context, ac); - krb5_free_ticket(context, ticket); - goto out; - } - ret = krb5_crypto_init(context, &ticket->ticket.key, - 0, &crypto_session); - krb5_free_ticket(context, ticket); - if (ret) { - krb5_auth_con_free(context, ac); - krb5_crypto_destroy(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(context, crypto_subkey, crypto_session, - &pepper1, &pepper2, - ac->remote_subkey->keytype, - &armorkey); - krb5_crypto_destroy(context, crypto_subkey); - krb5_crypto_destroy(context, crypto_session); - krb5_auth_con_free(context, ac); - if (ret) - goto out; - - ret = krb5_crypto_init(context, &armorkey, 0, &armor_crypto); - if (ret) - goto out; - krb5_free_keyblock_contents(context, &armorkey); - - /* verify req-checksum of the outer body */ - - ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, len, &req->req_body, &size, ret); - if (ret) - goto out; - if (size != len) { - ret = KRB5KDC_ERR_PREAUTH_FAILED; - goto out; - } - - ret = krb5_verify_checksum(context, 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(context, 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(&req->req_body); - ret = copy_KDC_REQ_BODY(&fastreq.req_body, &req->req_body); - if (ret) - goto out; - - /* check for unsupported mandatory options */ - if (FastOptions2int(fastreq.fast_options) & 0xfffc) { - kdc_log(context, 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 */ - free_METHOD_DATA(req->padata); - ret = copy_METHOD_DATA(&fastreq.padata, req->padata); - if (ret) - goto out; - - free_KrbFastReq(&fastreq); - free_PA_FX_FAST_REQUEST(&fxreq); - } - } + ret = unwrap_fast(context, config, req, &armor_crypto); + if (ret) + goto out; b = &req->req_body; f = b->kdc_options; @@ -1796,42 +1871,16 @@ _kdc_as_rep(krb5_context context, || b->kdc_options.request_anonymous /* hack to force anon */ || client->entry.flags.require_preauth || server->entry.flags.require_preauth) { - PA_DATA *pa; - + size_t n; use_pa: - - ret = realloc_method_data(&error_method); - if (ret) - goto out; - pa = &error_method.val[error_method.len-1]; - pa->padata_type = KRB5_PADATA_ENC_TIMESTAMP; - pa->padata_value.length = 0; - pa->padata_value.data = NULL; - -#ifdef PKINIT - ret = realloc_method_data(&error_method); - if (ret) - goto out; - pa = &error_method.val[error_method.len-1]; - pa->padata_type = KRB5_PADATA_PK_AS_REQ; - pa->padata_value.length = 0; - pa->padata_value.data = NULL; - - ret = realloc_method_data(&error_method); - if (ret) - goto out; - pa = &error_method.val[error_method.len-1]; - pa->padata_type = KRB5_PADATA_PK_AS_REQ_WIN; - pa->padata_value.length = 0; - pa->padata_value.data = NULL; -#endif - /* - * Announce FX-FAST - */ - ret = krb5_padata_add(context, &error_method, - KRB5_PADATA_FX_FAST, NULL, 0); - if (ret) - goto out; + for (n = 0; n < sizeof(pat) / sizeof(pat[0]); n++) { + if ((pat[n].flags & PA_ANNOUNCE) == 0) + continue; + ret = krb5_padata_add(context, &error_method, + pat[n].type, NULL, 0); + if (ret) + goto out; + } /* * If there is a client key, send ETYPE_INFO{,2} @@ -2239,7 +2288,17 @@ _kdc_as_rep(krb5_context context, log_as_req(context, config, reply_key->keytype, setype, b); - ret = _kdc_encode_reply(context, config, armor_crypto, req->req_body.nonce, + { + PA_DATA *pa; + int i = 0; + + pa = _kdc_find_padata(req, &i, KRB5_PADATA_REQ_ENC_PA_REP); + if (pa == NULL) + req_buffer = NULL; + } + + ret = _kdc_encode_reply(context, config, req_buffer, + armor_crypto, req->req_body.nonce, &rep, &et, &ek, setype, server->entry.kvno, &skey->key, client->entry.kvno, reply_key, 0, &e_text, reply); @@ -2292,8 +2351,6 @@ out2: _kdc_free_ent(context, client); if(server) _kdc_free_ent(context, server); - if(armor_user) - _kdc_free_ent(context, armor_user); if (armor_crypto) krb5_crypto_destroy(context, armor_crypto); return ret; diff --git a/kdc/krb5tgs.c b/kdc/krb5tgs.c index f513dfbff..559e18dfb 100644 --- a/kdc/krb5tgs.c +++ b/kdc/krb5tgs.c @@ -987,7 +987,7 @@ tgs_make_reply(krb5_context context, CAST session key. Should the DES3 etype be added to the etype list, even if we don't want a session key with DES3? */ - ret = _kdc_encode_reply(context, config, NULL, 0, + ret = _kdc_encode_reply(context, config, NULL, NULL, 0, &rep, &et, &ek, et.key.keytype, kvno, serverkey, 0, replykey, rk_is_subkey, diff --git a/tests/kdc/Makefile.am b/tests/kdc/Makefile.am index ecf74e5d1..a0e624b8e 100644 --- a/tests/kdc/Makefile.am +++ b/tests/kdc/Makefile.am @@ -14,6 +14,7 @@ SCRIPT_TESTS = \ check-delegation \ check-des \ check-digest \ + check-fast \ check-kadmin \ check-kdc \ check-kdc-weak \ @@ -63,6 +64,11 @@ check-des: check-des.in Makefile krb5.conf chmod +x check-des.tmp mv check-des.tmp check-des +check-fast: check-fast.in Makefile + $(do_subst) < $(srcdir)/check-fast.in > check-fast.tmp + chmod +x check-fast.tmp + mv check-fast.tmp check-fast + check-kdc: check-kdc.in Makefile $(do_subst) < $(srcdir)/check-kdc.in > check-kdc.tmp chmod +x check-kdc.tmp diff --git a/tests/kdc/check-fast.in b/tests/kdc/check-fast.in new file mode 100644 index 000000000..c565f25db --- /dev/null +++ b/tests/kdc/check-fast.in @@ -0,0 +1,150 @@ +#!/bin/sh +# +# Copyright (c) 2006 - 2011 Kungliga Tekniska Högskolan +# (Royal Institute of Technology, Stockholm, Sweden). +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the Institute nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +top_builddir="@top_builddir@" +env_setup="@env_setup@" +objdir="@objdir@" + +. ${env_setup} + +KRB5_CONFIG="${1-${objdir}/krb5.conf}" +export KRB5_CONFIG + +testfailed="echo test failed; cat messages.log; exit 1" + +# If there is no useful db support compile in, disable test +${have_db} || exit 77 + +R=TEST.H5L.SE + +port=@port@ + +kadmin="${kadmin} -l -r $R" +kdc="${kdc} --addresses=localhost -P $port" + +server=host/datan.test.h5l.se +cache="FILE:${objdir}/cache.krb5" +acache="FILE:${objdir}/acache.krb5" + +kinit="${kinit} -c $cache ${afs_no_afslog}" +klist="${klist} -c $cache" +aklist="${klist} -c $acache" +kgetcred="${kgetcred} -c $cache" +kdestroy="${kdestroy} -c $cache ${afs_no_unlog}" + +rm -f ${keytabfile} +rm -f current-db* +rm -f out-* +rm -f mkey.file* + +> messages.log + +echo Creating database +${kadmin} \ + init \ + --realm-max-ticket-life=1day \ + --realm-max-renewable-life=1month \ + ${R} || exit 1 + +${kadmin} add -p foo --use-defaults foo@${R} || exit 1 +${kadmin} add -p foo --use-defaults ${server}@${R} || exit 1 + +echo "Doing database check" +${kadmin} check ${R} || exit 1 + +echo foo > ${objdir}/foopassword + +echo Starting kdc +env MallocStackLogging=1 MallocStackLoggingNoCompact=1 MallocErrorAbort=1 MallocLogFile=${objdir}/malloc-log \ +${kdc} & +kdcpid=$! + +sh ${wait_kdc} +if [ "$?" != 0 ] ; then + kill -9 ${kdcpid} + exit 1 +fi + +trap "kill -9 ${kdcpid}; echo signal killing kdc; exit 1;" EXIT + +ec=0 + +echo "Getting client initial tickets"; > messages.log +${kinit} --password-file=${objdir}/foopassword foo@$R || \ + { ec=1 ; eval "${testfailed}"; } +echo "Getting tickets"; > messages.log +${kgetcred} ${server}@${R} || { ec=1 ; eval "${testfailed}"; } +echo "Listing tickets"; > messages.log +${klist} > /dev/null || { ec=1 ; eval "${testfailed}"; } +${kdestroy} + +echo foo > ${objdir}/foopassword + +kinitpty=${objdir}/foopassword.rkpty +cat > ${kinitpty} </dev/null|| { exit 1; } + (${aklist} | grep ${server} > /dev/null ) || { exit 1; } + + echo "Checking for FAST avail" + ${aklist} --hidden | grep fast_avail > /dev/null || { exit 1; } + + echo "Using plain to get a initial ticket" + ${rkpty} ${kinitpty} ${mit}/kinit -c ${cache} foo@${R} >/dev/null|| { exit 1; } + (${aklist} | grep ${server} > /dev/null ) || { exit 1; } + + echo "Using FAST to get a initial ticket" + ${rkpty} ${kinitpty} ${mit}/kinit -c ${cache} -T ${acache} foo@${R} >/dev/null || { exit 1; } + (${aklist} | grep ${server} > /dev/null ) || { exit 1; } + + echo "Checking for FAST avail" + ${klist} --hidden | grep fast_avail > /dev/null || { exit 1; } + +fi + + +echo "killing kdc (${kdcpid})" +sh ${leaks_kill} kdc $kdcpid || exit 1 + +trap "" EXIT + +exit $ec From 65254713a2b7f8379f6079f3cf36d59efdd44848 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Mon, 9 May 2011 21:17:29 -0700 Subject: [PATCH 046/119] log if we have FAST PA or not --- kdc/krb5tgs.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/kdc/krb5tgs.c b/kdc/krb5tgs.c index 559e18dfb..9b7c21346 100644 --- a/kdc/krb5tgs.c +++ b/kdc/krb5tgs.c @@ -2317,6 +2317,14 @@ _kdc_tgs_rep(krb5_context context, goto out; } + { + int i = 0; + const PA_DATA *pa = _kdc_find_padata(req, &i, KRB5_PADATA_FX_FAST); + if (pa) + kdc_log(context, config, 10, "Got TGS FAST request"); + } + + ret = tgs_build_reply(context, config, req, From 0332787e0f5b541bd55e5f72fcc9e7ee835b52ec Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Mon, 9 May 2011 21:39:26 -0700 Subject: [PATCH 047/119] Hide client name of privacy reasons --- kdc/kerberos5.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 1ff6714d9..532c29e6b 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -481,6 +481,13 @@ _kdc_encode_reply(krb5_context context, data.data, data.length); if (ret) return ret; + + /* + * Hide client name of privacy reasons + */ + rep->crealm[0] = '\0'; + free_PrincipalName(&rep->cname); + rep->cname.name_type = 0; } if(rep->msg_type == krb_as_rep && !config->encode_as_rep_as_tgs_rep) From ca060554fb2c6145157d984c30fb757997b19037 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Tue, 10 May 2011 06:25:12 -0700 Subject: [PATCH 048/119] x --- doc/standardisation/rfc6112.txt | 899 +++++++++++ doc/standardisation/rfc6113.txt | 2691 +++++++++++++++++++++++++++++++ 2 files changed, 3590 insertions(+) create mode 100644 doc/standardisation/rfc6112.txt create mode 100644 doc/standardisation/rfc6113.txt diff --git a/doc/standardisation/rfc6112.txt b/doc/standardisation/rfc6112.txt new file mode 100644 index 000000000..b40775966 --- /dev/null +++ b/doc/standardisation/rfc6112.txt @@ -0,0 +1,899 @@ + + + + + + +Internet Engineering Task Force (IETF) L. Zhu +Request for Comments: 6112 P. Leach +Updates: 4120, 4121, 4556 Microsoft Corporation +Category: Standards Track S. Hartman +ISSN: 2070-1721 Painless Security + April 2011 + + + Anonymity Support for Kerberos + +Abstract + + This document defines extensions to the Kerberos protocol to allow a + Kerberos client to securely communicate with a Kerberos application + service without revealing its identity, or without revealing more + than its Kerberos realm. It also defines extensions that allow a + Kerberos client to obtain anonymous credentials without revealing its + identity to the Kerberos Key Distribution Center (KDC). This + document updates RFCs 4120, 4121, and 4556. + +Status of This Memo + + This is an Internet Standards Track document. + + This document is a product of the Internet Engineering Task Force + (IETF). It represents the consensus of the IETF community. It has + received public review and has been approved for publication by the + Internet Engineering Steering Group (IESG). Further information on + Internet Standards is available in Section 2 of RFC 5741. + + Information about the current status of this document, any errata, + and how to provide feedback on it may be obtained at + http://www.rfc-editor.org/info/rfc6112. + +Copyright Notice + + Copyright (c) 2011 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (http://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. Code Components extracted from this document must + include Simplified BSD License text as described in Section 4.e of + the Trust Legal Provisions and are provided without warranty as + described in the Simplified BSD License. + + + +Zhu, et al. Standards Track [Page 1] + +RFC 6112 Kerberos Anonymity Support April 2011 + + + This document may contain material from IETF Documents or IETF + Contributions published or made publicly available before November + 10, 2008. The person(s) controlling the copyright in some of this + material may not have granted the IETF Trust the right to allow + modifications of such material outside the IETF Standards Process. + Without obtaining an adequate license from the person(s) controlling + the copyright in such materials, this document may not be modified + outside the IETF Standards Process, and derivative works of it may + not be created outside the IETF Standards Process, except to format + it for publication as an RFC or to translate it into languages other + than English. + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 3 + 2. Conventions Used in This Document . . . . . . . . . . . . . . 3 + 3. Definitions . . . . . . . . . . . . . . . . . . . . . . . . . 3 + 4. Protocol Description . . . . . . . . . . . . . . . . . . . . . 5 + 4.1. Anonymity Support in AS Exchange . . . . . . . . . . . . . 5 + 4.1.1. Anonymous PKINIT . . . . . . . . . . . . . . . . . . . 6 + 4.2. Anonymity Support in TGS Exchange . . . . . . . . . . . . 7 + 4.3. Subsequent Exchanges and Protocol Actions Common to AS + and TGS for Anonymity Support . . . . . . . . . . . . . . 9 + 5. Interoperability Requirements . . . . . . . . . . . . . . . . 10 + 6. GSS-API Implementation Notes . . . . . . . . . . . . . . . . . 10 + 7. PKINIT Client Contribution to the Ticket Session Key . . . . . 11 + 7.1. Combining Two Protocol Keys . . . . . . . . . . . . . . . 12 + 8. Security Considerations . . . . . . . . . . . . . . . . . . . 13 + 9. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 14 + 10. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 15 + 11. References . . . . . . . . . . . . . . . . . . . . . . . . . . 15 + 11.1. Normative References . . . . . . . . . . . . . . . . . . . 15 + 11.2. Informative References . . . . . . . . . . . . . . . . . . 16 + + + + + + + + + + + + + + + + + + +Zhu, et al. Standards Track [Page 2] + +RFC 6112 Kerberos Anonymity Support April 2011 + + +1. Introduction + + In certain situations, the Kerberos [RFC4120] client may wish to + authenticate a server and/or protect communications without revealing + the client's own identity. For example, consider an application that + provides read access to a research database and that permits queries + by arbitrary requesters. A client of such a service might wish to + authenticate the service, to establish trust in the information + received from it, but might not wish to disclose the client's + identity to the service for privacy reasons. + + Extensions to Kerberos are specified in this document by which a + client can authenticate the Key Distribution Center (KDC) and request + an anonymous ticket. The client can use the anonymous ticket to + authenticate the server and protect subsequent client-server + communications. + + By using the extensions defined in this specification, the client can + request an anonymous ticket where the client may reveal the client's + identity to the client's own KDC, or the client can hide the client's + identity completely by using anonymous Public Key Cryptography for + Initial Authentication in Kerberos (PKINIT) as defined in + Section 4.1. Using the returned anonymous ticket, the client remains + anonymous in subsequent Kerberos exchanges thereafter to KDCs on the + cross-realm authentication path and to the server with which it + communicates. + + In this specification, the client realm in the anonymous ticket is + the anonymous realm name when anonymous PKINIT is used to obtain the + ticket. The client realm is the client's real realm name if the + client is authenticated using the client's long-term keys. Note that + the membership of a realm can imply a member of the community + represented by the realm. + + The interaction with Generic Security Service Application Program + Interface (GSS-API) is described after the protocol description. + +2. Conventions Used in This Document + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [RFC2119]. + +3. Definitions + + The anonymous Kerberos realm name is defined as a well-known realm + name based on [RFC6111], and the value of this well-known realm name + is the literal "WELLKNOWN:ANONYMOUS". + + + +Zhu, et al. Standards Track [Page 3] + +RFC 6112 Kerberos Anonymity Support April 2011 + + + The anonymous Kerberos principal name is defined as a well-known + Kerberos principal name based on [RFC6111]. The value of the name- + type field is KRB_NT_WELLKNOWN [RFC6111], and the value of the name- + string field is a sequence of two KerberosString components: + "WELLKNOWN", "ANONYMOUS". + + The anonymous ticket flag is defined as bit 16 (with the first bit + being bit 0) in the TicketFlags: + + TicketFlags ::= KerberosFlags + -- anonymous(16) + -- TicketFlags and KerberosFlags are defined in [RFC4120] + + This is a new ticket flag that is used to indicate that a ticket is + an anonymous one. + + An anonymous ticket is a ticket that has all of the following + properties: + + o The cname field contains the anonymous Kerberos principal name. + + o The crealm field contains the client's realm name or the anonymous + realm name. + + o The anonymous ticket contains no information that can reveal the + client's identity. However, the ticket may contain the client + realm, intermediate realms on the client's authentication path, + and authorization data that may provide information related to the + client's identity. For example, an anonymous principal that is + identifiable only within a particular group of users can be + implemented using authorization data and such authorization data, + if included in the anonymous ticket, would disclose the client's + membership of that group. + + o The anonymous ticket flag is set. + + The anonymous KDC option is defined as bit 16 (with the first bit + being bit 0) in the KDCOptions: + + KDCOptions ::= KerberosFlags + -- anonymous(16) + -- KDCOptions and KerberosFlags are defined in [RFC4120] + + + + + + + + + +Zhu, et al. Standards Track [Page 4] + +RFC 6112 Kerberos Anonymity Support April 2011 + + + As described in Section 4, the anonymous KDC option is set to request + an anonymous ticket in an Authentication Service (AS) request or a + Ticket Granting Service (TGS) request. + +4. Protocol Description + + In order to request an anonymous ticket, the client sets the + anonymous KDC option in an AS request or a TGS request. + + The rest of this section is organized as follows: it first describes + protocol actions specific to AS exchanges, then it describes those of + TGS exchanges. These are then followed by the description of + protocol actions common to both AS and TGS and those in subsequent + exchanges. + +4.1. Anonymity Support in AS Exchange + + The client requests an anonymous ticket by setting the anonymous KDC + option in an AS exchange. + + The Kerberos client can use the client's long-term keys, the client's + X.509 certificates [RFC4556], or any other pre-authentication data, + to authenticate to the KDC and requests an anonymous ticket in an AS + exchange where the client's identity is known to the KDC. + + If the client in the AS request is anonymous, the anonymous KDC + option MUST be set in the request. Otherwise, the KDC MUST return a + KRB-ERROR message with the code KDC_ERR_BADOPTION. + + If the client is anonymous and the KDC does not have a key to encrypt + the reply (this can happen when, for example, the KDC does not + support PKINIT [RFC4556]), the KDC MUST return an error message with + the code KDC_ERR_NULL_KEY [RFC4120]. + + When policy allows, the KDC issues an anonymous ticket. If the + client name in the request is the anonymous principal, the client + realm (crealm) in the reply is the anonymous realm, otherwise, the + client realm is the realm of the AS. According to [RFC4120], the + client name and the client realm in the EncTicketPart of the reply + MUST match with the corresponding client name and the client realm of + the KDC reply; the client MUST use the client name and the client + realm returned in the KDC-REP in subsequent message exchanges when + using the obtained anonymous ticket. + + Care MUST be taken by the KDC not to reveal the client's identity in + the authorization data of the returned ticket when populating the + authorization data in a returned anonymous ticket. + + + + +Zhu, et al. Standards Track [Page 5] + +RFC 6112 Kerberos Anonymity Support April 2011 + + + The AD-INITIAL-VERIFIED-CAS authorization data, as defined in + [RFC4556], contains the issuer name of the client certificate. This + authorization is not applicable and MUST NOT be present in the + returned anonymous ticket when anonymous PKINIT is used. When the + client is authenticated (i.e., anonymous PKINIT is not used), if it + is undesirable to disclose such information about the client's + identity, the AD-INITIAL-VERIFIED-CAS authorization data SHOULD be + removed from the returned anonymous ticket. + + The client can use the client keys to mutually authenticate with the + KDC and request an anonymous Ticket Granting Ticket (TGT) in the AS + request. In that case, the reply key is selected as normal, + according to Section 3.1.3 of [RFC4120]. + +4.1.1. Anonymous PKINIT + + This sub-section defines anonymous PKINIT. + + As described earlier in this section, the client can request an + anonymous ticket by authenticating to the KDC using the client's + identity; alternatively, without revealing the client's identity to + the KDC, the Kerberos client can request an anonymous ticket as + follows: the client sets the client name as the anonymous principal + in the AS exchange and provides PA_PK_AS_REQ pre-authentication data + [RFC4556] where the signerInfos field of the SignedData [RFC5652] of + the PA_PK_AS_REQ is empty, and the certificates field is absent. + Because the anonymous client does not have an associated asymmetric + key pair, the client MUST choose the Diffie-Hellman key agreement + method by filling in the Diffie-Hellman domain parameters in the + clientPublicValue [RFC4556]. This use of the anonymous client name + in conjunction with PKINIT is referred to as anonymous PKINIT. If + anonymous PKINIT is used, the realm name in the returned anonymous + ticket MUST be the anonymous realm. + + Upon receiving the anonymous PKINIT request from the client, the KDC + processes the request, according to Section 3.1.2 of [RFC4120]. The + KDC skips the checks for the client's signature and the client's + public key (such as the verification of the binding between the + client's public key and the client name), but performs otherwise + applicable checks, and proceeds as normal, according to [RFC4556]. + For example, the AS MUST check if the client's Diffie-Hellman domain + parameters are acceptable. The Diffie-Hellman key agreement method + MUST be used and the reply key is derived according to Section + 3.2.3.1 of [RFC4556]. If the clientPublicValue is not present in the + request, the KDC MUST return a KRB-ERROR with the code + KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED [RFC4556]. If all goes + well, an anonymous ticket is generated, according to Section 3.1.3 of + [RFC4120], and PA_PK_AS_REP [RFC4556] pre-authentication data is + + + +Zhu, et al. Standards Track [Page 6] + +RFC 6112 Kerberos Anonymity Support April 2011 + + + included in the KDC reply, according to [RFC4556]. If the KDC does + not have an asymmetric key pair, it MAY reply anonymously or reject + the authentication attempt. If the KDC replies anonymously, the + signerInfos field of the SignedData [RFC5652] of PA_PK_AS_REP in the + reply is empty, and the certificates field is absent. The server + name in the anonymous KDC reply contains the name of the TGS. + + Upon receipt of the KDC reply that contains an anonymous ticket and + PA_PK_AS_REP [RFC4556] pre-authentication data, the client can then + authenticate the KDC based on the KDC's signature in the + PA_PK_AS_REP. If the KDC's signature is missing in the KDC reply + (the reply is anonymous), the client MUST reject the returned ticket + if it cannot authenticate the KDC otherwise. + + A KDC that supports anonymous PKINIT MUST indicate the support of + PKINIT, according to Section 3.4 of [RFC4556]. In addition, such a + KDC MUST indicate support for anonymous PKINIT by including a padata + element of padata-type PA_PKINIT_KX and empty padata-value when + including PA-PK-AS-REQ in an error reply. + + When included in a KDC error, PA_PKINIT_KX indicates support for + anonymous PKINIT. As discussed in Section 7, when included in an AS- + REP, PA_PKINIT_KX proves that the KDC and client both contributed to + the session key for any use of Diffie-Hellman key agreement with + PKINIT. + + Note that in order to obtain an anonymous ticket with the anonymous + realm name, the client MUST set the client name as the anonymous + principal in the request when requesting an anonymous ticket in an AS + exchange. Anonymity PKINIT is the only way via which an anonymous + ticket with the anonymous realm as the client realm can be generated + in this specification. + +4.2. Anonymity Support in TGS Exchange + + The client requests an anonymous ticket by setting the anonymous KDC + option in a TGS exchange, and in that request the client can use a + normal Ticket Granting Ticket (TGT) with the client's identity, or an + anonymous TGT, or an anonymous cross-realm TGT. If the client uses a + normal TGT, the client's identity is known to the TGS. + + Note that the client can completely hide the client's identity in an + AS exchange using anonymous PKINIT, as described in the previous + section. + + + + + + + +Zhu, et al. Standards Track [Page 7] + +RFC 6112 Kerberos Anonymity Support April 2011 + + + If the ticket in the PA-TGS-REQ of the TGS request is an anonymous + one, the anonymous KDC option MUST be set in the request. Otherwise, + the KDC MUST return a KRB-ERROR message with the code + KDC_ERR_BADOPTION. + + When policy allows, the KDC issues an anonymous ticket. If the + ticket in the TGS request is an anonymous one, the client name and + the client realm are copied from that ticket; otherwise, the ticket + in the TGS request is a normal ticket, the returned anonymous ticket + contains the client name as the anonymous principal and the client + realm as the true realm of the client. In all cases, according to + [RFC4120] the client name and the client realm in the EncTicketPart + of the reply MUST match with the corresponding client name and the + client realm of the anonymous ticket in the reply; the client MUST + use the client name and the client realm returned in the KDC-REP in + subsequent message exchanges when using the obtained anonymous + ticket. + + Care MUST be taken by the TGS not to reveal the client's identity in + the authorization data of the returned ticket. When propagating + authorization data in the ticket or in the enc-authorization-data + field of the request, the TGS MUST ensure that the client + confidentiality is not violated in the returned anonymous ticket. + The TGS MUST process the authorization data recursively, according to + Section 5.2.6 of [RFC4120], beyond the container levels such that all + embedded authorization elements are interpreted. The TGS SHOULD NOT + populate identity-based authorization data into an anonymous ticket + in that such authorization data typically reveals the client's + identity. The specification of a new authorization data type MUST + specify the processing rules of the authorization data when an + anonymous ticket is returned. If there is no processing rule defined + for an authorization data element or the authorization data element + is unknown, the TGS MUST process it when an anonymous ticket is + returned as follows: + + o If the authorization data element may reveal the client's + identity, it MUST be removed unless otherwise specified. + + o If the authorization data element, that could reveal the client's + identity, is intended to restrict the use of the ticket or limit + the rights otherwise conveyed in the ticket, it cannot be removed + in order to hide the client's identity. In this case, the + authentication attempt MUST be rejected, and the TGS MUST return + an error message with the code KDC_ERR_POLICY. Note this is + applicable to both critical and optional authorization data. + + + + + + +Zhu, et al. Standards Track [Page 8] + +RFC 6112 Kerberos Anonymity Support April 2011 + + + o If the authorization data element is unknown, the TGS MAY remove + it, or transfer it into the returned anonymous ticket, or reject + the authentication attempt, based on local policy for that + authorization data type unless otherwise specified. If there is + no policy defined for a given unknown authorization data type, the + authentication MUST be rejected. The error code is KDC_ERR_POLICY + when the authentication is rejected. + + The AD-INITIAL-VERIFIED-CAS authorization data, as defined in + [RFC4556], contains the issuer name of the client certificate. If it + is undesirable to disclose such information about the client's + identity, the AD-INITIAL-VERIFIED-CAS authorization data SHOULD be + removed from an anonymous ticket. + + The TGS encodes the name of the previous realm into the transited + field, according to Section 3.3.3.2 of [RFC4120]. Based on local + policy, the TGS MAY omit the previous realm, if the cross realm TGT + is an anonymous one, in order to hide the authentication path of the + client. The unordered set of realms in the transited field, if + present, can reveal which realm may potentially be the realm of the + client or the realm that issued the anonymous TGT. The anonymous + Kerberos realm name MUST NOT be present in the transited field of a + ticket. The true name of the realm that issued the anonymous ticket + MAY be present in the transited field of a ticket. + +4.3. Subsequent Exchanges and Protocol Actions Common to AS and TGS for + Anonymity Support + + In both AS and TGS exchanges, the realm field in the KDC request is + always the realm of the target KDC, not the anonymous realm when the + client requests an anonymous ticket. + + Absent other information, the KDC MUST NOT include any identifier in + the returned anonymous ticket that could reveal the client's identity + to the server. + + Unless anonymous PKINIT is used, if a client requires anonymous + communication, then the client MUST check to make sure that the + ticket in the reply is actually anonymous by checking the presence of + the anonymous ticket flag in the flags field of the EncKDCRepPart. + This is because KDCs ignore unknown KDC options. A KDC that does not + understand the anonymous KDC option will not return an error, but + will instead return a normal ticket. + + The subsequent client and server communications then proceed as + described in [RFC4120]. + + + + + +Zhu, et al. Standards Track [Page 9] + +RFC 6112 Kerberos Anonymity Support April 2011 + + + Note that the anonymous principal name and realm are only applicable + to the client in Kerberos messages, the server cannot be anonymous in + any Kerberos message per this specification. + + A server accepting an anonymous service ticket may assume that + subsequent requests using the same ticket originate from the same + client. Requests with different tickets are likely to originate from + different clients. + + Upon receipt of an anonymous ticket, the transited policy check is + performed in the same way as that of a normal ticket if the client's + realm is not the anonymous realm; if the client realm is the + anonymous realm, absent other information any realm in the + authentication path is allowed by the cross-realm policy check. + +5. Interoperability Requirements + + Conforming implementations MUST support the anonymous principal with + a non-anonymous realm, and they MAY support the anonymous principal + with the anonymous realm using anonymous PKINIT. + +6. GSS-API Implementation Notes + + GSS-API defines the name_type GSS_C_NT_ANONYMOUS [RFC2743] to + represent the anonymous identity. In addition, Section 2.1.1 of + [RFC1964] defines the single string representation of a Kerberos + principal name with the name_type GSS_KRB5_NT_PRINCIPAL_NAME. The + anonymous principal with the anonymous realm corresponds to the GSS- + API anonymous principal. A principal with the anonymous principal + name and a non-anonymous realm is an authenticated principal; hence, + such a principal does not correspond to the anonymous principal in + GSS-API with the GSS_C_NT_ANONYMOUS name type. The [RFC1964] name + syntax for GSS_KRB5_NT_PRINCIPAL_NAME MUST be used for importing the + anonymous principal name with a non-anonymous realm name and for + displaying and exporting these names. In addition, this syntax must + be used along with the name type GSS_C_NT_ANONYMOUS for displaying + and exporting the anonymous principal with the anonymous realm. + + At the GSS-API [RFC2743] level, an initiator/client requests the use + of an anonymous principal with the anonymous realm by asserting the + "anonymous" flag when calling GSS_Init_Sec_Context(). The GSS-API + implementation MAY provide implementation-specific means for + requesting the use of an anonymous principal with a non-anonymous + realm. + + GSS-API does not know or define "anonymous credentials", so the + (printable) name of the anonymous principal will rarely be used by or + relevant for the initiator/client. The printable name is relevant + + + +Zhu, et al. Standards Track [Page 10] + +RFC 6112 Kerberos Anonymity Support April 2011 + + + for the acceptor/server when performing an authorization decision + based on the initiator name that is returned from the acceptor side + upon the successful security context establishment. + + A GSS-API initiator MUST carefully check the resulting context + attributes from the initial call to GSS_Init_Sec_Context() when + requesting anonymity, because (as in the GSS-API tradition and for + backwards compatibility) anonymity is just another optional context + attribute. It could be that the mechanism doesn't recognize the + attribute at all or that anonymity is not available for some other + reasons -- and in that case the initiator MUST NOT send the initial + security context token to the acceptor, because it will likely reveal + the initiators identity to the acceptor, something that can rarely be + "un-done". + + Portable initiators are RECOMMENDED to use default credentials + whenever possible, and request anonymity only through the input + anon_req_flag [RFC2743] to GSS_Init_Sec_Context(). + +7. PKINIT Client Contribution to the Ticket Session Key + + The definition in this section was motivated by protocol analysis of + anonymous PKINIT (defined in this document) in building tunneling + channels [RFC6113] and subsequent channel bindings. In order to + enable applications of anonymous PKINIT to form channels, all + implementations of anonymous PKINIT need to meet the requirements of + this section. There is otherwise no connection to the rest of this + document. + + PKINIT is useful for constructing tunneling channels. To ensure that + an attacker cannot create a channel with a given name, it is + desirable that neither the KDC nor the client unilaterally determine + the ticket session key. To achieve that end, a KDC conforming to + this definition MUST encrypt a randomly generated key, called the KDC + contribution key, in the PA_PKINIT_KX padata (defined next in this + section). The KDC contribution key is then combined with the reply + key to form the ticket session key of the returned ticket. These two + keys are then combined using the KRB-FX-CF2 operation defined in + Section 7.1, where K1 is the KDC contribution key, K2 is the reply + key, the input pepper1 is American Standard Code for Information + Interchange (ASCII) [ASAX34] string "PKINIT", and the input pepper2 + is ASCII string "KeyExchange". + + + + + + + + + +Zhu, et al. Standards Track [Page 11] + +RFC 6112 Kerberos Anonymity Support April 2011 + + + PA_PKINIT_KX 147 + -- padata for PKINIT that contains an encrypted + -- KDC contribution key. + + PA-PKINIT-KX ::= EncryptedData -- EncryptionKey + -- Contains an encrypted key randomly + -- generated by the KDC (known as the KDC contribution key). + -- Both EncryptedData and EncryptionKey are defined in [RFC4120] + + The PA_PKINIT_KX padata MUST be included in the KDC reply when + anonymous PKINIT is used; it SHOULD be included if PKINIT is used + with the Diffie-Hellman key exchange but the client is not anonymous; + it MUST NOT be included otherwise (e.g., when PKINIT is used with the + public key encryption as the key exchange). + + The padata-value field of the PA-PKINIT-KX type padata contains the + DER [X.680] [X.690] encoding of the Abstract Syntax Notation One + (ASN.1) type PA-PKINIT-KX. The PA-PKINIT-KX structure is an + EncryptedData. The cleartext data being encrypted is the DER-encoded + KDC contribution key randomly generated by the KDC. The encryption + key is the reply key and the key usage number is + KEY_USAGE_PA_PKINIT_KX (44). + + The client then decrypts the KDC contribution key and verifies the + ticket session key in the returned ticket is the combined key of the + KDC contribution key and the reply key as described above. A + conforming client MUST reject anonymous PKINIT authentication if the + PA_PKINIT_KX padata is not present in the KDC reply or if the ticket + session key of the returned ticket is not the combined key of the KDC + contribution key and the reply key when PA-PKINIT-KX is present in + the KDC reply. + +7.1. Combining Two Protocol Keys + + KRB-FX-CF2() combines two protocol keys based on the pseudo-random() + function defined in [RFC3961]. + + Given two input keys, K1 and K2, where K1 and K2 can be of two + different enctypes, the output key of KRB-FX-CF2(), K3, is derived as + follows: + + KRB-FX-CF2(protocol key, protocol key, octet string, + octet string) -> (protocol key) + + PRF+(K1, pepper1) -> octet-string-1 + PRF+(K2, pepper2) -> octet-string-2 + KRB-FX-CF2(K1, K2, pepper1, pepper2) -> + random-to-key(octet-string-1 ^ octet-string-2) + + + +Zhu, et al. Standards Track [Page 12] + +RFC 6112 Kerberos Anonymity Support April 2011 + + + Where ^ denotes the exclusive-OR operation. PRF+() is defined as + follows: + + PRF+(protocol key, octet string) -> (octet string) + + PRF+(key, shared-info) -> pseudo-random( key, 1 || shared-info ) || + pseudo-random( key, 2 || shared-info ) || + pseudo-random( key, 3 || shared-info ) || ... + + Here the counter value 1, 2, 3, and so on are encoded as a one-octet + integer. The pseudo-random() operation is specified by the enctype + of the protocol key. PRF+() uses the counter to generate enough bits + as needed by the random-to-key() [RFC3961] function for the + encryption type specified for the resulting key; unneeded bits are + removed from the tail. + +8. Security Considerations + + Since KDCs ignore unknown options, a client requiring anonymous + communication needs to make sure that the returned ticket is actually + anonymous. This is because a KDC that does not understand the + anonymous option would not return an anonymous ticket. + + By using the mechanism defined in this specification, the client does + not reveal the client's identity to the server but the client + identity may be revealed to the KDC of the server principal (when the + server principal is in a different realm than that of the client), + and any KDC on the cross-realm authentication path. The Kerberos + client MUST verify the ticket being used is indeed anonymous before + communicating with the server, otherwise, the client's identity may + be revealed unintentionally. + + In cases where specific server principals must not have access to the + client's identity (for example, an anonymous poll service), the KDC + can define server-principal-specific policy that ensures any normal + service ticket can NEVER be issued to any of these server principals. + + If the KDC that issued an anonymous ticket were to maintain records + of the association of identities to an anonymous ticket, then someone + obtaining such records could breach the anonymity. Additionally, the + implementations of most (for now all) KDC's respond to requests at + the time that they are received. Traffic analysis on the connection + to the KDC will allow an attacker to match client identities to + anonymous tickets issued. Because there are plaintext parts of the + tickets that are exposed on the wire, such matching by a third-party + observer is relatively straightforward. A service that is + authenticated by the anonymous principals may be able to infer the + + + + +Zhu, et al. Standards Track [Page 13] + +RFC 6112 Kerberos Anonymity Support April 2011 + + + identity of the client by examining and linking quasi-static protocol + information such as the IP address from which a request is received, + or by linking multiple uses of the same anonymous ticket. + + Two mechanisms, the FAST facility with the hide-client-names option + in [RFC6113] and the Kerberos5 starttls option [STARTTLS], protect + the client identity so that an attacker would never be able to + observe the client identity sent to the KDC. Transport or network + layer security between the client and the server will help prevent + tracking of a particular ticket to link a ticket to a user. In + addition, clients can limit how often a ticket is reused to minimize + ticket linking. + + The client's real identity is not revealed when the client is + authenticated as the anonymous principal. Application servers MAY + reject the authentication in order to, for example, prevent + information disclosure or as part of Denial of Service (DoS) + prevention. Application servers MUST avoid accepting anonymous + credentials in situations where they must record the client's + identity; for example, when there must be an audit trail. + +9. Acknowledgements + + JK Jaganathan helped editing early revisions of this document. + + Clifford Neuman contributed the core notions of this document. + + Ken Raeburn reviewed the document and provided suggestions for + improvements. + + Martin Rex wrote the text for GSS-API considerations. + + Nicolas Williams reviewed the GSS-API considerations section and + suggested ideas for improvements. + + Sam Hartman and Nicolas Williams were great champions of this work. + + Miguel Garcia and Phillip Hallam-Baker reviewed the document and + provided helpful suggestions. + + In addition, the following individuals made significant + contributions: Jeffrey Altman, Tom Yu, Chaskiel M Grundman, Love + Hornquist Astrand, Jeffrey Hutzelman, and Olga Kornievskaia. + + + + + + + + +Zhu, et al. Standards Track [Page 14] + +RFC 6112 Kerberos Anonymity Support April 2011 + + +10. IANA Considerations + + This document defines a new 'anonymous' Kerberos well-known name and + a new 'anonymous' Kerberos well-known realm based on [RFC6111]. IANA + has added these two values to the Kerberos naming registries that are + created in [RFC6111]. + +11. References + +11.1. Normative References + + [ASAX34] American Standards Institute, "American Standard Code for + Information Interchange", ASA X3.4-1963, June 1963. + + [RFC1964] Linn, J., "The Kerberos Version 5 GSS-API Mechanism", + RFC 1964, June 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2743] Linn, J., "Generic Security Service Application Program + Interface Version 2, Update 1", RFC 2743, January 2000. + + [RFC3961] Raeburn, K., "Encryption and Checksum Specifications for + Kerberos 5", RFC 3961, February 2005. + + [RFC4120] Neuman, C., Yu, T., Hartman, S., and K. Raeburn, "The + Kerberos Network Authentication Service (V5)", RFC 4120, + July 2005. + + [RFC4556] Zhu, L. and B. Tung, "Public Key Cryptography for Initial + Authentication in Kerberos (PKINIT)", RFC 4556, + June 2006. + + [RFC5652] Housley, R., "Cryptographic Message Syntax (CMS)", + STD 70, RFC 5652, September 2009. + + [RFC6111] Zhu, L., "Additional Kerberos Naming Constraints", + RFC 6111, April 2011. + + [X.680] "Abstract Syntax Notation One (ASN.1): Specification of + Basic Notation", ITU-T Recommendation X.680: ISO/IEC + International Standard 8824-1:1998, 1997. + + [X.690] "ASN.1 encoding rules: Specification of Basic Encoding + Rules (BER), Canonical Encoding Rules (CER) and + Distinguished Encoding Rules (DER)", ITU-T Recommendation + X.690 ISO/IEC International Standard 8825-1:1998, 1997. + + + +Zhu, et al. Standards Track [Page 15] + +RFC 6112 Kerberos Anonymity Support April 2011 + + +11.2. Informative References + + [RFC6113] Hartman, S. and L. Zhu, "A Generalized Framework for + Kerberos Pre-Authentication", RFC 6113, April 2011. + + [STARTTLS] Josefsson, S., "Using Kerberos V5 over the Transport + Layer Security (TLS) protocol", Work in Progress, + August 2010. + +Authors' Addresses + + Larry Zhu + Microsoft Corporation + One Microsoft Way + Redmond, WA 98052 + US + + EMail: larry.zhu@microsoft.com + + + Paul Leach + Microsoft Corporation + One Microsoft Way + Redmond, WA 98052 + US + + EMail: paulle@microsoft.com + + + Sam Hartman + Painless Security + + EMail: hartmans-ietf@mit.edu + + + + + + + + + + + + + + + + + + +Zhu, et al. Standards Track [Page 16] + diff --git a/doc/standardisation/rfc6113.txt b/doc/standardisation/rfc6113.txt new file mode 100644 index 000000000..e0a579eab --- /dev/null +++ b/doc/standardisation/rfc6113.txt @@ -0,0 +1,2691 @@ + + + + + + +Internet Engineering Task Force (IETF) S. Hartman +Request for Comments: 6113 Painless Security +Updates: 4120 L. Zhu +Category: Standards Track Microsoft Corporation +ISSN: 2070-1721 April 2011 + + + A Generalized Framework for Kerberos Pre-Authentication + +Abstract + + Kerberos is a protocol for verifying the identity of principals + (e.g., a workstation user or a network server) on an open network. + The Kerberos protocol provides a facility called pre-authentication. + Pre-authentication mechanisms can use this facility to extend the + Kerberos protocol and prove the identity of a principal. + + This document describes a more formal model for this facility. The + model describes what state in the Kerberos request a pre- + authentication mechanism is likely to change. It also describes how + multiple pre-authentication mechanisms used in the same request will + interact. + + This document also provides common tools needed by multiple pre- + authentication mechanisms. One of these tools is a secure channel + between the client and the key distribution center with a reply key + strengthening mechanism; this secure channel can be used to protect + the authentication exchange and thus eliminate offline dictionary + attacks. With these tools, it is relatively straightforward to chain + multiple authentication mechanisms, utilize a different key + management system, or support a new key agreement algorithm. + +Status of This Memo + + This is an Internet Standards Track document. + + This document is a product of the Internet Engineering Task Force + (IETF). It represents the consensus of the IETF community. It has + received public review and has been approved for publication by the + Internet Engineering Steering Group (IESG). Further information on + Internet Standards is available in Section 2 of RFC 5741. + + Information about the current status of this document, any errata, + and how to provide feedback on it may be obtained at + http://www.rfc-editor.org/info/rfc6113. + + + + + + +Hartman & Zhu Standards Track [Page 1] + +RFC 6113 Kerberos Preauth Framework April 2011 + + +Copyright Notice + + Copyright (c) 2011 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + (http://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. Code Components extracted from this document must + include Simplified BSD License text as described in Section 4.e of + the Trust Legal Provisions and are provided without warranty as + described in the Simplified BSD License. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Hartman & Zhu Standards Track [Page 2] + +RFC 6113 Kerberos Preauth Framework April 2011 + + +Table of Contents + + 1. Introduction ....................................................4 + 1.1. Conventions and Terminology Used in This Document ..........5 + 1.2. Conformance Requirements ...................................5 + 2. Model for Pre-Authentication ....................................6 + 2.1. Information Managed by the Pre-Authentication Model ........7 + 2.2. Initial Pre-Authentication Required Error ..................9 + 2.3. Client to KDC .............................................10 + 2.4. KDC to Client .............................................11 + 3. Pre-Authentication Facilities ..................................12 + 3.1. Client Authentication Facility ............................13 + 3.2. Strengthening Reply Key Facility ..........................13 + 3.3. Replace Reply Key Facility ................................14 + 3.4. KDC Authentication Facility ...............................15 + 4. Requirements for Pre-Authentication Mechanisms .................15 + 4.1. Protecting Requests/Responses .............................16 + 5. Tools for Use in Pre-Authentication Mechanisms .................17 + 5.1. Combining Keys ............................................17 + 5.2. Managing States for the KDC ...............................19 + 5.3. Pre-Authentication Set ....................................20 + 5.4. Definition of Kerberos FAST Padata ........................23 + 5.4.1. FAST Armors ........................................24 + 5.4.2. FAST Request .......................................26 + 5.4.3. FAST Response ......................................30 + 5.4.4. Authenticated Kerberos Error Messages Using + Kerberos FAST ......................................33 + 5.4.5. Outer and Inner Requests ...........................34 + 5.4.6. The Encrypted Challenge FAST Factor ................34 + 5.5. Authentication Strength Indication ........................36 + 6. Assigned Constants .............................................37 + 6.1. New Errors ................................................37 + 6.2. Key Usage Numbers .........................................37 + 6.3. Authorization Data Elements ...............................37 + 6.4. New PA-DATA Types .........................................37 + 7. IANA Considerations ............................................38 + 7.1. Pre-Authentication and Typed Data .........................38 + 7.2. Fast Armor Types ..........................................40 + 7.3. FAST Options ..............................................40 + 8. Security Considerations ........................................41 + 9. Acknowledgements ...............................................42 + 10. References ....................................................43 + 10.1. Normative References .....................................43 + 10.2. Informative References ...................................43 + Appendix A. Test Vectors for KRB-FX-CF2 ...........................45 + Appendix B. ASN.1 Module ..........................................46 + + + + + +Hartman & Zhu Standards Track [Page 3] + +RFC 6113 Kerberos Preauth Framework April 2011 + + +1. Introduction + + The core Kerberos specification [RFC4120] treats pre-authentication + data (padata) as an opaque typed hole in the messages to the key + distribution center (KDC) that may influence the reply key used to + encrypt the KDC reply. This generality has been useful: pre- + authentication data is used for a variety of extensions to the + protocol, many outside the expectations of the initial designers. + However, this generality makes designing more common types of pre- + authentication mechanisms difficult. Each mechanism needs to specify + how it interacts with other mechanisms. Also, tasks such as + combining a key with the long-term secrets or proving the identity of + the user are common to multiple mechanisms. Where there are + generally well-accepted solutions to these problems, it is desirable + to standardize one of these solutions so mechanisms can avoid + duplication of work. In other cases, a modular approach to these + problems is appropriate. The modular approach will allow new and + better solutions to common pre-authentication problems to be used by + existing mechanisms as they are developed. + + This document specifies a framework for Kerberos pre-authentication + mechanisms. It defines the common set of functions that pre- + authentication mechanisms perform as well as how these functions + affect the state of the request and reply. In addition, several + common tools needed by pre-authentication mechanisms are provided. + Unlike [RFC3961], this framework is not complete -- it does not + describe all the inputs and outputs for the pre-authentication + mechanisms. Pre-authentication mechanism designers should try to be + consistent with this framework because doing so will make their + mechanisms easier to implement. Kerberos implementations are likely + to have plug-in architectures for pre-authentication; such + architectures are likely to support mechanisms that follow this + framework plus commonly used extensions. This framework also + facilitates combining multiple pre-authentication mechanisms, each of + which may represent an authentication factor, into a single multi- + factor pre-authentication mechanism. + + One of these common tools is the flexible authentication secure + tunneling (FAST) padata type. FAST provides a protected channel + between the client and the key distribution center (KDC), and it can + optionally deliver key material used to strengthen the reply key + within the protected channel. Based on FAST, pre-authentication + mechanisms can extend Kerberos with ease, to support, for example, + password-authenticated key exchange (PAKE) protocols with zero- + knowledge password proof (ZKPP) [EKE] [IEEE1363.2]. Any pre- + authentication mechanism can be encapsulated in the FAST messages as + defined in Section 5.4. A pre-authentication type carried within + FAST is called a "FAST factor". Creating a FAST factor is the + + + +Hartman & Zhu Standards Track [Page 4] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + easiest path to create a new pre-authentication mechanism. FAST + factors are significantly easier to analyze from a security + standpoint than other pre-authentication mechanisms. + + Mechanism designers should design FAST factors, instead of new pre- + authentication mechanisms outside of FAST. + +1.1. Conventions and Terminology Used in This Document + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [RFC2119]. + + This document should be read only after reading the documents + describing the Kerberos cryptography framework [RFC3961] and the core + Kerberos protocol [RFC4120]. This document may freely use + terminology and notation from these documents without reference or + further explanation. + + The word padata is used as a shorthand for pre-authentication data. + + A conversation is the set of all authentication messages exchanged + between the client and the client's Authentication Service (AS) in + order to authenticate the client principal. A conversation as + defined here consists of all messages that are necessary to complete + the authentication between the client and the client's AS. In the + Ticket Granting Service (TGS) exchange, a conversation consists of + the request message and the reply message. The term conversation is + defined here for both AS and TGS for convenience of discussion. See + Section 5.2 for specific rules on the extent of a conversation in the + AS-REQ case. Prior to this framework, implementations needed to use + implementation-specific heuristics to determine the extent of a + conversation. + + If the KDC reply in an AS exchange is verified, the KDC is + authenticated by the client. In this document, verification of the + KDC reply is used as a synonym of authentication of the KDC. + +1.2. Conformance Requirements + + This section summarizes the mandatory-to-implement subset of this + specification as a convenience to implementors. The actual + requirements and their context are stated in the body of the + document. + + Clients conforming to this specification MUST support the padata + defined in Section 5.2. + + + + +Hartman & Zhu Standards Track [Page 5] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + Conforming implementations MUST support Kerberos FAST padata + (Section 5.4). Conforming implementations MUST implement the + FX_FAST_ARMOR_AP_REQUEST armor type. + + Conforming implementations MUST support the encrypted challenge FAST + factor (Section 5.4.6). + +2. Model for Pre-Authentication + + When a Kerberos client wishes to obtain a ticket, it sends an initial + Authentication Service (AS) request to the KDC. If pre- + authentication is required but not being used, then the KDC will + respond with a KDC_ERR_PREAUTH_REQUIRED error [RFC4120]. + Alternatively, if the client knows what pre-authentication to use, it + MAY optimize away a round trip and send an initial request with + padata included in the initial request. If the client includes the + padata computed using the wrong pre-authentication mechanism or + incorrect keys, the KDC MAY return KDC_ERR_PREAUTH_FAILED with no + indication of what padata should have been included. In that case, + the client MUST retry with no padata and examine the error data of + the KDC_ERR_PREAUTH_REQUIRED error. If the KDC includes pre- + authentication information in the accompanying error data of + KDC_ERR_PREAUTH_FAILED, the client SHOULD process the error data and + then retry. + + The conventional KDC maintains no state between two requests; + subsequent requests may even be processed by a different KDC. On the + other hand, the client treats a series of exchanges with KDCs as a + single conversation. Each exchange accumulates state and hopefully + brings the client closer to a successful authentication. + + These models for state management are in apparent conflict. For many + of the simpler pre-authentication scenarios, the client uses one + round trip to find out what mechanisms the KDC supports. Then, the + next request contains sufficient pre-authentication for the KDC to be + able to return a successful reply. For these simple scenarios, the + client only sends one request with pre-authentication data and so the + conversation is trivial. For more complex conversations, the KDC + needs to provide the client with a cookie to include in future + requests to capture the current state of the authentication session. + Handling of multiple round-trip mechanisms is discussed in + Section 5.2. + + This framework specifies the behavior of Kerberos pre-authentication + mechanisms used to identify users or to modify the reply key used to + encrypt the KDC reply. The PA-DATA typed hole may be used to carry + extensions to Kerberos that have nothing to do with proving the + + + + +Hartman & Zhu Standards Track [Page 6] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + identity of the user or establishing a reply key. Such extensions + are outside the scope of this framework. However, mechanisms that do + accomplish these goals should follow this framework. + + This framework specifies the minimum state that a Kerberos + implementation needs to maintain while handling a request in order to + process pre-authentication. It also specifies how Kerberos + implementations process the padata at each step of the AS request + process. + +2.1. Information Managed by the Pre-Authentication Model + + The following information is maintained by the client and KDC as each + request is being processed: + + o The reply key used to encrypt the KDC reply + + o How strongly the identity of the client has been authenticated + + o Whether the reply key has been used in this conversation + + o Whether the reply key has been replaced in this conversation + + o Whether the origin of the KDC reply can be verified by the client + (i.e., whether the KDC is authenticated to the client) + + Conceptually, the reply key is initially the long-term key of the + principal. However, principals can have multiple long-term keys + because of support for multiple encryption types, salts, and + string2key parameters. As described in Section 5.2.7.5 of the + Kerberos protocol [RFC4120], the KDC sends PA-ETYPE-INFO2 to notify + the client what types of keys are available. Thus, in full + generality, the reply key in the pre-authentication model is actually + a set of keys. At the beginning of a request, it is initialized to + the set of long-term keys advertised in the PA-ETYPE-INFO2 element on + the KDC. If multiple reply keys are available, the client chooses + which one to use. Thus, the client does not need to treat the reply + key as a set. At the beginning of a request, the client picks a key + to use. + + KDC implementations MAY choose to offer only one key in the PA-ETYPE- + INFO2 element. Since the KDC already knows the client's list of + supported enctypes from the request, no interoperability problems are + + + + + + + + +Hartman & Zhu Standards Track [Page 7] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + created by choosing a single possible reply key. This way, the KDC + implementation avoids the complexity of treating the reply key as a + set. + + When the padata in the request are verified by the KDC, then the + client is known to have that key; therefore, the KDC SHOULD pick the + same key as the reply key. + + At the beginning of handling a message on both the client and the + KDC, the client's identity is not authenticated. A mechanism may + indicate that it has successfully authenticated the client's + identity. It is useful to keep track of this information on the + client in order to know what pre-authentication mechanisms should be + used. The KDC needs to keep track of whether the client is + authenticated because the primary purpose of pre-authentication is to + authenticate the client identity before issuing a ticket. The + handling of authentication strength using various authentication + mechanisms is discussed in Section 5.5. + + Initially, the reply key is not used. A pre-authentication mechanism + that uses the reply key to encrypt or checksum some data in the + generation of new keys MUST indicate that the reply key is used. + This state is maintained by the client and the KDC to enforce the + security requirement stated in Section 3.3 that the reply key SHOULD + NOT be replaced after it is used. + + Initially, the reply key is not replaced. If a mechanism implements + the Replace Reply Key facility discussed in Section 3.3, then the + state MUST be updated to indicate that the reply key has been + replaced. Once the reply key has been replaced, knowledge of the + reply key is insufficient to authenticate the client. The reply key + is marked as replaced in exactly the same situations as the KDC reply + is marked as not being verified to the client principal. However, + while mechanisms can verify the KDC reply to the client, once the + reply key is replaced, then the reply key remains replaced for the + remainder of the conversation. + + Without pre-authentication, the client knows that the KDC reply is + authentic and has not been modified because it is encrypted in a + long-term key of the client. Only the KDC and the client know that + key. So, at the start of a conversation, the KDC reply is presumed + to be verified using the client's long-term key. It should be noted + that in this document, verifying the KDC reply means authenticating + the KDC, and these phrases are used interchangeably. Any pre- + authentication mechanism that sets a new reply key not based on the + principal's long-term secret MUST either verify the KDC reply some + other way or indicate that the reply is not verified. If a mechanism + indicates that the reply is not verified, then the client + + + +Hartman & Zhu Standards Track [Page 8] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + implementation MUST return an error unless a subsequent mechanism + verifies the reply. The KDC needs to track this state so it can + avoid generating a reply that is not verified. + + In this specification, KDC verification/authentication refers to the + level of authentication of the KDC to the client provided by RFC + 4120. There is a stronger form of KDC verification that, while + sometimes important in Kerberos deployments, is not addressed in this + specification: the typical Kerberos request does not provide a way + for the client machine to know that it is talking to the correct KDC. + Someone who can inject packets into the network between the client + machine and the KDC and who knows the password that the user will + give to the client machine can generate a KDC reply that will decrypt + properly. So, if the client machine needs to authenticate that the + user is in fact the named principal, then the client machine needs to + do a TGS request for itself as a service. Some pre-authentication + mechanisms may provide a way for the client machine to authenticate + the KDC. Examples of this include signing the reply that can be + verified using a well-known public key or providing a ticket for the + client machine as a service. + +2.2. Initial Pre-Authentication Required Error + + Typically, a client starts a conversation by sending an initial + request with no pre-authentication. If the KDC requires pre- + authentication, then it returns a KDC_ERR_PREAUTH_REQUIRED message. + After the first reply with the KDC_ERR_PREAUTH_REQUIRED error code, + the KDC returns the error code KDC_ERR_MORE_PREAUTH_DATA_REQUIRED + (defined in Section 5.2) for pre-authentication configurations that + use multi-round-trip mechanisms; see Section 2.4 for details of that + case. + + The KDC needs to choose which mechanisms to offer the client. The + client needs to be able to choose what mechanisms to use from the + first message. For example, consider the KDC that will accept + mechanism A followed by mechanism B or alternatively the single + mechanism C. A client that supports A and C needs to know that it + should not bother trying A. + + Mechanisms can either be sufficient on their own or can be part of an + authentication set -- a group of mechanisms that all need to + successfully complete in order to authenticate a client. Some + mechanisms may only be useful in authentication sets; others may be + useful alone or in authentication sets. For the second group of + mechanisms, KDC policy dictates whether the mechanism will be part of + an authentication set, offered alone, or both. For each mechanism + that is offered alone (even if it is also offered in an + authentication set), the KDC includes the pre-authentication type ID + + + +Hartman & Zhu Standards Track [Page 9] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + of the mechanism in the padata sequence returned in the + KDC_ERR_PREAUTH_REQUIRED error. Mechanisms that are only offered as + part of an authentication set are not directly represented in the + padata sequence returned in the KDC_ERR_PREAUTH_REQUIRED error, + although they are represented in the PA-AUTHENTICATION-SET sequence. + + The KDC SHOULD NOT send data that is encrypted in the long-term + password-based key of the principal. Doing so has the same security + exposures as the Kerberos protocol without pre-authentication. There + are few situations where the KDC needs to expose cipher text + encrypted in a weak key before the client has proven knowledge of + that key, and where pre-authentication is desirable. + +2.3. Client to KDC + + This description assumes that a client has already received a + KDC_ERR_PREAUTH_REQUIRED from the KDC. If the client performs + optimistic pre-authentication, then the client needs to guess values + for the information it would normally receive from that error + response or use cached information obtained in prior interactions + with the KDC. + + The client starts by initializing the pre-authentication state as + specified. It then processes the padata in the + KDC_ERR_PREAUTH_REQUIRED. + + When processing the response to the KDC_ERR_PREAUTH_REQUIRED, the + client MAY ignore any padata it chooses unless doing so violates a + specification to which the client conforms. Clients conforming to + this specification MUST NOT ignore the padata defined in Section 5.2. + Clients SHOULD choose one authentication set or mechanism that could + lead to authenticating the user and ignore other such mechanisms. + However, this rule does not affect the processing of padata unrelated + to this framework; clients SHOULD process such padata normally. + Since the list of mechanisms offered by the KDC is in the decreasing + preference order, clients typically choose the first mechanism or + authentication set that the client can usefully perform. If a client + chooses to ignore padata, it MUST NOT process the padata, allow the + padata to affect the pre-authentication state, or respond to the + padata. + + For each instance of padata the client chooses to process, the client + processes the padata and modifies the pre-authentication state as + required by that mechanism. + + + + + + + +Hartman & Zhu Standards Track [Page 10] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + After processing the padata in the KDC error, the client generates a + new request. It processes the pre-authentication mechanisms in the + order in which they will appear in the next request, updating the + state as appropriate. The request is sent when it is complete. + +2.4. KDC to Client + + When a KDC receives an AS request from a client, it needs to + determine whether it will respond with an error or an AS reply. + There are many causes for an error to be generated that have nothing + to do with pre-authentication; they are discussed in the core + Kerberos specification. + + From the standpoint of evaluating the pre-authentication, the KDC + first starts by initializing the pre-authentication state. If a PA- + FX-COOKIE pre-authentication data item is present, it is processed + first; see Section 5.2 for a definition. It then processes the + padata in the request. As mentioned in Section 2.3, the KDC MAY + ignore padata that are inappropriate for the configuration and MUST + ignore padata of an unknown type. The KDC MUST NOT ignore padata of + types used in previous messages. For example, if a KDC issues a + KDC_ERR_PREAUTH_REQUIRED error including padata of type x, then the + KDC cannot ignore padata of type x received in an AS-REQ message from + the client. + + At this point, the KDC decides whether it will issue an error or a + reply. Typically, a KDC will issue a reply if the client's identity + has been authenticated to a sufficient degree. + + In the case of a KDC_ERR_MORE_PREAUTH_DATA_REQUIRED error, the KDC + first starts by initializing the pre-authentication state. Then, it + processes any padata in the client's request in the order provided by + the client. Mechanisms that are not understood by the KDC are + ignored. Next, it generates padata for the error response, modifying + the pre-authentication state appropriately as each mechanism is + processed. The KDC chooses the order in which it will generate + padata (and thus the order of padata in the response), but it needs + to modify the pre-authentication state consistently with the choice + of order. For example, if some mechanism establishes an + authenticated client identity, then the subsequent mechanisms in the + generated response receive this state as input. After the padata are + generated, the error response is sent. Typically, the errors with + the code KDC_ERR_MORE_PREAUTH_DATA_REQUIRED in a conversation will + include KDC state, as discussed in Section 5.2. + + To generate a final reply, the KDC generates the padata modifying the + pre-authentication state as necessary. Then, it generates the final + response, encrypting it in the current pre-authentication reply key. + + + +Hartman & Zhu Standards Track [Page 11] + +RFC 6113 Kerberos Preauth Framework April 2011 + + +3. Pre-Authentication Facilities + + Pre-authentication mechanisms can be thought of as providing various + conceptual facilities. This serves two useful purposes. First, + mechanism authors can choose only to solve one specific small + problem. It is often useful for a mechanism designed to offer key + management not to directly provide client authentication but instead + to allow one or more other mechanisms to handle this need. Secondly, + thinking about the abstract services that a mechanism provides yields + a minimum set of security requirements that all mechanisms providing + that facility must meet. These security requirements are not + complete; mechanisms will have additional security requirements based + on the specific protocol they employ. + + A mechanism is not constrained to only offering one of these + facilities. While such mechanisms can be designed and are sometimes + useful, many pre-authentication mechanisms implement several + facilities. It is often easier to construct a secure, simple + solution by combining multiple facilities in a single mechanism than + by solving the problem in full generality. Even when mechanisms + provide multiple facilities, they need to meet the security + requirements for all the facilities they provide. If the FAST factor + approach is used, it is likely that one or a small number of + facilities can be provided by a single mechanism without complicating + the security analysis. + + According to Kerberos extensibility rules (Section 1.5 of the + Kerberos specification [RFC4120]), an extension MUST NOT change the + semantics of a message unless a recipient is known to understand that + extension. Because a client does not know that the KDC supports a + particular pre-authentication mechanism when it sends an initial + request, a pre-authentication mechanism MUST NOT change the semantics + of the request in a way that will break a KDC that does not + understand that mechanism. Similarly, KDCs MUST NOT send messages to + clients that affect the core semantics unless the client has + indicated support for the message. + + The only state in this model that would break the interpretation of a + message is changing the expected reply key. If one mechanism changed + the reply key and a later mechanism used that reply key, then a KDC + that interpreted the second mechanism but not the first would fail to + interpret the request correctly. In order to avoid this problem, + extensions that change core semantics are typically divided into two + parts. The first part proposes a change to the core semantic -- for + example, proposes a new reply key. The second part acknowledges that + the extension is understood and that the change takes effect. + Section 3.2 discusses how to design mechanisms that modify the reply + key to be split into a proposal and acceptance without requiring + + + +Hartman & Zhu Standards Track [Page 12] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + additional round trips to use the new reply key in subsequent pre- + authentication. Other changes in the state described in Section 2.1 + can safely be ignored by a KDC that does not understand a mechanism. + Mechanisms that modify the behavior of the request outside the scope + of this framework need to carefully consider the Kerberos + extensibility rules to avoid similar problems. + +3.1. Client Authentication Facility + + The Client Authentication facility proves the identity of a user to + the KDC before a ticket is issued. Examples of mechanisms + implementing this facility include the encrypted timestamp facility, + defined in Section 5.2.7.2 of the Kerberos specification [RFC4120]. + Mechanisms that provide this facility are expected to mark the client + as authenticated. + + Mechanisms implementing this facility SHOULD require the client to + prove knowledge of the reply key before transmitting a successful KDC + reply. Otherwise, an attacker can intercept the pre-authentication + exchange and get a reply to attack. One way of proving the client + knows the reply key is to implement the Replace Reply Key facility + along with this facility. The Public Key Cryptography for Initial + Authentication in Kerberos (PKINIT) mechanism [RFC4556] implements + Client Authentication alongside Replace Reply Key. + + If the reply key has been replaced, then mechanisms such as + encrypted-timestamp that rely on knowledge of the reply key to + authenticate the client MUST NOT be used. + +3.2. Strengthening Reply Key Facility + + Particularly when dealing with keys based on passwords, it is + desirable to increase the strength of the key by adding additional + secrets to it. Examples of sources of additional secrets include the + results of a Diffie-Hellman key exchange or key bits from the output + of a smart card [KRB-WG.SAM]. Typically, these additional secrets + can be first combined with the existing reply key and then converted + to a protocol key using tools defined in Section 5.1. + + Typically, a mechanism implementing this facility will know that the + other side of the exchange supports the facility before the reply key + is changed. For example, a mechanism might need to learn the + certificate for a KDC before encrypting a new key in the public key + belonging to that certificate. However, if a mechanism implementing + this facility wishes to modify the reply key before knowing that the + other party in the exchange supports the mechanism, it proposes + modifying the reply key. The other party then includes a message + indicating that the proposal is accepted if it is understood and + + + +Hartman & Zhu Standards Track [Page 13] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + meets policy. In many cases, it is desirable to use the new reply + key for client authentication and for other facilities. Waiting for + the other party to accept the proposal and actually modify the reply + key state would add an additional round trip to the exchange. + Instead, mechanism designers are encouraged to include a typed hole + for additional padata in the message that proposes the reply key + change. The padata included in the typed hole are generated assuming + the new reply key. If the other party accepts the proposal, then + these padata are considered as an inner level. As with the outer + level, one authentication set or mechanism is typically chosen for + client authentication, along with auxiliary mechanisms such as KDC + cookies, and other mechanisms are ignored. When mechanisms include + such a container, the hint provided for use in authentication sets + (as defined in Section 5.3) MUST contain a sequence of inner + mechanisms along with hints for those mechanisms. The party + generating the proposal can determine whether the padata were + processed based on whether the proposal for the reply key is + accepted. + + The specific formats of the proposal message, including where padata + are included, is a matter for the mechanism specification. + Similarly, the format of the message accepting the proposal is + mechanism specific. + + Mechanisms implementing this facility and including a typed hole for + additional padata MUST checksum that padata using a keyed checksum or + encrypt the padata. This requirement protects against modification + of the contents of the typed hole. By modifying these contents, an + attacker might be able to choose which mechanism is used to + authenticate the client, or to convince a party to provide text + encrypted in a key that the attacker had manipulated. It is + important that mechanisms strengthen the reply key enough that using + it to checksum padata is appropriate. + +3.3. Replace Reply Key Facility + + The Replace Reply Key facility replaces the key in which a successful + AS reply will be encrypted. This facility can only be used in cases + where knowledge of the reply key is not used to authenticate the + client. The new reply key MUST be communicated to the client and the + KDC in a secure manner. This facility MUST NOT be used if there can + be a man-in-the-middle between the client and the KDC. Mechanisms + implementing this facility MUST mark the reply key as replaced in the + pre-authentication state. Mechanisms implementing this facility MUST + either provide a mechanism to verify the KDC reply to the client or + mark the reply as unverified in the pre-authentication state. + Mechanisms implementing this facility SHOULD NOT be used if a + previous mechanism has used the reply key. + + + +Hartman & Zhu Standards Track [Page 14] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + As with the Strengthening Reply Key facility, Kerberos extensibility + rules require that the reply key not be changed unless both sides of + the exchange understand the extension. In the case of this facility, + it will likely be the case for both sides to know that the facility + is available by the time that the new key is available to be used. + However, mechanism designers can use a container for padata in a + proposal message, as discussed in Section 3.2, if appropriate. + +3.4. KDC Authentication Facility + + This facility verifies that the reply comes from the expected KDC. + In traditional Kerberos, the KDC and the client share a key, so if + the KDC reply can be decrypted, then the client knows that a trusted + KDC responded. Note that the client machine cannot trust the client + unless the machine is presented with a service ticket for it + (typically, the machine can retrieve this ticket by itself). + However, if the reply key is replaced, some mechanism is required to + verify the KDC. Pre-authentication mechanisms providing this + facility allow a client to determine that the expected KDC has + responded even after the reply key is replaced. They mark the pre- + authentication state as having been verified. + +4. Requirements for Pre-Authentication Mechanisms + + This section lists requirements for specifications of pre- + authentication mechanisms. + + For each message in the pre-authentication mechanism, the + specification describes the pa-type value to be used and the contents + of the message. The processing of the message by the sender and + recipient is also specified. This specification needs to include all + modifications to the pre-authentication state. + + Generally, mechanisms have a message that can be sent in the error + data of the KDC_ERR_PREAUTH_REQUIRED error message or in an + authentication set. If the client needs information, such as trusted + certificate authorities, in order to determine if it can use the + mechanism, then this information should be in that message. In + addition, such mechanisms should also define a pa-hint to be included + in authentication sets. Often, the same information included in the + padata-value is appropriate to include in the pa-hint (as defined in + Section 5.3). + + In order to ease security analysis, the mechanism specification + should describe what facilities from this document are offered by the + mechanism. For each facility, the security considerations section of + the mechanism specification should show that the security + + + + +Hartman & Zhu Standards Track [Page 15] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + requirements of that facility are met. This requirement is + applicable to any FAST factor that provides authentication + information. + + Significant problems have resulted in the specification of Kerberos + protocols because much of the KDC exchange is not protected against + alteration. The security considerations section should discuss + unauthenticated plaintext attacks. It should either show that + plaintext is protected or discuss what harm an attacker could do by + modifying the plaintext. It is generally acceptable for an attacker + to be able to cause the protocol negotiation to fail by modifying + plaintext. More significant attacks should be evaluated carefully. + + As discussed in Section 5.2, there is no guarantee that a client will + use the same KDCs for all messages in a conversation. The mechanism + specification needs to show why the mechanism is secure in this + situation. The hardest problem to deal with, especially for + challenge/response mechanisms is to make sure that the same response + cannot be replayed against two KDCs while allowing the client to talk + to any KDC. + +4.1. Protecting Requests/Responses + + Mechanism designers SHOULD protect cleartext portions of pre- + authentication data. Various denial-of-service attacks and downgrade + attacks against Kerberos are possible unless plaintexts are somehow + protected against modification. An early design goal of Kerberos + Version 5 [RFC4120] was to avoid encrypting more of the + authentication exchange than was required. (Version 4 doubly- + encrypted the encrypted part of a ticket in a KDC reply, for + example). This minimization of encryption reduces the load on the + KDC and busy servers. Also, during the initial design of Version 5, + the existence of legal restrictions on the export of cryptography + made it desirable to minimize of the number of uses of encryption in + the protocol. Unfortunately, performing this minimization created + numerous instances of unauthenticated security-relevant plaintext + fields. + + Mechanisms MUST guarantee that by the end of a successful + authentication exchange, both the client and the KDC have verified + all the plaintext sent by the other party. If there is more than one + round trip in the exchange, mechanisms MUST additionally guarantee + that no individual messages were reordered or replayed from a + previous exchange. Strategies for accomplishing this include using + message authentication codes (MACs) to protect the plaintext as it is + sent including some form of nonce or cookie to allow for the chaining + of state from one message to the next or exchanging a MAC of the + entire conversation after a key is established. + + + +Hartman & Zhu Standards Track [Page 16] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + Mechanism designers need to provide a strategy for updating + cryptographic algorithms, such as defining a new pre-authentication + type for each algorithm or taking advantage of the client's list of + supported RFC 3961 encryption types to indicate the client's support + for cryptographic algorithms. + + Primitives defined in [RFC3961] are RECOMMENDED for integrity + protection and confidentiality. Mechanisms based on these primitives + are crypto-agile as the result of using [RFC3961] along with + [RFC4120]. The advantage afforded by crypto-agility is the ability + to incrementally deploy a fix specific to a particular algorithm thus + avoid a multi-year standardization and deployment cycle, when real + attacks do arise against that algorithm. + + Note that data used by FAST factors (defined in Section 5.4) is + encrypted in a protected channel; thus, they do not share the un- + authenticated-text issues with mechanisms designed as full-blown pre- + authentication mechanisms. + +5. Tools for Use in Pre-Authentication Mechanisms + + This section describes common tools needed by multiple pre- + authentication mechanisms. By using these tools, mechanism designers + can use a modular approach to specify mechanism details and ease + security analysis. + +5.1. Combining Keys + + Frequently, a weak key needs to be combined with a stronger key + before use. For example, passwords are typically limited in size and + insufficiently random: therefore, it is desirable to increase the + strength of the keys based on passwords by adding additional secrets. + An additional source of secrecy may come from hardware tokens. + + This section provides standard ways to combine two keys into one. + + KRB-FX-CF1() is defined to combine two passphrases. + + KRB-FX-CF1(UTF-8 string, UTF-8 string) -> (UTF-8 string) + KRB-FX-CF1(x, y) := x || y + + Where || denotes concatenation. The strength of the final key is + roughly the total strength of the individual keys being combined, + assuming that the string_to_key() function [RFC3961] uses all its + input evenly. + + + + + + +Hartman & Zhu Standards Track [Page 17] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + An example usage of KRB-FX-CF1() is when a device provides random but + short passwords, the password is often combined with a personal + identification number (PIN). The password and the PIN can be + combined using KRB-FX-CF1(). + + KRB-FX-CF2() combines two protocol keys based on the pseudo-random() + function defined in [RFC3961]. + + Given two input keys, K1 and K2, where K1 and K2 can be of two + different enctypes, the output key of KRB-FX-CF2(), K3, is derived as + follows: + + KRB-FX-CF2(protocol key, protocol key, octet string, + octet string) -> (protocol key) + + PRF+(K1, pepper1) -> octet-string-1 + PRF+(K2, pepper2) -> octet-string-2 + KRB-FX-CF2(K1, K2, pepper1, pepper2) := + random-to-key(octet-string-1 ^ octet-string-2) + + Where ^ denotes the exclusive-OR operation. PRF+() is defined as + follows: + + PRF+(protocol key, octet string) -> (octet string) + + PRF+(key, shared-info) := pseudo-random( key, 1 || shared-info ) || + pseudo-random( key, 2 || shared-info ) || + pseudo-random( key, 3 || shared-info ) || ... + + Here the counter value 1, 2, 3, and so on are encoded as a one-octet + integer. The pseudo-random() operation is specified by the enctype + of the protocol key. PRF+() uses the counter to generate enough bits + as needed by the random-to-key() [RFC3961] function for the + encryption type specified for the resulting key; unneeded bits are + removed from the tail. Unless otherwise specified, the resulting + enctype of KRB-FX-CF2 is the enctype of k1. The pseudo-random() + operation is the RFC 3961 pseudo-random() operation for the + corresponding input key; the random-to-key() operation is the RFC + 3961 random-to-key operation for the resulting key. + + Mechanism designers MUST specify the values for the input parameter + pepper1 and pepper2 when combining two keys using KRB-FX-CF2(). The + pepper1 and pepper2 MUST be distinct so that if the two keys being + combined are the same, the resulting key is not a trivial key. + + + + + + + +Hartman & Zhu Standards Track [Page 18] + +RFC 6113 Kerberos Preauth Framework April 2011 + + +5.2. Managing States for the KDC + + Kerberos KDCs are stateless in that there is no requirement that + clients will choose the same KDC for the second request in a + conversation. Proxies or other intermediate nodes may also influence + KDC selection. So, each request from a client to a KDC must include + sufficient information that the KDC can regenerate any needed state. + This is accomplished by giving the client a potentially long opaque + cookie in responses to include in future requests in the same + conversation. The KDC MAY respond that a conversation is too old and + needs to restart by responding with a KDC_ERR_PREAUTH_EXPIRED error. + + KDC_ERR_PREAUTH_EXPIRED 90 + + When a client receives this error, the client SHOULD abort the + existing conversation, and restart a new one. + + An example, where more than one message from the client is needed, is + when the client is authenticated based on a challenge/response + scheme. In that case, the KDC needs to keep track of the challenge + issued for a client authentication request. + + The PA-FX-COOKIE padata type is defined in this section to facilitate + state management in the AS exchange. These padata are sent by the + KDC when the KDC requires state for a future transaction. The client + includes this opaque token in the next message in the conversation. + The token may be relatively large; clients MUST be prepared for + tokens somewhat larger than the size of all messages in a + conversation. + + PA-FX-COOKIE 133 + -- Stateless cookie that is not tied to a specific KDC. + + The corresponding padata-value field [RFC4120] contains an opaque + token that will be echoed by the client in its response to an error + from the KDC. + + The cookie token is generated by the KDC and transmitted in a PA-FX- + COOKIE pre-authentication data item of a KRB-ERROR message. The + client MUST copy the exact cookie encapsulated in a PA-FX-COOKIE data + element into the next message of the same conversation. The content + of the cookie field is a local matter of the KDC. As a result, it is + not generally possible to mix KDC implementations from different + vendors in the same realm. However, the KDC MUST construct the + cookie token in such a manner that a malicious client cannot subvert + the authentication process by manipulating the token. The KDC + implementation needs to consider expiration of tokens, key rollover, + and other security issues in token design. The content of the cookie + + + +Hartman & Zhu Standards Track [Page 19] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + field is likely specific to the pre-authentication mechanisms used to + authenticate the client. If a client authentication response can be + replayed to multiple KDCs via the PA-FX-COOKIE mechanism, an + expiration in the cookie is RECOMMENDED to prevent the response being + presented indefinitely. Implementations need to consider replay both + of an entire conversation and of messages within a conversation when + designing what information is stored in a cookie and how pre- + authentication mechanisms are implemented. + + If at least one more message for a mechanism or a mechanism set is + expected by the KDC, the KDC returns a + KDC_ERR_MORE_PREAUTH_DATA_REQUIRED error with a PA-FX-COOKIE to + identify the conversation with the client, according to Section 2.2. + The cookie is not expected to stay constant for a conversation: the + KDC is expected to generate a new cookie for each message. + + KDC_ERR_MORE_PREAUTH_DATA_REQUIRED 91 + + A client MAY throw away the state associated with a conversation and + begin a new conversation by discarding its state and not including a + cookie in the first message of a conversation. KDCs that comply with + this specification MUST include a cookie in a response when the + client can continue the conversation. In particular, a KDC MUST + include a cookie in a KDC_ERR_PREAUTH_REQUIRED or + KDC_ERR_MORE_PREAUTH_DATA_REQUIRED. KDCs SHOULD include a cookie in + errors containing additional information allowing a client to retry. + One reasonable strategy for meeting these requirements is to always + include a cookie in KDC errors. + + A KDC MAY indicate that it is terminating a conversation by not + including a cookie in a response. When FAST is used, clients can + assume that the absence of a cookie means that the KDC is ending the + conversation. Similarly, if a cookie is seen at all during a + conversation, clients MAY assume that the absence of a cookie in a + future message means that the KDC is ending the conversation. + Clients also need to deal with KDCs, prior to this specification, + that do not include cookies; if neither cookies nor FAST are used in + a conversation, the absence of a cookie is not a strong indication + that the KDC is terminating the conversation. + +5.3. Pre-Authentication Set + + If all mechanisms in a group need to successfully complete in order + to authenticate a client, the client and the KDC SHOULD use the PA- + AUTHENTICATION-SET padata element. + + PA-AUTHENTICATION-SET 134 + + + + +Hartman & Zhu Standards Track [Page 20] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + A PA-AUTHENTICATION-SET padata element contains the ASN.1 DER + encoding of the PA-AUTHENTICATION-SET structure: + + PA-AUTHENTICATION-SET ::= SEQUENCE OF PA-AUTHENTICATION-SET-ELEM + + PA-AUTHENTICATION-SET-ELEM ::= SEQUENCE { + pa-type [0] Int32, + -- same as padata-type. + pa-hint [1] OCTET STRING OPTIONAL, + pa-value [2] OCTET STRING OPTIONAL, + ... + } + + The pa-type field of the PA-AUTHENTICATION-SET-ELEM structure + contains the corresponding value of padata-type in PA-DATA [RFC4120]. + Associated with the pa-type is a pa-hint, which is an octet string + specified by the pre-authentication mechanism. This hint may provide + information for the client that helps it determine whether the + mechanism can be used. For example, a public-key mechanism might + include the certificate authorities it trusts in the hint info. Most + mechanisms today do not specify hint info; if a mechanism does not + specify hint info, the KDC MUST NOT send a hint for that mechanism. + To allow future revisions of mechanism specifications to add hint + info, clients MUST ignore hint info received for mechanisms that the + client believes do not support hint info. The pa-value element of + the PA-AUTHENTICATION-SET-ELEM sequence is included to carry the + first padata-value from the KDC to the client. If the client chooses + this authentication set, then the client MUST process this pa-value. + The pa-value element MUST be absent for all but the first entry in + the authentication set. Clients MUST ignore the pa-value for the + second and following entries in the authentication set. + + If the client chooses an authentication set, then its first AS-REQ + message MUST contain a PA-AUTH-SET-SELECTED padata element. This + element contains the encoding of the PA-AUTHENTICATION-SET sequence + received from the KDC corresponding to the authentication set that is + chosen. The client MUST use the same octet values received from the + KDC; it cannot re-encode the sequence. This allows KDCs to use bit- + wise comparison to identify the selected authentication set. + Permitting bit-wise comparison may limit the ability to use certain + pre-authentication mechanisms that generate a dynamic challenge in an + authentication set with optimistic selection of an authentication + set. As with other optimistic pre-authentication failures, the KDC + MAY return KDC_ERR_PREAUTH_FAILED with a new list of pre- + authentication mechanisms (including authentication sets) if + optimistic pre-authentication fails. The PA-AUTH-SET-SELECTED padata + element MUST come before any padata elements from the authentication + set in the padata sequence in the AS-REQ message. The client MAY + + + +Hartman & Zhu Standards Track [Page 21] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + cache authentication sets from prior messages and use them to + construct an optimistic initial AS-REQ. If the KDC receives a PA- + AUTH-SET-SELECTED padata element that does not correspond to an + authentication set that it would offer, then the KDC returns the + KDC_ERR_PREAUTH_BAD_AUTHENTICATION_SET error. The e-data in this + error contains a sequence of padata just as for the + KDC_ERR_PREAUTH_REQUIRED error. + + PA-AUTH-SET-SELECTED 135 + KDC_ERR_PREAUTH_BAD_AUTHENTICATION_SET 92 + + The PA-AUTHENTICATION-SET appears only in the first message from the + KDC to the client. In particular, the client MAY fail if the + authentication mechanism sets change as the conversation progresses. + Clients MAY assume that the hints provided in the authentication set + contain enough information that the client knows what user interface + elements need to be displayed during the entire authentication + conversation. Exceptional circumstances, such as expired passwords + or expired accounts, may require that additional user interface be + displayed. Mechanism designers need to carefully consider the design + of their hints so that the client has this information. This way, + clients can construct necessary dialogue boxes or wizards based on + the authentication set and can present a coherent user interface. + Current standards for user interfaces do not provide an acceptable + experience when the client has to ask additional questions later in + the conversation. + + When indicating which sets of pre-authentication mechanisms are + supported, the KDC includes a PA-AUTHENTICATION-SET padata element + for each pre-authentication mechanism set. + + The client sends the padata-value for the first mechanism it picks in + the pre-authentication set, when the first mechanism completes, the + client and the KDC will proceed with the second mechanism, and so on + until all mechanisms complete successfully. The PA-FX-COOKIE, as + defined in Section 5.2, MUST be sent by the KDC. One reason for this + requirement is so that the conversation can continue if the + conversation involves multiple KDCs. KDCs MUST support clients that + do not include a cookie because they optimistically choose an + authentication set, although they MAY always return a + KDC_ERR_PREAUTH_BAD_AUTHENTICATION_SET and include a cookie in that + message. Clients that support PA-AUTHENTICATION-SET MUST support PA- + FX-COOKIE. + + Before the authentication succeeds and a ticket is returned, the + message that the client sends is an AS-REQ and the message that the + KDC sends is a KRB-ERROR message. The error code in the KRB-ERROR + message from the KDC is KDC_ERR_MORE_PREAUTH_DATA_REQUIRED as defined + + + +Hartman & Zhu Standards Track [Page 22] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + in Section 5.2 and the accompanying e-data contains the DER encoding + of ASN.1 type METHOD-DATA. The KDC includes the padata elements in + the METHOD-DATA. If there are no padata, the e-data field is absent + in the KRB-ERROR message. + + If the client sends the last message for a given mechanism, then the + KDC sends the first message for the next mechanism. If the next + mechanism does not start with a KDC-side challenge, then the KDC + includes a padata item with the appropriate pa-type and an empty pa- + data. + + If the KDC sends the last message for a particular mechanism, the KDC + also includes the first padata for the next mechanism. + +5.4. Definition of Kerberos FAST Padata + + As described in [RFC4120], Kerberos is vulnerable to offline + dictionary attacks. An attacker can request an AS-REP and try + various passwords to see if they can decrypt the resulting ticket. + RFC 4120 provides the encrypted timestamp pre-authentication method + that ameliorates the situation somewhat by requiring that an attacker + observe a successful authentication. However, stronger security is + desired in many environments. The Kerberos FAST pre-authentication + padata defined in this section provides a tool to significantly + reduce vulnerability to offline dictionary attacks. When combined + with encrypted challenge, FAST requires an attacker to mount a + successful man-in-the-middle attack to observe ciphertext. When + combined with host keys, FAST can even protect against active + attacks. FAST also provides solutions to common problems for pre- + authentication mechanisms such as binding of the request and the + reply and freshness guarantee of the authentication. FAST itself, + however, does not authenticate the client or the KDC; instead, it + provides a typed hole to allow pre-authentication data be tunneled. + A pre-authentication data element used within FAST is called a "FAST + factor". A FAST factor captures the minimal work required for + extending Kerberos to support a new pre-authentication scheme. + + A FAST factor MUST NOT be used outside of FAST unless its + specification explicitly allows so. The typed holes in FAST messages + can also be used as generic holes for other padata that are not + intended to prove the client's identity, or establish the reply key. + + New pre-authentication mechanisms SHOULD be designed as FAST factors, + instead of full-blown pre-authentication mechanisms. + + FAST factors that are pre-authentication mechanisms MUST meet the + requirements in Section 4. + + + + +Hartman & Zhu Standards Track [Page 23] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + FAST employs an armoring scheme. The armor can be a Ticket Granting + Ticket (TGT) obtained by the client's machine using the host keys to + pre-authenticate with the KDC, or an anonymous TGT obtained based on + anonymous PKINIT [RFC6112] [RFC4556]. + + The rest of this section describes the types of armors and the syntax + of the messages used by FAST. Conforming implementations MUST + support Kerberos FAST padata. + + Any FAST armor scheme MUST provide a fresh armor key for each + conversation. Clients and KDCs can assume that if a message is + encrypted and integrity protected with a given armor key, then it is + part of the conversation using that armor key. + + All KDCs in a realm MUST support FAST if FAST is offered by any KDC + as a pre-authentication mechanism. + +5.4.1. FAST Armors + + An armor key is used to encrypt pre-authentication data in the FAST + request and the response. The KrbFastArmor structure is defined to + identify the armor key. This structure contains the following two + fields: the armor-type identifies the type of armors and the armor- + value is an OCTET STRING that contains the description of the armor + scheme and the armor key. + + KrbFastArmor ::= SEQUENCE { + armor-type [0] Int32, + -- Type of the armor. + armor-value [1] OCTET STRING, + -- Value of the armor. + ... + } + + The value of the armor key is a matter of the armor type + specification. Only one armor type is defined in this document. + + FX_FAST_ARMOR_AP_REQUEST 1 + + The FX_FAST_ARMOR_AP_REQUEST armor is based on Kerberos tickets. + + Conforming implementations MUST implement the + FX_FAST_ARMOR_AP_REQUEST armor type. If a FAST KDC receives an + unknown armor type it MUST respond with KDC_ERR_PREAUTH_FAILED. + + An armor type may be appropriate for use in armoring AS requests, + armoring TGS requests, or both. TGS armor types MUST authenticate + the client to the KDC, typically by binding the TGT sub-session key + + + +Hartman & Zhu Standards Track [Page 24] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + to the armor key. As discussed below, it is desirable for AS armor + types to authenticate the KDC to the client, but this is not + required. + + FAST implementations MUST maintain state about whether the armor + mechanism authenticates the KDC. If it does not, then a FAST factor + that authenticates the KDC MUST be used if the reply key is replaced. + +5.4.1.1. Ticket-Based Armors + + This is a ticket-based armoring scheme. The armor-type is + FX_FAST_ARMOR_AP_REQUEST, the armor-value contains an ASN.1 DER + encoded AP-REQ. The ticket in the AP-REQ is called an armor ticket + or an armor TGT. The subkey field in the AP-REQ MUST be present. + The armor key is defined by the following function: + + armor_key = KRB-FX-CF2( subkey, ticket_session_key, + "subkeyarmor", "ticketarmor" ) + + The 'ticket_session_key' is the session key from the ticket in the + ap-req. The 'subkey' is the ap-req subkey. This construction + guarantees that both the KDC (through the session key) and the client + (through the subkey) contribute to the armor key. + + The server name field of the armor ticket MUST identify the TGS of + the target realm. Here are three common ways in the decreasing + preference order how an armor TGT SHOULD be obtained: + + 1. If the client is authenticating from a host machine whose + Kerberos realm has an authentication path to the client's realm, + the host machine obtains a TGT by using the host keys. If the + client's realm is different than the realm of the local host, the + machine then obtains a cross-realm TGT to the client's realm as + the armor ticket. Otherwise, the host's primary TGT is the armor + ticket. + + 2. If the client's host machine cannot obtain a host ticket strictly + based on RFC 4120, but the KDC has an asymmetric signing key + whose binding with the expected KDC can be verified by the + client, the client can use anonymous PKINIT [RFC6112] [RFC4556] + to authenticate the KDC and obtain an anonymous TGT as the armor + ticket. The armor ticket can also be a cross-realm TGT obtained + based on the initial primary TGT obtained using anonymous PKINIT + with KDC authentication. + + 3. Otherwise, the client uses anonymous PKINIT to get an anonymous + TGT without KDC authentication and that TGT is the armor ticket. + Note that this mode of operation is vulnerable to man-in-the- + + + +Hartman & Zhu Standards Track [Page 25] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + middle attacks at the time of obtaining the initial anonymous + armor TGT. + + If anonymous PKINIT is used to obtain the armor ticket, the KDC + cannot know whether its signing key can be verified by the client; + hence, the KDC MUST be marked as unverified from the KDC's point of + view while the client could be able to authenticate the KDC by + verifying the KDC's signing key is bound with the expected KDC. The + client needs to carefully consider the risk and benefit tradeoffs + associated with active attacks before exposing cipher text encrypted + using the user's long-term secrets when the armor does not + authenticate the KDC. + + The TGS MUST reject a request if there is an AD-fx-fast-armor (71) + element in the authenticator of the pa-tgs-req padata or if the + ticket in the authenticator of a pa-tgs-req contains the AD-fx-fast- + armor authorization data element. These tickets and authenticators + MAY be used as FAST armor tickets but not to obtain a ticket via the + TGS. This authorization data is used in a system where the + encryption of the user's pre-authentication data is performed in an + unprivileged user process. A privileged process can provide to the + user process a host ticket, an authenticator for use with that + ticket, and the sub-session key contained in the authenticator. In + order for the host process to ensure that the host ticket is not + accidentally or intentionally misused, (i.e., the user process might + use the host ticket to authenticate as the host), it MUST include a + critical authorization data element of the type AD-fx-fast-armor when + providing the authenticator or in the enc-authorization-data field of + the TGS request used to obtain the TGT. The corresponding ad-data + field of the AD-fx-fast-armor element is empty. + + This armor type is only valid for AS requests; implicit armor, + described below in TGS processing, is the only supported way to + establish an armor key for the TGS at this time. + +5.4.2. FAST Request + + A padata type PA-FX-FAST is defined for the Kerberos FAST pre- + authentication padata. The corresponding padata-value field + [RFC4120] contains the DER encoding of the ASN.1 type PA-FX-FAST- + REQUEST. As with all pre-authentication types, the KDC SHOULD + advertise PA-FX-FAST in a PREAUTH_REQUIRED error. KDCs MUST send the + advertisement of PA-FX-FAST with an empty pa-value. Clients MUST + ignore the pa-value of PA-FX-FAST in an initial PREAUTH_REQUIRED + error. FAST is not expected to be used in an authentication set: + clients will typically use FAST padata if available and this decision + should not depend on what other pre-authentication methods are + available. As such, no pa-hint is defined for FAST at this time. + + + +Hartman & Zhu Standards Track [Page 26] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + PA-FX-FAST 136 + -- Padata type for Kerberos FAST + + PA-FX-FAST-REQUEST ::= CHOICE { + armored-data [0] KrbFastArmoredReq, + ... + } + + KrbFastArmoredReq ::= SEQUENCE { + armor [0] KrbFastArmor OPTIONAL, + -- Contains the armor that identifies the armor key. + -- MUST be present in AS-REQ. + req-checksum [1] Checksum, + -- For AS, contains the checksum performed over the type + -- KDC-REQ-BODY for the req-body field of the KDC-REQ + -- structure; + -- For TGS, contains the checksum performed over the type + -- AP-REQ in the PA-TGS-REQ padata. + -- The checksum key is the armor key, the checksum + -- type is the required checksum type for the enctype of + -- the armor key, and the key usage number is + -- KEY_USAGE_FAST_REQ_CHKSUM. + enc-fast-req [2] EncryptedData, -- KrbFastReq -- + -- The encryption key is the armor key, and the key usage + -- number is KEY_USAGE_FAST_ENC. + ... + } + + KEY_USAGE_FAST_REQ_CHKSUM 50 + KEY_USAGE_FAST_ENC 51 + + The PA-FX-FAST-REQUEST structure contains a KrbFastArmoredReq type. + The KrbFastArmoredReq encapsulates the encrypted padata. + + The enc-fast-req field contains an encrypted KrbFastReq structure. + The armor key is used to encrypt the KrbFastReq structure, and the + key usage number for that encryption is KEY_USAGE_FAST_ENC. + + The armor key is selected as follows: + + o In an AS request, the armor field in the KrbFastArmoredReq + structure MUST be present and the armor key is identified + according to the specification of the armor type. + + + + + + + + +Hartman & Zhu Standards Track [Page 27] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + o There are two possibilities for armor for a TGS request. If the + ticket presented in the PA-TGS-REQ authenticator is a TGT, then + the client SHOULD NOT include the armor field in the Krbfastreq + and a subkey MUST be included in the PA-TGS-REQ authenticator. In + this case, the armor key is the same armor key that would be + computed if the TGS-REQ authenticator was used in an + FX_FAST_ARMOR_AP_REQUEST armor. Clients MAY present a non-TGT in + the PA-TGS-REQ authenticator and omit the armor field, in which + case the armor key is the same that would be computed if the + authenticator were used in an FX_FAST_ARMOR_AP_REQUEST armor. + This is the only case where a ticket other than a TGT can be used + to establish an armor key; even though the armor key is computed + the same as an FX_FAST_ARMOR_AP_REQUEST, a non-TGT cannot be used + as an armor ticket in FX_FAST_ARMOR_AP_REQUEST. Alternatively, a + client MAY use an armor type defined in the future for use with + the TGS request. + + The req-checksum field contains a checksum computed differently for + AS and TGS. For an AS-REQ, it is performed over the type KDC-REQ- + BODY for the req-body field of the KDC-REQ structure of the + containing message; for a TGS-REQ, it is performed over the type AP- + REQ in the PA-TGS-REQ padata of the TGS request. The checksum key is + the armor key, and the checksum type is the required checksum type + for the enctype of the armor key per [RFC3961]. This checksum MUST + be a keyed checksum and it is included in order to bind the FAST + padata to the outer request. A KDC that implements FAST will ignore + the outer request, but including a checksum is relatively cheap and + may prevent confusing behavior. + + The KrbFastReq structure contains the following information: + + KrbFastReq ::= SEQUENCE { + fast-options [0] FastOptions, + -- Additional options. + padata [1] SEQUENCE OF PA-DATA, + -- padata typed holes. + req-body [2] KDC-REQ-BODY, + -- Contains the KDC request body as defined in Section + -- 5.4.1 of [RFC4120]. + -- This req-body field is preferred over the outer field + -- in the KDC request. + ... + } + + + + + + + + +Hartman & Zhu Standards Track [Page 28] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + The fast-options field indicates various options that are to modify + the behavior of the KDC. The following options are defined: + + FastOptions ::= KerberosFlags + -- reserved(0), + -- hide-client-names(1), + + Bits Name Description + ----------------------------------------------------------------- + 0 RESERVED Reserved for future expansion of this + field. + 1 hide-client-names Requesting the KDC to hide client + names in the KDC response, as + described next in this section. + 16 kdc-follow-referrals reserved [REFERRALS]. + + Bits 1 through 15 inclusive (with bit 1 and bit 15 included) are + critical options. If the KDC does not support a critical option, it + MUST fail the request with KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS, and + there is no accompanying e-data defined in this document for this + error code. Bit 16 and onward (with bit 16 included) are non- + critical options. KDCs conforming to this specification ignore + unknown non-critical options. + + KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS 93 + + The hide-client-names Option + + The Kerberos response defined in [RFC4120] contains the client + identity in cleartext. This makes traffic analysis + straightforward. The hide-client-names option is designed to + complicate traffic analysis. If the hide-client-names option is + set, the KDC implementing PA-FX-FAST MUST identify the client as + the anonymous principal [RFC6112] in the KDC reply and the error + response. Hence, this option is set by the client if it wishes to + conceal the client identity in the KDC response. A conforming KDC + ignores the client principal name in the outer KDC-REQ-BODY field, + and identifies the client using the cname and crealm fields in the + req-body field of the KrbFastReq structure. + + The kdc-follow-referrals Option + + This option is reserved for [REFERRALS]. + + + + + + + + +Hartman & Zhu Standards Track [Page 29] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + The padata field contains a list of PA-DATA structures as described + in Section 5.2.7 of [RFC4120]. These PA-DATA structures can contain + FAST factors. They can also be used as generic typed-holes to + contain data not intended for proving the client's identity or + establishing a reply key, but for protocol extensibility. If the KDC + supports the PA-FX-FAST-REQUEST padata, unless otherwise specified, + the client MUST place any padata that is otherwise in the outer KDC + request body into this field. In a TGS request, PA-TGS-REQ padata is + not included in this field and it is present in the outer KDC request + body. + + The KDC-REQ-BODY in the FAST structure is used in preference to the + KDC-REQ-BODY outside of the FAST pre-authentication. The outer KDC- + REQ-BODY structure SHOULD be filled in for backwards compatibility + with KDCs that do not support FAST. A conforming KDC ignores the + outer KDC-REQ-BODY field in the KDC request. Pre-authentication data + methods such as [RFC4556] that include a checksum of the KDC-REQ-BODY + should checksum the KDC-REQ-BODY in the FAST structure. + + In a TGS request, a client MAY include the AD-fx-fast-used authdata + either in the pa-tgs-req authenticator or in the authorization data + in the pa-tgs-req ticket. If the KDC receives this authorization + data but does not find a FAST padata, then it MUST return + KRB_APP_ERR_MODIFIED. + +5.4.3. FAST Response + + The KDC that supports the PA-FX-FAST padata MUST include a PA-FX-FAST + padata element in the KDC reply. In the case of an error, the PA-FX- + FAST padata is included in the KDC responses according to + Section 5.4.4. + + The corresponding padata-value field [RFC4120] for the PA-FX-FAST in + the KDC response contains the DER encoding of the ASN.1 type PA-FX- + FAST-REPLY. + + PA-FX-FAST-REPLY ::= CHOICE { + armored-data [0] KrbFastArmoredRep, + ... + } + + KrbFastArmoredRep ::= SEQUENCE { + enc-fast-rep [0] EncryptedData, -- KrbFastResponse -- + -- The encryption key is the armor key in the request, and + -- the key usage number is KEY_USAGE_FAST_REP. + ... + } + KEY_USAGE_FAST_REP 52 + + + +Hartman & Zhu Standards Track [Page 30] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + The PA-FX-FAST-REPLY structure contains a KrbFastArmoredRep + structure. The KrbFastArmoredRep structure encapsulates the padata + in the KDC reply in the encrypted form. The KrbFastResponse is + encrypted with the armor key used in the corresponding request, and + the key usage number is KEY_USAGE_FAST_REP. + + The Kerberos client MUST support a local policy that rejects the + response if PA-FX-FAST-REPLY is not included in the response. + Clients MAY also support policies that fall back to other mechanisms + or that do not use pre-authentication when FAST is unavailable. It + is important to consider the potential downgrade attacks when + deploying such a policy. + + The KrbFastResponse structure contains the following information: + + KrbFastResponse ::= SEQUENCE { + padata [0] SEQUENCE OF PA-DATA, + -- padata typed holes. + strengthen-key [1] EncryptionKey OPTIONAL, + -- This, if present, strengthens the reply key for AS and + -- TGS. MUST be present for TGS. + -- MUST be absent in KRB-ERROR. + finished [2] KrbFastFinished OPTIONAL, + -- Present in AS or TGS reply; absent otherwise. + nonce [3] UInt32, + -- Nonce from the client request. + ... + } + + The padata field in the KrbFastResponse structure contains a list of + PA-DATA structures as described in Section 5.2.7 of [RFC4120]. These + PA-DATA structures are used to carry data advancing the exchange + specific for the FAST factors. They can also be used as generic + typed-holes for protocol extensibility. Unless otherwise specified, + the KDC MUST include any padata that are otherwise in the outer KDC- + REP or KDC-ERROR structure into this field. The padata field in the + KDC reply structure outside of the PA-FX-FAST-REPLY structure + typically includes only the PA-FX-FAST-REPLY padata. + + The strengthen-key field provides a mechanism for the KDC to + strengthen the reply key. If set, the strengthen-key value MUST be + randomly generated to have the same etype as that of the reply key + before being strengthened, and then the reply key is strengthened + after all padata items are processed. Let padata-reply-key be the + reply key after padata processing. + + reply-key = KRB-FX-CF2(strengthen-key, padata-reply-key, + "strengthenkey", "replykey") + + + +Hartman & Zhu Standards Track [Page 31] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + The strengthen-key field MAY be set in an AS reply; it MUST be set in + a TGS reply; it must be absent in an error reply. The strengthen key + is required in a TGS reply so that an attacker cannot remove the FAST + PADATA from a TGS reply, causing the KDC to appear not to support + FAST. + + The finished field contains a KrbFastFinished structure. It is + filled by the KDC in the final message in the conversation. This + field is present in an AS-REP or a TGS-REP when a ticket is returned, + and it is not present in an error reply. + + The KrbFastFinished structure contains the following information: + + KrbFastFinished ::= SEQUENCE { + timestamp [0] KerberosTime, + usec [1] Microseconds, + -- timestamp and usec represent the time on the KDC when + -- the reply was generated. + crealm [2] Realm, + cname [3] PrincipalName, + -- Contains the client realm and the client name. + ticket-checksum [4] Checksum, + -- checksum of the ticket in the KDC-REP using the armor + -- and the key usage is KEY_USAGE_FAST_FINISH. + -- The checksum type is the required checksum type + -- of the armor key. + ... + } + KEY_USAGE_FAST_FINISHED 53 + + The timestamp and usec fields represent the time on the KDC when the + reply ticket was generated, these fields have the same semantics as + the corresponding identically named fields in Section 5.6.1 of + [RFC4120]. The client MUST use the KDC's time in these fields + thereafter when using the returned ticket. The client need not + confirm that the timestamp returned is within allowable clock skew: + the armor key guarantees that the reply is fresh. The client MAY + trust the timestamp returned. + + The cname and crealm fields identify the authenticated client. If + facilities described in [REFERRALS] are used, the authenticated + client may differ from the client in the FAST request. + + The ticket-checksum is a checksum of the issued ticket. The checksum + key is the armor key, and the checksum type is the required checksum + type of the enctype of that key, and the key usage number is + KEY_USAGE_FAST_FINISHED. + + + + +Hartman & Zhu Standards Track [Page 32] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + When FAST padata is included, the PA-FX-COOKIE padata as defined in + Section 5.2 MUST be included in the padata sequence in the + KrbFastResponse sequence if the KDC expects at least one more message + from the client in order to complete the authentication. + + The nonce field in the KrbFastResponse contains the value of the + nonce field in the KDC-REQ of the corresponding client request and it + binds the KDC response with the client request. The client MUST + verify that this nonce value in the reply matches with that of the + request and reject the KDC reply otherwise. To prevent the response + from one message in a conversation from being replayed to a request + in another message, clients SHOULD use a new nonce for each message + in a conversation. + +5.4.4. Authenticated Kerberos Error Messages Using Kerberos FAST + + If the Kerberos FAST padata was included in the request, unless + otherwise specified, the e-data field of the KRB-ERROR message + [RFC4120] contains the ASN.1 DER encoding of the type METHOD-DATA + [RFC4120] and a PA-FX-FAST is included in the METHOD-DATA. The KDC + MUST include all the padata elements such as PA-ETYPE-INFO2 and + padata elements that indicate acceptable pre-authentication + mechanisms [RFC4120] in the KrbFastResponse structure. + + The KDC MUST also include a PA-FX-ERROR padata item in the + KRBFastResponse structure. The padata-value element of this sequence + is the ASN.1 DER encoding of the type KRB-ERROR. The e-data field + MUST be absent in the PA-FX-ERROR padata. All other fields should be + the same as the outer KRB-ERROR. The client ignores the outer error + and uses the combination of the padata in the KRBFastResponse and the + error information in the PA-FX-ERROR. + + PA-FX-ERROR 137 + + If the Kerberos FAST padata is included in the request but not + included in the error reply, it is a matter of the local policy on + the client to accept the information in the error message without + integrity protection. However, the client SHOULD process the KDC + errors as the result of the KDC's inability to accept the AP_REQ + armor and potentially retry another request with a different armor + when applicable. The Kerberos client MAY process an error message + without a PA-FX-FAST-REPLY, if that is only intended to return better + error information to the application, typically for trouble-shooting + purposes. + + In the cases where the e-data field of the KRB-ERROR message is + expected to carry a TYPED-DATA [RFC4120] element, that information + should be transmitted in a pa-data element within the KRBFastResponse + + + +Hartman & Zhu Standards Track [Page 33] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + structure. The padata-type is the same as the data-type would be in + the typed data element and the padata-value is the same as the data- + value. As discussed in Section 7, data-types and padata-types are + drawn from the same namespace. For example, the + TD_TRUSTED_CERTIFIERS structure is expected to be in the KRB-ERROR + message when the error code is KDC_ERR_CANT_VERIFY_CERTIFICATE + [RFC4556]. + +5.4.5. Outer and Inner Requests + + Typically, a client will know that FAST is being used before a + request containing PA-FX-FAST is sent. So, the outer AS request + typically only includes one pa-data item: PA-FX-FAST. The client MAY + include additional pa-data, but the KDC MUST ignore the outer request + body and any padata besides PA-FX-FAST if and only if PA-FX-FAST is + processed. In the case of the TGS request, the outer request should + include PA-FX-FAST and PA-TGS-REQ. + + When an AS generates a response, all padata besides PA-FX-FAST should + be included in PA-FX-FAST. The client MUST ignore other padata + outside of PA-FX-FAST. + +5.4.6. The Encrypted Challenge FAST Factor + + The encrypted challenge FAST factor authenticates a client using the + client's long-term key. This factor works similarly to the encrypted + timestamp pre-authentication option described in [RFC4120]. The word + "challenge" is used instead of "timestamp" because while the + timestamp is used as an initial challenge, if the KDC and client do + not have synchronized time, then the KDC can provide updated time to + the client to use as a challenge. The client encrypts a structure + containing a timestamp in the challenge key. The challenge key used + by the client to send a message to the KDC is KRB-FX- + CF2(armor_key,long_term_key, "clientchallengearmor", + "challengelongterm"). The challenge key used by the KDC encrypting + to the client is KRB-FX-CF2(armor_key, long_term_key, + "kdcchallengearmor", "challengelongterm"). Because the armor key is + fresh and random, the challenge key is fresh and random. The only + purpose of the timestamp is to limit the validity of the + authentication so that a request cannot be replayed. A client MAY + base the timestamp on the KDC time in a KDC error and need not + maintain accurate time synchronization itself. If a client bases its + time on an untrusted source, an attacker may trick the client into + producing an authentication request that is valid at some future + time. The attacker may be able to use this authentication request to + make it appear that a client has authenticated at that future time. + If ticket-based armor is used, then the lifetime of the ticket will + limit the window in which an attacker can make the client appear to + + + +Hartman & Zhu Standards Track [Page 34] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + have authenticated. For many situations, the ability of an attacker + to cause a client to appear to have authenticated is not a + significant concern; the ability to avoid requiring time + synchronization on clients is more valuable. + + The client sends a padata of type PA-ENCRYPTED-CHALLENGE. The + corresponding padata-value contains the DER encoding of ASN.1 type + EncryptedChallenge. + + EncryptedChallenge ::= EncryptedData + -- Encrypted PA-ENC-TS-ENC, encrypted in the challenge key + -- using key usage KEY_USAGE_ENC_CHALLENGE_CLIENT for the + -- client and KEY_USAGE_ENC_CHALLENGE_KDC for the KDC. + + PA-ENCRYPTED-CHALLENGE 138 + KEY_USAGE_ENC_CHALLENGE_CLIENT 54 + KEY_USAGE_ENC_CHALLENGE_KDC 55 + + The client includes some timestamp reasonably close to the KDC's + current time and encrypts it in the challenge key in a PA-ENC-TS-ENC + structure (see Section 5.2.7.2 in RFC 4120). Clients MAY use the + current time; doing so prevents the exposure where an attacker can + cause a client to appear to authenticate in the future. The client + sends the request including this factor. + + On receiving an AS-REQ containing the PA-ENCRYPTED-CHALLENGE FAST + factor, the KDC decrypts the timestamp. If the decryption fails the + KDC SHOULD return KDC_ERR_PREAUTH_FAILED, including PA-ETYPE-INFO2 in + the KRBFastResponse in the error. The KDC confirms that the + timestamp falls within its current clock skew returning + KRB_APP_ERR_SKEW if not. The KDC then SHOULD check to see if the + encrypted challenge is a replay. The KDC MUST NOT consider two + encrypted challenges replays simply because the timestamps are the + same; to be a replay, the ciphertext MUST be identical. Allowing + clients to reuse timestamps avoids requiring that clients maintain + state about which timestamps have been used. + + If the KDC accepts the encrypted challenge, it MUST include a padata + element of type PA-ENCRYPTED-CHALLENGE. The KDC encrypts its current + time in the challenge key. The KDC MUST strengthen the reply key + before issuing a ticket. The client MUST check that the timestamp + decrypts properly. The client MAY check that the timestamp is within + the window of acceptable clock skew for the client. The client MUST + NOT require that the timestamp be identical to the timestamp in the + issued credentials or the returned message. + + + + + + +Hartman & Zhu Standards Track [Page 35] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + The encrypted challenge FAST factor provides the following + facilities: Client Authentication and KDC Authentication. This FAST + factor also takes advantage of the FAST facility to strengthen the + reply key. It does not provide the Replace Reply Key facility. The + Security Considerations section of this document provides an + explanation why the security requirements are met. + + The encrypted challenge FAST factor can be useful in an + authentication set. No pa-hint is defined because the only + information needed by this mechanism is information contained in the + PA-ETYPE-INFO2 pre-authentication data. KDCs are already required to + send PA-ETYPE-INFO2. If KDCs were not required to send PA-ETYPE- + INFO2 then that information would need to be part of a hint for + encrypted challenge. + + Conforming implementations MUST support the encrypted challenge FAST + factor. + +5.5. Authentication Strength Indication + + Implementations that have pre-authentication mechanisms offering + significantly different strengths of client authentication MAY choose + to keep track of the strength of the authentication used as an input + into policy decisions. For example, some principals might require + strong pre-authentication, while less sensitive principals can use + relatively weak forms of pre-authentication like encrypted timestamp. + + An AuthorizationData data type AD-Authentication-Strength is defined + for this purpose. + + AD-authentication-strength 70 + + The corresponding ad-data field contains the DER encoding of the pre- + authentication data set as defined in Section 5.3. This set contains + all the pre-authentication mechanisms that were used to authenticate + the client. If only one pre-authentication mechanism was used to + authenticate the client, the pre-authentication set contains one + element. Unless otherwise specified, the hint and value fields of + the members of this sequence MUST be empty. In order to permit + mechanisms to carry additional information about strength in these + fields in the future, clients and application servers MUST ignore + non-empty hint and value fields for mechanisms unless the + implementation is updated with the interpretation of these fields for + a given pre-authentication mechanism in this authorization element. + + The AD-authentication-strength element MUST be included in the AD- + KDC-ISSUED container so that the KDC integrity protects its contents. + This element can be ignored if it is unknown to the receiver. + + + +Hartman & Zhu Standards Track [Page 36] + +RFC 6113 Kerberos Preauth Framework April 2011 + + +6. Assigned Constants + + The pre-authentication framework and FAST involve using a number of + Kerberos protocol constants. This section lists protocol constants + first introduced in this specification drawn from registries not + managed by IANA. Many of these registries would best be managed by + IANA; that is a known issue that is out of scope for this document. + The constants described in this section have been accounted for and + will appear in the next revision of the Kerberos core specification + or in a document creating IANA registries. + + Section 7 creates IANA registries for a different set of constants + used by the extensions described in this document. + +6.1. New Errors + + KDC_ERR_PREAUTH_EXPIRED 90 + KDC_ERR_MORE_PREAUTH_DATA_REQUIRED 91 + KDC_ERR_PREAUTH_BAD_AUTHENTICATION_SET 92 + KDC_ERR_UNKNOWN_CRITICAL_FAST_OPTIONS 93 + +6.2. Key Usage Numbers + + KEY_USAGE_FAST_REQ_CHKSUM 50 + KEY_USAGE_FAST_ENC 51 + KEY_USAGE_FAST_REP 52 + KEY_USAGE_FAST_FINISHED 53 + KEY_USAGE_ENC_CHALLENGE_CLIENT 54 + KEY_USAGE_ENC_CHALLENGE_KDC 55 + +6.3. Authorization Data Elements + + AD-authentication-strength 70 + AD-fx-fast-armor 71 + AD-fx-fast-used 72 + +6.4. New PA-DATA Types + + PA-FX-COOKIE 133 + PA-AUTHENTICATION-SET 134 + PA-AUTH-SET-SELECTED 135 + PA-FX-FAST 136 + PA-FX-ERROR 137 + PA-ENCRYPTED-CHALLENGE 138 + + + + + + + +Hartman & Zhu Standards Track [Page 37] + +RFC 6113 Kerberos Preauth Framework April 2011 + + +7. IANA Considerations + + This document creates a number of IANA registries. These registries + are all located under Kerberos Parameters on http://www.iana.org. + See [RFC5226] for descriptions of the registration policies used in + this section. + +7.1. Pre-Authentication and Typed Data + + RFC 4120 defines pre-authentication data, which can be included in a + KDC request or response in order to authenticate the client or extend + the protocol. In addition, it defines Typed-Data, which is an + extension mechanism for errors. Both pre-authentication data and + typed data are carried as a 32-bit signed integer along with an octet + string. The encoding of typed data and pre-authentication data is + slightly different. However, the types for pre-authentication data + and typed-data are drawn from the same namespace. By convention, + registrations starting with TD- are typed data and registrations + starting with PA- are pre-authentication data. It is important that + these data types be drawn from the same namespace, because some + errors where it would be desirable to include typed data require the + e-data field to be formatted as pre-authentication data. + + When Kerberos FAST is used, pre-authentication data encoding is + always used. + + There is one apparently conflicting registration between typed data + and pre-authentication data. PA-GET-FROM-TYPED-DATA and TD-PADATA + are both assigned the value 22. However, this registration is simply + a mechanism to include an element of the other encoding. The use of + both should be deprecated. + + This document creates a registry for pre-authentication and typed + data. The registration procedures are as follows. Expert review for + pre-authentication mechanisms designed to authenticate users, KDCs, + or establish the reply key. The expert first determines that the + purpose of the method is to authenticate clients, KDCs, or to + establish the reply key. If so, expert review is appropriate. The + expert evaluates the security and interoperability of the + specification. + + IETF review is required if the expert believes that the pre- + authentication method is broader than these three areas. Pre- + authentication methods that change the Kerberos state machine or + otherwise make significant changes to the Kerberos protocol should be + Standards Track RFCs. A concern that a particular method needs to be + a Standards Track RFC may be raised as an objection during IETF + review. + + + +Hartman & Zhu Standards Track [Page 38] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + Several of the registrations indicated below were made at a time when + the Kerberos protocol was less mature and do not meet the current + requirements for this registry. These registrations are included in + order to accurately document what is known about the use of these + protocol code points and to avoid conflicts. + + Type Value Reference + ---------------------------------------------------------------------- + PA-TGS-REQ 1 [RFC4120] + PA-ENC-TIMESTAMP 2 [RFC4120] + PA-PW-SALT 3 [RFC4120] + [reserved] 4 [RFC6113] + PA-ENC-UNIX-TIME 5 (deprecated) [RFC4120] + PA-SANDIA-SECUREID 6 [RFC4120] + PA-SESAME 7 [RFC4120] + PA-OSF-DCE 8 [RFC4120] + PA-CYBERSAFE-SECUREID 9 [RFC4120] + PA-AFS3-SALT 10 [RFC4120] [RFC3961] + PA-ETYPE-INFO 11 [RFC4120] + PA-SAM-CHALLENGE 12 [KRB-WG.SAM] + PA-SAM-RESPONSE 13 [KRB-WG.SAM] + PA-PK-AS-REQ_OLD 14 [PK-INIT-1999] + PA-PK-AS-REP_OLD 15 [PK-INIT-1999] + PA-PK-AS-REQ 16 [RFC4556] + PA-PK-AS-REP 17 [RFC4556] + PA-PK-OCSP-RESPONSE 18 [RFC4557] + PA-ETYPE-INFO2 19 [RFC4120] + PA-USE-SPECIFIED-KVNO 20 [RFC4120] + PA-SVR-REFERRAL-INFO 20 [REFERRALS] + PA-SAM-REDIRECT 21 [KRB-WG.SAM] + PA-GET-FROM-TYPED-DATA 22 (embedded in typed data) [RFC4120] + TD-PADATA 22 (embeds padata) [RFC4120] + PA-SAM-ETYPE-INFO 23 (sam/otp) [KRB-WG.SAM] + PA-ALT-PRINC 24 (crawdad@fnal.gov) [HW-AUTH] + PA-SERVER-REFERRAL 25 [REFERRALS] + PA-SAM-CHALLENGE2 30 (kenh@pobox.com) [KRB-WG.SAM] + PA-SAM-RESPONSE2 31 (kenh@pobox.com) [KRB-WG.SAM] + PA-EXTRA-TGT 41 Reserved extra TGT [RFC6113] + TD-PKINIT-CMS-CERTIFICATES 101 CertificateSet from CMS + TD-KRB-PRINCIPAL 102 PrincipalName + TD-KRB-REALM 103 Realm + TD-TRUSTED-CERTIFIERS 104 [RFC4556] + TD-CERTIFICATE-INDEX 105 [RFC4556] + TD-APP-DEFINED-ERROR 106 Application specific [RFC6113] + TD-REQ-NONCE 107 INTEGER [RFC6113] + TD-REQ-SEQ 108 INTEGER [RFC6113] + TD_DH_PARAMETERS 109 [RFC4556] + TD-CMS-DIGEST-ALGORITHMS 111 [ALG-AGILITY] + + + +Hartman & Zhu Standards Track [Page 39] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + TD-CERT-DIGEST-ALGORITHMS 112 [ALG-AGILITY] + PA-PAC-REQUEST 128 [MS-KILE] + PA-FOR_USER 129 [MS-KILE] + PA-FOR-X509-USER 130 [MS-KILE] + PA-FOR-CHECK_DUPS 131 [MS-KILE] + PA-AS-CHECKSUM 132 [MS-KILE] + PA-FX-COOKIE 133 [RFC6113] + PA-AUTHENTICATION-SET 134 [RFC6113] + PA-AUTH-SET-SELECTED 135 [RFC6113] + PA-FX-FAST 136 [RFC6113] + PA-FX-ERROR 137 [RFC6113] + PA-ENCRYPTED-CHALLENGE 138 [RFC6113] + PA-OTP-CHALLENGE 141 (gareth.richards@rsa.com) [OTP-PREAUTH] + PA-OTP-REQUEST 142 (gareth.richards@rsa.com) [OTP-PREAUTH] + PA-OTP-CONFIRM 143 (gareth.richards@rsa.com) [OTP-PREAUTH] + PA-OTP-PIN-CHANGE 144 (gareth.richards@rsa.com) [OTP-PREAUTH] + PA-EPAK-AS-REQ 145 (sshock@gmail.com) [RFC6113] + PA-EPAK-AS-REP 146 (sshock@gmail.com) [RFC6113] + PA_PKINIT_KX 147 [RFC6112] + PA_PKU2U_NAME 148 [PKU2U] + PA-SUPPORTED-ETYPES 165 [MS-KILE] + PA-EXTENDED_ERROR 166 [MS-KILE] + +7.2. Fast Armor Types + + FAST armor types are defined in Section 5.4.1. A FAST armor type is + a signed 32-bit integer. FAST armor types are assigned by standards + action. + + Type Name Description + ------------------------------------------------------------ + 0 Reserved. + 1 FX_FAST_ARMOR_AP_REQUEST Ticket armor using an ap-req. + +7.3. FAST Options + + A FAST request includes a set of bit flags to indicate additional + options. Bits 0-15 are critical; other bits are non-critical. + Assigning bits greater than 31 may require special support in + implementations. Assignment of FAST options requires standards + action. + + + + + + + + + + +Hartman & Zhu Standards Track [Page 40] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + Type Name Description + ------------------------------------------------------------------- + 0 RESERVED Reserved for future expansion of this + field. + 1 hide-client-names Requesting the KDC to hide client + names in the KDC response + 16 kdc-follow-referrals Reserved. + +8. Security Considerations + + The kdc-referrals option in the Kerberos FAST padata requests the KDC + to act as the client to follow referrals. This can overload the KDC. + To limit the damages of denial of service using this option, KDCs MAY + restrict the number of simultaneous active requests with this option + for any given client principal. + + Regarding the facilities provided by the Encrypted Challenge FAST + factor, the challenge key is derived from the client secrets and + because the client secrets are known only to the client and the KDC, + the verification of the EncryptedChallenge structure proves the + client's identity, the verification of the EncryptedChallenge + structure in the KDC reply proves that the expected KDC responded. + Therefore, the Encrypted Challenge FAST factor as a pre- + authentication mechanism offers the following facilities: Client + Authentication and KDC Authentication. There is no un-authenticated + cleartext introduced by the Encrypted Challenge FAST factor. + + FAST provides an encrypted tunnel over which pre-authentication + conversations can take place. In addition, FAST optionally + authenticates the KDC to the client. It is the responsibility of + FAST factors to authenticate the client to the KDC. Care MUST be + taken to design FAST factors such that they are bound to the + conversation. If this is not done, a man-in-the-middle may be able + to cut&paste a FAST factor from one conversation to another. The + easiest way to do this is to bind each FAST factor to the armor key + that is guaranteed to be unique for each conversation. + + The anonymous PKINIT mode for obtaining an armor ticket does not + always authenticate the KDC to the client before the conversation + begins. Tracking the KDC verified state guarantees that by the end + of the conversation, the client has authenticated the KDC. However, + FAST factor designers need to consider the implications of using + their factor when the KDC has not yet been authenticated. If this + proves problematic in an environment, then the particular FAST factor + should not be used with anonymous PKINIT. + + Existing pre-authentication mechanisms are believed to be at least as + secure when used with FAST as they are when used outside of FAST. + + + +Hartman & Zhu Standards Track [Page 41] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + One part of this security is making sure that when pre-authentication + methods checksum the request, they checksum the inner request rather + than the outer request. If the mechanism checksummed the outer + request, a man-in-the-middle could observe it outside a FAST tunnel + and then cut&paste it into a FAST exchange where the inner rather + than outer request would be used to select attributes of the issued + ticket. Such attacks would typically invalidate auditing information + or create a situation where the client and KDC disagree about what + ticket is issued. However, such attacks are unlikely to allow an + attacker who would not be able to authenticate as a principal to do + so. Even so, FAST is believed to defend against these attacks in + existing legacy mechanism. However, since there is no standard for + how legacy mechanisms bind the request to the pre-authentication or + provide integrity protection, security analysis can be difficult. In + some cases, FAST may significantly improve the integrity protection + of legacy mechanisms. + + The security of the TGS exchange depends on authenticating the client + to the KDC. In the AS exchange, this is done using pre- + authentication data or FAST factors. In the TGS exchange, this is + done by presenting a TGT and by using the session (or sub-session) + key in constructing the request. Because FAST uses a request body in + the inner request, encrypted in the armor key, rather than the + request body in the outer request, it is critical that establishing + the armor key be tied to the authentication of the client to the KDC. + If this is not done, an attacker could manipulate the options + requested in the TGS request, for example, requesting a ticket with + different validity or addresses. The easiest way to bind the armor + key to the authentication of the client to the KDC is for the armor + key to depend on the sub-session key of the TGT. This is done with + the implicit TGS armor supported by this specification. Future armor + types designed for use with the TGS MUST either bind their armor keys + to the TGT or provide another mechanism to authenticate the client to + the KDC. + +9. Acknowledgements + + Sam Hartman would like to thank the MIT Kerberos Consortium for its + funding of his time on this project. + + Several suggestions from Jeffrey Hutzelman based on early revisions + of this documents led to significant improvements of this document. + + The proposal to ask one KDC to chase down the referrals and return + the final ticket is based on requirements in [CROSS]. + + Joel Weber had a proposal for a mechanism similar to FAST that + created a protected tunnel for Kerberos pre-authentication. + + + +Hartman & Zhu Standards Track [Page 42] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + Srinivas Cheruku and Greg Hudson provided valuable review comments. + +10. References + +10.1. Normative References + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC3961] Raeburn, K., "Encryption and Checksum Specifications + for Kerberos 5", RFC 3961, February 2005. + + [RFC4120] Neuman, C., Yu, T., Hartman, S., and K. Raeburn, "The + Kerberos Network Authentication Service (V5)", + RFC 4120, July 2005. + + [RFC4556] Zhu, L. and B. Tung, "Public Key Cryptography for + Initial Authentication in Kerberos (PKINIT)", + RFC 4556, June 2006. + + [RFC5226] Narten, T. and H. Alvestrand, "Guidelines for Writing + an IANA Considerations Section in RFCs", BCP 26, + RFC 5226, May 2008. + + [RFC6112] Zhu, L., Leach, P., and S. Hartman "Anonymity Support + for Kerberos", RFC 6112, April 2011. + +10.2. Informative References + + [ALG-AGILITY] Astrand, L. and L. Zhu, "PK-INIT algorithm agility", + Work in Progress, August 2008. + + [CROSS] Sakane, S., Zrelli, S., and M. Ishiyama , "Problem + statement on the cross-realm operation of Kerberos in + a specific system", Work in Progress, July 2007. + + [EKE] Bellovin, S. and M. Merritt, "Augmented Encrypted Key + Exchange: A Password-Based Protocol Secure Against + Dictionary Attacks and Password File Compromise, + Proceedings of the 1st ACM Conference on Computer and + Communications Security, ACM Press.", November 1993. + + [HW-AUTH] Crawford, M., "Passwordless Initial Authentication to + Kerberos by Hardware Preauthentication", Work + in Progress, October 2006. + + [IEEE1363.2] IEEE, "IEEE P1363.2: Password-Based Public-Key + Cryptography", 2004. + + + +Hartman & Zhu Standards Track [Page 43] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + [KRB-WG.SAM] Hornstein, K., Renard, K., Neuman, C., and G. Zorn, + "Integrating Single-use Authentication Mechanisms + with Kerberos", Work in Progress, July 2004. + + [MS-KILE] Microsoft, "Kerberos Protocol Extensions", . + + [OTP-PREAUTH] Richards, G., "OTP Pre-authentication", Work + in Progress, February 2011. + + [PK-INIT-1999] Tung, B., Neuman, C., Hur, M., Medvinsky, A., + Medvinsky, S., Wray, J., and J. Trostle, "Public Key + Cryptography for Initial Authentication in Kerberos", + Work in Progress, July 1999. + + [PKU2U] Zhu, L., Altman, J., and N. Williams, "Public Key + Cryptography Based User-to-User Authentication - + (PKU2U)", Work in Progress, November 2008. + + [REFERRALS] Hartman, S., Ed., Raeburn, K., and L. Zhu, "Kerberos + Principal Name Canonicalization and KDC-Generated + Cross-Realm Referrals", Work in Progress, March 2011. + + [RFC4557] Zhu, L., Jaganathan, K., and N. Williams, "Online + Certificate Status Protocol (OCSP) Support for Public + Key Cryptography for Initial Authentication in + Kerberos (PKINIT)", RFC 4557, June 2006. + + + + + + + + + + + + + + + + + + + + + + + + +Hartman & Zhu Standards Track [Page 44] + +RFC 6113 Kerberos Preauth Framework April 2011 + + +Appendix A. Test Vectors for KRB-FX-CF2 + + This informative appendix presents test vectors for the KRB-FX-CF2 + function. Test vectors are presented for several encryption types. + In all cases, the first key (k1) is the result of string-to- + key("key1", "key1", default_parameters) and the second key (k2) is + the result of string-to-key("key2", "key2", default_parameters). + Both keys are of the same enctype. The presented test vector is the + hexadecimal encoding of the key produced by KRB-FX-CF2(k1, k2, "a", + "b"). The peppers are one-octet ASCII strings. + + In performing interoperability testing, there was significant + ambiguity surrounding [RFC3961] pseudo-random operations. These test + vectors assume that the AES pseudo-random operation is + aes-ecb(trunc128(sha-1(input))) where trunc128 truncates its input to + 128 bits. The 3DES pseudo-random operation is assumed to be + des3-cbc(trunc128(sha-1(input))). The DES pseudo-random operation is + assumed to be des-cbc(md5(input)). As specified in RFC 4757, the RC4 + pseudo-random operation is hmac-sha1(input). + + Interoperability testing also demonstrated ambiguity surrounding the + DES random-to-key operation. The random-to-key operation is assumed + to be distribute 56 bits into high-7-bits of 8 octets and generate + parity. + + These test vectors were produced with revision 22359 of the MIT + Kerberos sources. The AES 256 and AES 128 test vectors have been + confirmed by multiple other implementors. The RC4 test vectors have + been confirmed by one other implementor. The DES and triple DES test + vectors have not been confirmed. + + aes 128 (enctype 17): 97df97e4b798b29eb31ed7280287a92a + AES256 (enctype 18): 4d6ca4e629785c1f01baf55e2e548566 + b9617ae3a96868c337cb93b5e72b1c7b + DES (enctype 1): 43bae3738c9467e6 + 3DES (enctype 16): e58f9eb643862c13ad38e529313462a7f73e62834fe54a01 + RC4 (enctype 23): 24d7f6b6bae4e5c00d2082c5ebab3672 + + + + + + + + + + + + + + +Hartman & Zhu Standards Track [Page 45] + +RFC 6113 Kerberos Preauth Framework April 2011 + + +Appendix B. ASN.1 Module + + KerberosPreauthFramework { + iso(1) identified-organization(3) dod(6) internet(1) + security(5) kerberosV5(2) modules(4) preauth-framework(3) + } DEFINITIONS EXPLICIT TAGS ::= BEGIN + + IMPORTS + KerberosTime, PrincipalName, Realm, EncryptionKey, Checksum, + Int32, EncryptedData, PA-ENC-TS-ENC, PA-DATA, KDC-REQ-BODY, + Microseconds, KerberosFlags, UInt32 + FROM KerberosV5Spec2 { iso(1) identified-organization(3) + dod(6) internet(1) security(5) kerberosV5(2) + modules(4) krb5spec2(2) }; + -- as defined in RFC 4120. + + PA-AUTHENTICATION-SET ::= SEQUENCE OF PA-AUTHENTICATION-SET-ELEM + + PA-AUTHENTICATION-SET-ELEM ::= SEQUENCE { + pa-type [0] Int32, + -- same as padata-type. + pa-hint [1] OCTET STRING OPTIONAL, + pa-value [2] OCTET STRING OPTIONAL, + ... + } + + KrbFastArmor ::= SEQUENCE { + armor-type [0] Int32, + -- Type of the armor. + armor-value [1] OCTET STRING, + -- Value of the armor. + ... + } + + PA-FX-FAST-REQUEST ::= CHOICE { + armored-data [0] KrbFastArmoredReq, + ... + } + + KrbFastArmoredReq ::= SEQUENCE { + armor [0] KrbFastArmor OPTIONAL, + -- Contains the armor that identifies the armor key. + -- MUST be present in AS-REQ. + req-checksum [1] Checksum, + -- For AS, contains the checksum performed over the type + -- KDC-REQ-BODY for the req-body field of the KDC-REQ + -- structure; + -- For TGS, contains the checksum performed over the type + + + +Hartman & Zhu Standards Track [Page 46] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + -- AP-REQ in the PA-TGS-REQ padata. + -- The checksum key is the armor key, the checksum + -- type is the required checksum type for the enctype of + -- the armor key, and the key usage number is + -- KEY_USAGE_FAST_REQ_CHKSUM. + enc-fast-req [2] EncryptedData, -- KrbFastReq -- + -- The encryption key is the armor key, and the key usage + -- number is KEY_USAGE_FAST_ENC. + ... + } + + KrbFastReq ::= SEQUENCE { + fast-options [0] FastOptions, + -- Additional options. + padata [1] SEQUENCE OF PA-DATA, + -- padata typed holes. + req-body [2] KDC-REQ-BODY, + -- Contains the KDC request body as defined in Section + -- 5.4.1 of [RFC4120]. + -- This req-body field is preferred over the outer field + -- in the KDC request. + ... + } + + FastOptions ::= KerberosFlags + -- reserved(0), + -- hide-client-names(1), + -- kdc-follow-referrals(16) + + PA-FX-FAST-REPLY ::= CHOICE { + armored-data [0] KrbFastArmoredRep, + ... + } + + KrbFastArmoredRep ::= SEQUENCE { + enc-fast-rep [0] EncryptedData, -- KrbFastResponse -- + -- The encryption key is the armor key in the request, and + -- the key usage number is KEY_USAGE_FAST_REP. + ... + } + + KrbFastResponse ::= SEQUENCE { + padata [0] SEQUENCE OF PA-DATA, + -- padata typed holes. + strengthen-key [1] EncryptionKey OPTIONAL, + -- This, if present, strengthens the reply key for AS and + -- TGS. MUST be present for TGS + -- MUST be absent in KRB-ERROR. + + + +Hartman & Zhu Standards Track [Page 47] + +RFC 6113 Kerberos Preauth Framework April 2011 + + + finished [2] KrbFastFinished OPTIONAL, + -- Present in AS or TGS reply; absent otherwise. + nonce [3] UInt32, + -- Nonce from the client request. + ... + } + + KrbFastFinished ::= SEQUENCE { + timestamp [0] KerberosTime, + usec [1] Microseconds, + -- timestamp and usec represent the time on the KDC when + -- the reply was generated. + crealm [2] Realm, + cname [3] PrincipalName, + -- Contains the client realm and the client name. + ticket-checksum [4] Checksum, + -- checksum of the ticket in the KDC-REP using the armor + -- and the key usage is KEY_USAGE_FAST_FINISH. + -- The checksum type is the required checksum type + -- of the armor key. + ... + } + + EncryptedChallenge ::= EncryptedData + -- Encrypted PA-ENC-TS-ENC, encrypted in the challenge key + -- using key usage KEY_USAGE_ENC_CHALLENGE_CLIENT for the + -- client and KEY_USAGE_ENC_CHALLENGE_KDC for the KDC. + END + +Authors' Addresses + + Sam Hartman + Painless Security + + EMail: hartmans-ietf@mit.edu + + + Larry Zhu + Microsoft Corporation + One Microsoft Way + Redmond, WA 98052 + US + + EMail: larry.zhu@microsoft.com + + + + + + + +Hartman & Zhu Standards Track [Page 48] + From 13eeb30a1d07573d1879f0907473ab4778cee9f0 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Tue, 10 May 2011 23:43:53 -0700 Subject: [PATCH 049/119] Create a request structure --- kdc/digest-service.c | 2 + kdc/headers.h | 2 + kdc/kdc_locl.h | 43 ++ kdc/kerberos5.c | 980 +++++++++++++++++++++------------------- kdc/pkinit.c | 4 +- kdc/process.c | 16 +- tests/kdc/check-fast.in | 5 +- 7 files changed, 574 insertions(+), 478 deletions(-) diff --git a/kdc/digest-service.c b/kdc/digest-service.c index 4d339a2dd..575850c29 100644 --- a/kdc/digest-service.c +++ b/kdc/digest-service.c @@ -44,6 +44,8 @@ typedef struct pk_client_params pk_client_params; struct DigestREQ; struct Kx509Request; +typedef struct kdc_request_desc *kdc_request_t; + #include krb5_kdc_configuration *config; diff --git a/kdc/headers.h b/kdc/headers.h index aced5ce61..9e7af82e9 100644 --- a/kdc/headers.h +++ b/kdc/headers.h @@ -106,6 +106,8 @@ #include #include +#include + #undef ALLOC #define ALLOC(X) ((X) = calloc(1, sizeof(*(X)))) #undef ALLOC_SEQ diff --git a/kdc/kdc_locl.h b/kdc/kdc_locl.h index 36d694dae..40dcae16b 100644 --- a/kdc/kdc_locl.h +++ b/kdc/kdc_locl.h @@ -43,8 +43,51 @@ typedef struct pk_client_params pk_client_params; struct DigestREQ; struct Kx509Request; +typedef struct kdc_request_desc *kdc_request_t; + #include +struct kdc_request_desc { + krb5_context context; + krb5_kdc_configuration *config; + + /* */ + + krb5_data request; + KDC_REQ req; + METHOD_DATA *padata; + + /* out */ + + METHOD_DATA outpadata; + + KDC_REP rep; + EncTicketPart et; + EncKDCRepPart ek; + + /* PA methods can affect both the reply key and the session key (pkinit) */ + krb5_keyblock sessionetype; + krb5_keyblock reply_key; + krb5_keyblock session_key; + + const char *e_text; + + /* state */ + krb5_principal client_princ; + char *client_name; + hdb_entry_ex *client; + HDB *clientdb; + + krb5_principal server_princ; + char *server_name; + hdb_entry_ex *server; + + krb5_crypto armor_crypto; + + heim_dict_t pastate; +}; + + extern sig_atomic_t exit_flag; extern size_t max_request_udp; extern size_t max_request_tcp; diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 532c29e6b..db1494208 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -271,24 +271,366 @@ _kdc_log_timestamp(krb5_context context, type, authtime_str, starttime_str, endtime_str, renewtime_str); } +static krb5_error_code +make_pa_enc_challange(krb5_context context, METHOD_DATA *md, + krb5_crypto crypto) +{ + PA_ENC_TS_ENC p; + unsigned char *buf; + size_t buf_size; + size_t len; + EncryptedData encdata; + krb5_error_code ret; + int32_t usec; + int usec2; + + krb5_us_timeofday (context, &p.patimestamp, &usec); + usec2 = usec; + p.pausec = &usec2; + + ASN1_MALLOC_ENCODE(PA_ENC_TS_ENC, buf, buf_size, &p, &len, ret); + if (ret) + return ret; + if(buf_size != len) + krb5_abortx(context, "internal error in ASN.1 encoder"); + + ret = krb5_encrypt_EncryptedData(context, + crypto, + KRB5_KU_ENC_CHALLENGE_KDC, + buf, + len, + 0, + &encdata); + free(buf); + if (ret) + return ret; + + ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_size, &encdata, &len, ret); + free_EncryptedData(&encdata); + if (ret) + return ret; + if(buf_size != len) + krb5_abortx(context, "internal error in ASN.1 encoder"); + + ret = krb5_padata_add(context, md, KRB5_PADATA_ENCRYPTED_CHALLENGE, buf, len); + if (ret) + free(buf); + return ret; +} + +static krb5_error_code +pa_enc_chal_validate(kdc_request_t r, const PA_DATA *pa) +{ + krb5_data pepper1, pepper2, ts_data; + KDC_REQ_BODY *b = &r->req.req_body; + EncryptedData enc_data; + krb5_enctype aenctype; + krb5_error_code ret; + struct Key *k; + size_t size; + int i; + + heim_assert(r->armor_crypto != NULL, "ENC-CHAL called for non FAST"); + + if (b->kdc_options.request_anonymous) { + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + kdc_log(r->context, r->config, 0, "ENC-CHALL doesn't support anon"); + return ret; + } + + ret = decode_EncryptedData(pa->padata_value.data, + pa->padata_value.length, + &enc_data, + &size); + if (ret) { + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + kdc_log(r->context, r->config, 5, "Failed to decode PA-DATA -- %s", + r->client_name); + return ret; + } + + pepper1.data = "clientchallengearmor"; + pepper1.length = strlen(pepper1.data); + pepper2.data = "challengelongterm"; + pepper2.length = strlen(pepper2.data); + + krb5_crypto_getenctype(r->context, r->armor_crypto, &aenctype); + + for (i = 0; i < r->client->entry.keys.len; i++) { + krb5_crypto challangecrypto, longtermcrypto; + krb5_keyblock challangekey; + PA_ENC_TS_ENC p; + + k = &r->client->entry.keys.val[i]; + + ret = krb5_crypto_init(r->context, &k->key, 0, &longtermcrypto); + if (ret) + continue; + + ret = krb5_crypto_fx_cf2(r->context, r->armor_crypto, longtermcrypto, + &pepper1, &pepper2, aenctype, + &challangekey); + krb5_crypto_destroy(r->context, longtermcrypto); + if (ret) + continue; + + ret = krb5_crypto_init(r->context, &challangekey, 0, + &challangecrypto); + if (ret) + continue; + + ret = krb5_decrypt_EncryptedData(r->context, challangecrypto, + KRB5_KU_ENC_CHALLENGE_CLIENT, + &enc_data, + &ts_data); + if (ret) + continue; + + ret = decode_PA_ENC_TS_ENC(ts_data.data, + ts_data.length, + &p, + &size); + krb5_data_free(&ts_data); + if(ret){ + krb5_crypto_destroy(r->context, challangecrypto); + ret = KRB5KDC_ERR_PREAUTH_FAILED; + kdc_log(r->context, r->config, + 5, "Failed to decode PA-ENC-TS_ENC -- %s", + r->client_name); + continue; + } + + if (abs(kdc_time - p.patimestamp) > r->context->max_skew) { + char client_time[100]; + + krb5_crypto_destroy(r->context, challangecrypto); + + krb5_format_time(r->context, p.patimestamp, + client_time, sizeof(client_time), TRUE); + + ret = KRB5KRB_AP_ERR_SKEW; + kdc_log(r->context, r->config, 0, + "Too large time skew, " + "client time %s is out by %u > %u seconds -- %s", + client_time, + (unsigned)abs(kdc_time - p.patimestamp), + r->context->max_skew, + r->client_name); + + free_PA_ENC_TS_ENC(&p); + goto out; + } + + free_PA_ENC_TS_ENC(&p); + + ret = make_pa_enc_challange(r->context, &r->outpadata, + challangecrypto); + krb5_crypto_destroy(r->context, challangecrypto); + if (ret) + goto out; + + set_salt_padata(&r->outpadata, k->salt); + krb5_free_keyblock_contents(r->context, &r->reply_key); + ret = krb5_copy_keyblock_contents(r->context, &k->key, &r->reply_key); + ret = 0; + break; + } + if (i < r->client->entry.keys.len) + ret = KRB5KDC_ERR_PREAUTH_FAILED; + out: + free_EncryptedData(&enc_data); + + return ret; +} + +static krb5_error_code +pa_enc_ts_validate(kdc_request_t r, const PA_DATA *pa) +{ + EncryptedData enc_data; + krb5_error_code ret; + krb5_crypto crypto; + krb5_data ts_data; + PA_ENC_TS_ENC p; + size_t len; + Key *pa_key; + char *str; + + if (r->req.req_body.kdc_options.request_anonymous) { + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + r->e_text = "ENC-TS doesn't suport anon"; + kdc_log(r->context, r->config, 0, "ENC-TS doesn't support anon"); + goto out; + } + + ret = decode_EncryptedData(pa->padata_value.data, + pa->padata_value.length, + &enc_data, + &len); + if (ret) { + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + kdc_log(r->context, r->config, 5, "Failed to decode PA-DATA -- %s", + r->client_name); + goto out; + } + + ret = hdb_enctype2key(r->context, &r->client->entry, + enc_data.etype, &pa_key); + if(ret){ + char *estr; + r->e_text = "No key matching entype"; + ret = KRB5KDC_ERR_ETYPE_NOSUPP; + if(krb5_enctype_to_string(r->context, enc_data.etype, &estr)) + estr = NULL; + if(estr == NULL) + kdc_log(r->context, r->config, 5, + "No client key matching pa-data (%d) -- %s", + enc_data.etype, r->client_name); + else + kdc_log(r->context, r->config, 5, + "No client key matching pa-data (%s) -- %s", + estr, r->client_name); + free(estr); + free_EncryptedData(&enc_data); + goto out; + } + + try_next_key: + ret = krb5_crypto_init(r->context, &pa_key->key, 0, &crypto); + if (ret) { + const char *msg = krb5_get_error_message(r->context, ret); + kdc_log(r->context, r->config, 0, "krb5_crypto_init failed: %s", msg); + krb5_free_error_message(r->context, msg); + free_EncryptedData(&enc_data); + goto out; + } + + ret = krb5_decrypt_EncryptedData (r->context, + crypto, + KRB5_KU_PA_ENC_TIMESTAMP, + &enc_data, + &ts_data); + krb5_crypto_destroy(r->context, crypto); + /* + * Since the user might have several keys with the same + * enctype but with diffrent salting, we need to try all + * the keys with the same enctype. + */ + if(ret){ + krb5_error_code ret2; + const char *msg = krb5_get_error_message(r->context, ret); + + ret2 = krb5_enctype_to_string(r->context, + pa_key->key.keytype, &str); + if (ret2) + str = NULL; + kdc_log(r->context, r->config, 5, + "Failed to decrypt PA-DATA -- %s " + "(enctype %s) error %s", + r->client_name, str ? str : "unknown enctype", msg); + krb5_free_error_message(r->context, msg); + free(str); + + if(hdb_next_enctype2key(r->context, &r->client->entry, + enc_data.etype, &pa_key) == 0) + goto try_next_key; + + free_EncryptedData(&enc_data); + + if (r->clientdb->hdb_auth_status) + r->clientdb->hdb_auth_status(r->context, r->clientdb, r->client, + HDB_AUTH_WRONG_PASSWORD); + + ret = KRB5KDC_ERR_PREAUTH_FAILED; + goto out; + } + free_EncryptedData(&enc_data); + ret = decode_PA_ENC_TS_ENC(ts_data.data, + ts_data.length, + &p, + &len); + krb5_data_free(&ts_data); + if(ret){ + ret = KRB5KDC_ERR_PREAUTH_FAILED; + kdc_log(r->context, r->config, + 5, "Failed to decode PA-ENC-TS_ENC -- %s", + r->client_name); + goto out; + } + if (abs(kdc_time - p.patimestamp) > r->context->max_skew) { + char client_time[100]; + + krb5_format_time(r->context, p.patimestamp, + client_time, sizeof(client_time), TRUE); + + ret = KRB5KRB_AP_ERR_SKEW; + kdc_log(r->context, r->config, 0, + "Too large time skew, " + "client time %s is out by %u > %u seconds -- %s", + client_time, + (unsigned)abs(kdc_time - p.patimestamp), + r->context->max_skew, + r->client_name); + + /* + * The following is needed to make windows clients to + * retry using the timestamp in the error message, if + * there is a e_text, they become unhappy. + */ + r->e_text = NULL; + free_PA_ENC_TS_ENC(&p); + goto out; + } + free_PA_ENC_TS_ENC(&p); + + set_salt_padata(&r->outpadata, pa_key->salt); + + ret = krb5_copy_keyblock_contents(r->context, &pa_key->key, &r->reply_key); + if (ret) + return ret; + + ret = krb5_enctype_to_string(r->context, pa_key->key.keytype, &str); + if (ret) + str = NULL; + kdc_log(r->context, r->config, 2, + "ENC-TS Pre-authentication succeeded -- %s using %s", + r->client_name, str ? str : "unknown enctype"); + free(str); + + ret = 0; + + out: + + return ret; +} + struct kdc_patypes { int type; char *name; unsigned int flags; #define PA_ANNOUNCE 1 -#ifdef PKINIT -#define PA_ANNOUNCE_PKINIT PA_ANNOUNCE -#else -#define PA_ANNOUNCE_PKINIT 0 -#endif +#define PA_REQ_FAST 2 /* only use inside fast */ + krb5_error_code (*validate)(kdc_request_t, const PA_DATA *pa); }; static const struct kdc_patypes pat[] = { - { KRB5_PADATA_PK_AS_REQ, "PK-INIT(ietf)", PA_ANNOUNCE_PKINIT }, - { KRB5_PADATA_PK_AS_REQ_WIN, "PK-INIT(win2k)", PA_ANNOUNCE_PKINIT }, +#ifdef PKINIT + { KRB5_PADATA_PK_AS_REQ, "PK-INIT(ietf)", PA_ANNOUNCE }, + { KRB5_PADATA_PK_AS_REQ_WIN, "PK-INIT(win2k)", PA_ANNOUNCE }, +#else + { KRB5_PADATA_PK_AS_REQ, "PK-INIT(ietf)", 0 }, + { KRB5_PADATA_PK_AS_REQ_WIN, "PK-INIT(win2k)", 0 }, +#endif { KRB5_PADATA_PA_PK_OCSP_RESPONSE , "OCSP", 0 }, - { KRB5_PADATA_ENC_TIMESTAMP , "ENC-TS", PA_ANNOUNCE }, - { KRB5_PADATA_ENCRYPTED_CHALLENGE , "ENC-CHAL", PA_ANNOUNCE }, + { + KRB5_PADATA_ENC_TIMESTAMP , "ENC-TS", + PA_ANNOUNCE, + pa_enc_ts_validate + }, + { + KRB5_PADATA_ENCRYPTED_CHALLENGE , "ENC-CHAL", + PA_ANNOUNCE | PA_REQ_FAST, + pa_enc_chal_validate + }, { KRB5_PADATA_REQ_ENC_PA_REP , "REQ-ENC-PA-REP", 0 }, { KRB5_PADATA_FX_FAST, "FX-FAST", PA_ANNOUNCE }, { KRB5_PADATA_FX_ERROR, "FX-ERROR", 0 }, @@ -1063,53 +1405,6 @@ _kdc_is_anonymous(krb5_context context, krb5_principal principal) return 1; } -static krb5_error_code -make_pa_enc_challange(krb5_context context, METHOD_DATA *md, - krb5_crypto crypto) -{ - PA_ENC_TS_ENC p; - unsigned char *buf; - size_t buf_size; - size_t len; - EncryptedData encdata; - krb5_error_code ret; - int32_t usec; - int usec2; - - krb5_us_timeofday (context, &p.patimestamp, &usec); - usec2 = usec; - p.pausec = &usec2; - - ASN1_MALLOC_ENCODE(PA_ENC_TS_ENC, buf, buf_size, &p, &len, ret); - if (ret) - return ret; - if(buf_size != len) - krb5_abortx(context, "internal error in ASN.1 encoder"); - - ret = krb5_encrypt_EncryptedData(context, - crypto, - KRB5_KU_ENC_CHALLENGE_KDC, - buf, - len, - 0, - &encdata); - free(buf); - if (ret) - return ret; - - ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_size, &encdata, &len, ret); - free_EncryptedData(&encdata); - if (ret) - return ret; - if(buf_size != len) - krb5_abortx(context, "internal error in ASN.1 encoder"); - - ret = krb5_padata_add(context, md, KRB5_PADATA_ENCRYPTED_CHALLENGE, buf, len); - if (ret) - free(buf); - return ret; -} - static krb5_error_code unwrap_fast(krb5_context context, krb5_kdc_configuration *config, @@ -1344,41 +1639,33 @@ unwrap_fast(krb5_context context, */ krb5_error_code -_kdc_as_rep(krb5_context context, - krb5_kdc_configuration *config, - KDC_REQ *req, - const krb5_data *req_buffer, +_kdc_as_rep(kdc_request_t r, krb5_data *reply, const char *from, struct sockaddr *from_addr, int datagram_reply) { + krb5_context context = r->context; + krb5_kdc_configuration *config = r->config; + KDC_REQ *req = &r->req; + const krb5_data *req_buffer = &r->request; KDC_REQ_BODY *b = NULL; AS_REP rep; KDCOptions f; - hdb_entry_ex *client = NULL, *server = NULL; - HDB *clientdb; krb5_enctype setype, sessionetype; EncTicketPart et; EncKDCRepPart ek; - krb5_principal client_princ = NULL, server_princ = NULL; - char *client_name = NULL, *server_name = NULL; krb5_error_code ret = 0; - const char *e_text = NULL; - krb5_crypto crypto; Key *ckey, *skey; - EncryptionKey *reply_key = NULL, session_key; int flags = 0; #ifdef PKINIT pk_client_params *pkp = NULL; #endif METHOD_DATA error_method; - krb5_crypto armor_crypto = NULL; memset(&rep, 0, sizeof(rep)); memset(&et, 0, sizeof(et)); memset(&ek, 0, sizeof(ek)); - memset(&session_key, 0, sizeof(session_key)); error_method.len = 0; error_method.val = NULL; @@ -1389,7 +1676,7 @@ _kdc_as_rep(krb5_context context, /* * Look for FAST armor and unwrap */ - ret = unwrap_fast(context, config, req, &armor_crypto); + ret = unwrap_fast(context, config, req, &r->armor_crypto); if (ret) goto out; @@ -1401,14 +1688,14 @@ _kdc_as_rep(krb5_context context, if(b->sname == NULL){ ret = KRB5KRB_ERR_GENERIC; - e_text = "No server in request"; + r->e_text = "No server in request"; } else{ ret = _krb5_principalname2krb5_principal (context, - &server_princ, + &r->server_princ, *(b->sname), b->realm); if (ret == 0) - ret = krb5_unparse_name(context, server_princ, &server_name); + ret = krb5_unparse_name(context, r->server_princ, &r->server_name); } if (ret) { kdc_log(context, config, 0, @@ -1417,16 +1704,16 @@ _kdc_as_rep(krb5_context context, } if(b->cname == NULL){ ret = KRB5KRB_ERR_GENERIC; - e_text = "No client in request"; + r->e_text = "No client in request"; } else { ret = _krb5_principalname2krb5_principal (context, - &client_princ, + &r->client_princ, *(b->cname), b->realm); if (ret) goto out; - ret = krb5_unparse_name(context, client_princ, &client_name); + ret = krb5_unparse_name(context, r->client_princ, &r->client_name); } if (ret) { kdc_log(context, config, 0, @@ -1435,13 +1722,13 @@ _kdc_as_rep(krb5_context context, } kdc_log(context, config, 0, "AS-REQ %s from %s for %s", - client_name, from, server_name); + r->client_name, from, r->server_name); /* * */ - if (_kdc_is_anonymous(context, client_princ)) { + if (_kdc_is_anonymous(context, r->client_princ)) { if (!b->kdc_options.request_anonymous) { kdc_log(context, config, 0, "Anonymous ticket w/o anonymous flag"); ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; @@ -1450,7 +1737,7 @@ _kdc_as_rep(krb5_context context, } else if (b->kdc_options.request_anonymous) { kdc_log(context, config, 0, "Request for a anonymous ticket with non " - "anonymous client name: %s", client_name); + "anonymous client name: %s", r->client_name); ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; goto out; } @@ -1459,28 +1746,30 @@ _kdc_as_rep(krb5_context context, * */ - ret = _kdc_db_fetch(context, config, client_princ, + ret = _kdc_db_fetch(context, config, r->client_princ, HDB_F_GET_CLIENT | flags, NULL, - &clientdb, &client); + &r->clientdb, &r->client); if(ret == HDB_ERR_NOT_FOUND_HERE) { - kdc_log(context, config, 5, "client %s does not have secrets at this KDC, need to proxy", client_name); + kdc_log(context, config, 5, "client %s does not have secrets at this KDC, need to proxy", + r->client_name); goto out; } else if(ret){ const char *msg = krb5_get_error_message(context, ret); - kdc_log(context, config, 0, "UNKNOWN -- %s: %s", client_name, msg); + kdc_log(context, config, 0, "UNKNOWN -- %s: %s", r->client_name, msg); krb5_free_error_message(context, msg); ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; goto out; } - ret = _kdc_db_fetch(context, config, server_princ, + ret = _kdc_db_fetch(context, config, r->server_princ, HDB_F_GET_SERVER|HDB_F_GET_KRBTGT | flags, - NULL, NULL, &server); + NULL, NULL, &r->server); if(ret == HDB_ERR_NOT_FOUND_HERE) { - kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", server_name); + kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", + r->server_name); goto out; } else if(ret){ const char *msg = krb5_get_error_message(context, ret); - kdc_log(context, config, 0, "UNKNOWN -- %s: %s", server_name, msg); + kdc_log(context, config, 0, "UNKNOWN -- %s: %s", r->server_name, msg); krb5_free_error_message(context, msg); ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; goto out; @@ -1509,153 +1798,51 @@ _kdc_as_rep(krb5_context context, client_name, from); goto out; } - /* - * But if the KDC admin is paranoid and doesn't want to have "not - * the best" enctypes on the krbtgt, lets save the best pick from - * the client list and hope that that will work for any other - * KDCs. - */ /* * Pre-auth processing */ if(req->padata){ - int i; const PA_DATA *pa; int found_pa = 0; + unsigned int n; + int i; log_patypes(context, config, req->padata); - kdc_log(context, config, 5, - "Looking for ENCRYPTED-CHALLANGE pa-data -- %s", client_name); + /* Check if preauth matching */ - e_text = "No FAST ENCRYPTED CHALLANGE found"; - - i = 0; - pa = _kdc_find_padata(req, &i, KRB5_PADATA_ENCRYPTED_CHALLENGE); - if (pa && armor_crypto) { - krb5_data ts_data; - struct Key *k; - size_t size; - - if (b->kdc_options.request_anonymous) { - ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; - kdc_log(context, config, 0, "ENC-CHALL doesn't support anon"); - goto out; - } - - EncryptedData enc_data; - - ret = decode_EncryptedData(pa->padata_value.data, - pa->padata_value.length, - &enc_data, - &size); - if (ret) { - ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; - kdc_log(context, config, 5, "Failed to decode PA-DATA -- %s", - client_name); - goto out; - } - - krb5_data pepper1, pepper2; - - pepper1.data = "clientchallengearmor"; - pepper1.length = strlen(pepper1.data); - pepper2.data = "challengelongterm"; - pepper2.length = strlen(pepper2.data); - - krb5_enctype aenctype; - krb5_crypto_getenctype(context, armor_crypto, &aenctype); - - for (i = 0; i < client->entry.keys.len; i++) { - krb5_crypto challangecrypto, longtermcrypto; - krb5_keyblock challangekey; - PA_ENC_TS_ENC p; - - k = &client->entry.keys.val[i]; - - ret = krb5_crypto_init(context, &k->key, 0, &longtermcrypto); - if (ret) - continue; - - ret = krb5_crypto_fx_cf2(context, armor_crypto, longtermcrypto, - &pepper1, &pepper2, aenctype, - &challangekey); - krb5_crypto_destroy(context, longtermcrypto); - if (ret) - continue; - - ret = krb5_crypto_init(context, &challangekey, 0, - &challangecrypto); - if (ret) - continue; - - ret = krb5_decrypt_EncryptedData(context, challangecrypto, - KRB5_KU_ENC_CHALLENGE_CLIENT, - &enc_data, - &ts_data); - if (ret) - continue; - - ret = decode_PA_ENC_TS_ENC(ts_data.data, - ts_data.length, - &p, - &size); - krb5_data_free(&ts_data); - if(ret){ - krb5_crypto_destroy(context, challangecrypto); - e_text = "Failed to decode PA-ENC-TS-ENC"; - ret = KRB5KDC_ERR_PREAUTH_FAILED; - kdc_log(context, config, - 5, "Failed to decode PA-ENC-TS_ENC -- %s", - client_name); - continue; - } - - if (abs(kdc_time - p.patimestamp) > context->max_skew) { - char client_time[100]; - - krb5_crypto_destroy(context, challangecrypto); - - krb5_format_time(context, p.patimestamp, - client_time, sizeof(client_time), TRUE); - - ret = KRB5KRB_AP_ERR_SKEW; + for (n = 0; !found_pa && n < sizeof(pat) / sizeof(pat[0]); n++) { + if (pat[n].validate == NULL) + continue; + if (r->armor_crypto == NULL && (pat[n].flags & PA_REQ_FAST)) + continue; + kdc_log(context, config, 5, + "Looking for %s pa-data -- %s", pat[n].name, r->client_name); + i = 0; + pa = _kdc_find_padata(req, &i, pat[n].type); + if (pa) { + ret = pat[n].validate(r, pa); + if (ret == 0) { kdc_log(context, config, 0, - "Too large time skew, " - "client time %s is out by %u > %u seconds -- %s", - client_time, - (unsigned)abs(kdc_time - p.patimestamp), - context->max_skew, - client_name); - - free_PA_ENC_TS_ENC(&p); - goto out; + "%s pre-authentication succeeded -- %s", + pat[n].name, r->client_name); + found_pa = 1; } - - free_PA_ENC_TS_ENC(&p); - et.flags.pre_authent = 1; - - ret = make_pa_enc_challange(context, rep.padata, - challangecrypto); - krb5_crypto_destroy(context, challangecrypto); - if (ret) - goto out; - - set_salt_padata(rep.padata, k->salt); - reply_key = &k->key; - - goto preauth_done; } - free_EncryptedData(&enc_data); + } + + if (found_pa) { + et.flags.pre_authent = 1; + goto preauth_done; } #ifdef PKINIT kdc_log(context, config, 5, - "Looking for PKINIT pa-data -- %s", client_name); + "Looking for PKINIT pa-data -- %s", r->client_name); - e_text = "No PKINIT PA found"; + r->e_text = "No PKINIT PA found"; i = 0; pa = _kdc_find_padata(req, &i, KRB5_PADATA_PK_AS_REQ); @@ -1666,29 +1853,29 @@ _kdc_as_rep(krb5_context context, if (pa) { char *client_cert = NULL; - ret = _kdc_pk_rd_padata(context, config, req, pa, client, &pkp); + ret = _kdc_pk_rd_padata(context, config, req, pa, r->client, &pkp); if (ret) { ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; kdc_log(context, config, 5, "Failed to decode PKINIT PA-DATA -- %s", - client_name); - goto ts_enc; + r->client_name); + goto out; } if (ret == 0 && pkp == NULL) - goto ts_enc; + goto out; ret = _kdc_pk_check_client(context, config, - clientdb, - client, + r->clientdb, + r->client, pkp, &client_cert); if (ret) { - e_text = "PKINIT certificate not allowed to " + r->e_text = "PKINIT certificate not allowed to " "impersonate principal"; _kdc_pk_free_client_param(context, pkp); - - kdc_log(context, config, 0, "%s", e_text); + + kdc_log(context, config, 0, "%s", r->e_text); pkp = NULL; goto out; } @@ -1697,172 +1884,9 @@ _kdc_as_rep(krb5_context context, et.flags.pre_authent = 1; kdc_log(context, config, 0, "PKINIT pre-authentication succeeded -- %s using %s", - client_name, client_cert); + r->client_name, client_cert); free(client_cert); - if (pkp) - goto preauth_done; } - ts_enc: -#endif - kdc_log(context, config, 5, "Looking for ENC-TS pa-data -- %s", - client_name); - - i = 0; - e_text = "No ENC-TS found"; - while((pa = _kdc_find_padata(req, &i, KRB5_PADATA_ENC_TIMESTAMP))){ - krb5_data ts_data; - PA_ENC_TS_ENC p; - size_t len; - EncryptedData enc_data; - Key *pa_key; - char *str; - - found_pa = 1; - - if (b->kdc_options.request_anonymous) { - ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; - kdc_log(context, config, 0, "ENC-TS doesn't support anon"); - goto out; - } - - ret = decode_EncryptedData(pa->padata_value.data, - pa->padata_value.length, - &enc_data, - &len); - if (ret) { - ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; - kdc_log(context, config, 5, "Failed to decode PA-DATA -- %s", - client_name); - goto out; - } - - ret = hdb_enctype2key(context, &client->entry, - enc_data.etype, &pa_key); - if(ret){ - char *estr; - e_text = "No key matches pa-data"; - ret = KRB5KDC_ERR_ETYPE_NOSUPP; - if(krb5_enctype_to_string(context, enc_data.etype, &estr)) - estr = NULL; - if(estr == NULL) - kdc_log(context, config, 5, - "No client key matching pa-data (%d) -- %s", - enc_data.etype, client_name); - else - kdc_log(context, config, 5, - "No client key matching pa-data (%s) -- %s", - estr, client_name); - free(estr); - free_EncryptedData(&enc_data); - - continue; - } - - try_next_key: - ret = krb5_crypto_init(context, &pa_key->key, 0, &crypto); - if (ret) { - const char *msg = krb5_get_error_message(context, ret); - kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg); - krb5_free_error_message(context, msg); - free_EncryptedData(&enc_data); - continue; - } - - ret = krb5_decrypt_EncryptedData (context, - crypto, - KRB5_KU_PA_ENC_TIMESTAMP, - &enc_data, - &ts_data); - krb5_crypto_destroy(context, crypto); - /* - * Since the user might have several keys with the same - * enctype but with diffrent salting, we need to try all - * the keys with the same enctype. - */ - if(ret){ - krb5_error_code ret2; - const char *msg = krb5_get_error_message(context, ret); - - ret2 = krb5_enctype_to_string(context, - pa_key->key.keytype, &str); - if (ret2) - str = NULL; - kdc_log(context, config, 5, - "Failed to decrypt PA-DATA -- %s " - "(enctype %s) error %s", - client_name, str ? str : "unknown enctype", msg); - krb5_free_error_message(context, msg); - free(str); - - if(hdb_next_enctype2key(context, &client->entry, - enc_data.etype, &pa_key) == 0) - goto try_next_key; - e_text = "Failed to decrypt PA-DATA"; - - free_EncryptedData(&enc_data); - - if (clientdb->hdb_auth_status) - (clientdb->hdb_auth_status)(context, clientdb, client, HDB_AUTH_WRONG_PASSWORD); - - ret = KRB5KDC_ERR_PREAUTH_FAILED; - continue; - } - free_EncryptedData(&enc_data); - ret = decode_PA_ENC_TS_ENC(ts_data.data, - ts_data.length, - &p, - &len); - krb5_data_free(&ts_data); - if(ret){ - e_text = "Failed to decode PA-ENC-TS-ENC"; - ret = KRB5KDC_ERR_PREAUTH_FAILED; - kdc_log(context, config, - 5, "Failed to decode PA-ENC-TS_ENC -- %s", - client_name); - continue; - } - if (abs(kdc_time - p.patimestamp) > context->max_skew) { - char client_time[100]; - - krb5_format_time(context, p.patimestamp, - client_time, sizeof(client_time), TRUE); - - ret = KRB5KRB_AP_ERR_SKEW; - kdc_log(context, config, 0, - "Too large time skew, " - "client time %s is out by %u > %u seconds -- %s", - client_time, - (unsigned)abs(kdc_time - p.patimestamp), - context->max_skew, - client_name); - - /* - * The following is needed to make windows clients to - * retry using the timestamp in the error message, if - * there is a e_text, they become unhappy. - */ - e_text = NULL; - free_PA_ENC_TS_ENC(&p); - goto out; - } - free_PA_ENC_TS_ENC(&p); - et.flags.pre_authent = 1; - - set_salt_padata(rep.padata, pa_key->salt); - - reply_key = &pa_key->key; - - ret = krb5_enctype_to_string(context, pa_key->key.keytype, &str); - if (ret) - str = NULL; - - kdc_log(context, config, 2, - "ENC-TS Pre-authentication succeeded -- %s using %s", - client_name, str ? str : "unknown enctype"); - free(str); - break; - } -#ifdef PKINIT preauth_done: #endif if(found_pa == 0 && config->require_preauth) @@ -1870,14 +1894,14 @@ _kdc_as_rep(krb5_context context, /* We come here if we found a pa-enc-timestamp, but if there was some problem with it, other than too large skew */ if(found_pa && et.flags.pre_authent == 0){ - kdc_log(context, config, 0, "%s -- %s", e_text, client_name); - e_text = NULL; + kdc_log(context, config, 0, "%s -- %s", r->e_text, r->client_name); + r->e_text = NULL; goto out; } }else if (config->require_preauth || b->kdc_options.request_anonymous /* hack to force anon */ - || client->entry.flags.require_preauth - || server->entry.flags.require_preauth) { + || r->client->entry.flags.require_preauth + || r->server->entry.flags.require_preauth) { size_t n; use_pa: for (n = 0; n < sizeof(pat) / sizeof(pat[0]); n++) { @@ -1922,25 +1946,25 @@ _kdc_as_rep(krb5_context context, } ret = KRB5KDC_ERR_PREAUTH_REQUIRED; - e_text ="Need to use PA-ENC-TIMESTAMP/PA-PK-AS-REQ", + r->e_text ="Need to use PA-ENC-TIMESTAMP/PA-PK-AS-REQ", kdc_log(context, config, 0, "No preauth found, returning PREAUTH-REQUIRED -- %s", - client_name); + r->client_name); goto out; } - if (clientdb->hdb_auth_status) - (clientdb->hdb_auth_status)(context, clientdb, client, - HDB_AUTH_SUCCESS); + if (r->clientdb->hdb_auth_status) + r->clientdb->hdb_auth_status(context, r->clientdb, r->client, + HDB_AUTH_SUCCESS); /* * Verify flags after the user been required to prove its identity * with in a preauth mech. */ - ret = _kdc_check_access(context, config, client, client_name, - server, server_name, + ret = _kdc_check_access(context, config, r->client, r->client_name, + r->server, r->server_name, req, &error_method); if(ret) goto out; @@ -1951,7 +1975,7 @@ _kdc_as_rep(krb5_context context, */ ret = _kdc_get_preferred_key(context, config, - server, server_name, + r->server, r->server_name, &setype, &skey); if(ret) goto out; @@ -1959,25 +1983,25 @@ _kdc_as_rep(krb5_context context, if(f.renew || f.validate || f.proxy || f.forwarded || f.enc_tkt_in_skey || (f.request_anonymous && !config->allow_anonymous)) { ret = KRB5KDC_ERR_BADOPTION; - e_text = "Bad KDC options"; - kdc_log(context, config, 0, "Bad KDC options -- %s", client_name); + r->e_text = "Bad KDC options"; + kdc_log(context, config, 0, "Bad KDC options -- %s", r->client_name); goto out; } rep.pvno = 5; rep.msg_type = krb_as_rep; - ret = copy_Realm(&client->entry.principal->realm, &rep.crealm); + ret = copy_Realm(&r->client->entry.principal->realm, &rep.crealm); if (ret) goto out; - ret = _krb5_principal2principalname(&rep.cname, client->entry.principal); + ret = _krb5_principal2principalname(&rep.cname, r->client->entry.principal); if (ret) goto out; rep.ticket.tkt_vno = 5; - copy_Realm(&server->entry.principal->realm, &rep.ticket.realm); + copy_Realm(&r->server->entry.principal->realm, &rep.ticket.realm); _krb5_principal2principalname(&rep.ticket.sname, - server->entry.principal); + r->server->entry.principal); /* java 1.6 expects the name to be the same type, lets allow that * uncomplicated name-types. */ #define CNT(sp,t) (((sp)->sname->name_type) == KRB5_NT_##t) @@ -1986,40 +2010,40 @@ _kdc_as_rep(krb5_context context, #undef CNT et.flags.initial = 1; - if(client->entry.flags.forwardable && server->entry.flags.forwardable) + if(r->client->entry.flags.forwardable && r->server->entry.flags.forwardable) et.flags.forwardable = f.forwardable; else if (f.forwardable) { - e_text = "Ticket may not be forwardable"; + r->e_text = "Ticket may not be forwardable"; ret = KRB5KDC_ERR_POLICY; kdc_log(context, config, 0, - "Ticket may not be forwardable -- %s", client_name); + "Ticket may not be forwardable -- %s", r->client_name); goto out; } - if(client->entry.flags.proxiable && server->entry.flags.proxiable) + if(r->client->entry.flags.proxiable && r->server->entry.flags.proxiable) et.flags.proxiable = f.proxiable; else if (f.proxiable) { - e_text = "Ticket may not be proxiable"; + r->e_text = "Ticket may not be proxiable"; ret = KRB5KDC_ERR_POLICY; kdc_log(context, config, 0, - "Ticket may not be proxiable -- %s", client_name); + "Ticket may not be proxiable -- %s", r->client_name); goto out; } - if(client->entry.flags.postdate && server->entry.flags.postdate) + if(r->client->entry.flags.postdate && r->server->entry.flags.postdate) et.flags.may_postdate = f.allow_postdate; else if (f.allow_postdate){ - e_text = "Ticket may not be postdate"; + r->e_text = "Ticket may not be postdate"; ret = KRB5KDC_ERR_POLICY; kdc_log(context, config, 0, - "Ticket may not be postdatable -- %s", client_name); + "Ticket may not be postdatable -- %s", r->client_name); goto out; } /* check for valid set of addresses */ if(!_kdc_check_addresses(context, config, b->addresses, from_addr)) { - e_text = "Bad address list in requested"; + r->e_text = "Bad address list in requested"; ret = KRB5KRB_AP_ERR_BADADDR; kdc_log(context, config, 0, - "Bad address list requested -- %s", client_name); + "Bad address list requested -- %s", r->client_name); goto out; } @@ -2047,10 +2071,10 @@ _kdc_as_rep(krb5_context context, /* be careful not overflowing */ - if(client->entry.max_life) - t = start + min(t - start, *client->entry.max_life); - if(server->entry.max_life) - t = start + min(t - start, *server->entry.max_life); + if(r->client->entry.max_life) + t = start + min(t - start, *r->client->entry.max_life); + if(r->server->entry.max_life) + t = start + min(t - start, *r->server->entry.max_life); #if 0 t = min(t, start + realm->max_life); #endif @@ -2068,10 +2092,10 @@ _kdc_as_rep(krb5_context context, t = *b->rtime; if(t == 0) t = MAX_TIME; - if(client->entry.max_renew) - t = start + min(t - start, *client->entry.max_renew); - if(server->entry.max_renew) - t = start + min(t - start, *server->entry.max_renew); + if(r->client->entry.max_renew) + t = start + min(t - start, *r->client->entry.max_renew); + if(r->server->entry.max_renew) + t = start + min(t - start, *r->server->entry.max_renew); #if 0 t = min(t, start + realm->max_renew); #endif @@ -2107,16 +2131,16 @@ _kdc_as_rep(krb5_context context, goto out; } ek.last_req.len = 0; - if (client->entry.pw_end + if (r->client->entry.pw_end && (config->kdc_warn_pwexpire == 0 - || kdc_time + config->kdc_warn_pwexpire >= *client->entry.pw_end)) { + || kdc_time + config->kdc_warn_pwexpire >= *r->client->entry.pw_end)) { ek.last_req.val[ek.last_req.len].lr_type = LR_PW_EXPTIME; - ek.last_req.val[ek.last_req.len].lr_value = *client->entry.pw_end; + ek.last_req.val[ek.last_req.len].lr_value = *r->client->entry.pw_end; ++ek.last_req.len; } - if (client->entry.valid_end) { + if (r->client->entry.valid_end) { ek.last_req.val[ek.last_req.len].lr_type = LR_ACCT_EXPTIME; - ek.last_req.val[ek.last_req.len].lr_value = *client->entry.valid_end; + ek.last_req.val[ek.last_req.len].lr_value = *r->client->entry.valid_end; ++ek.last_req.len; } if (ek.last_req.len == 0) { @@ -2125,16 +2149,16 @@ _kdc_as_rep(krb5_context context, ++ek.last_req.len; } ek.nonce = b->nonce; - if (client->entry.valid_end || client->entry.pw_end) { + if (r->client->entry.valid_end || r->client->entry.pw_end) { ALLOC(ek.key_expiration); - if (client->entry.valid_end) { - if (client->entry.pw_end) - *ek.key_expiration = min(*client->entry.valid_end, - *client->entry.pw_end); + if (r->client->entry.valid_end) { + if (r->client->entry.pw_end) + *ek.key_expiration = min(*r->client->entry.valid_end, + *r->client->entry.pw_end); else - *ek.key_expiration = *client->entry.valid_end; + *ek.key_expiration = *r->client->entry.valid_end; } else - *ek.key_expiration = *client->entry.pw_end; + *ek.key_expiration = *r->client->entry.pw_end; } else ek.key_expiration = NULL; ek.flags = et.flags; @@ -2157,10 +2181,10 @@ _kdc_as_rep(krb5_context context, #if PKINIT if (pkp) { - e_text = "Failed to build PK-INIT reply"; - ret = _kdc_pk_mk_pa_reply(context, config, pkp, client, + r->e_text = "Failed to build PK-INIT reply"; + ret = _kdc_pk_mk_pa_reply(context, config, pkp, r->client, sessionetype, req, req_buffer, - &reply_key, &et.key, rep.padata); + &r->reply_key, &et.key, rep.padata); if (ret) goto out; ret = _kdc_add_inital_verified_cas(context, @@ -2178,8 +2202,8 @@ _kdc_as_rep(krb5_context context, goto out; } - if (reply_key == NULL) { - e_text = "Client have no reply key"; + if (r->reply_key.keytype == ETYPE_NULL) { + r->e_text = "Client have no reply key"; ret = KRB5KDC_ERR_CLIENT_NOTYET; goto out; } @@ -2199,7 +2223,7 @@ _kdc_as_rep(krb5_context context, memset(&canon, 0, sizeof(canon)); canon.names.requested_name = *b->cname; - canon.names.mapped_name = client->entry.principal->name; + canon.names.mapped_name = r->client->entry.principal->name; ASN1_MALLOC_ENCODE(PA_ClientCanonicalizedNames, data.data, data.length, &canon.names, &len, ret); @@ -2250,22 +2274,22 @@ _kdc_as_rep(krb5_context context, krb5_pac p = NULL; krb5_data data; - ret = _kdc_pac_generate(context, client, &p); + ret = _kdc_pac_generate(context, r->client, &p); if (ret) { kdc_log(context, config, 0, "PAC generation failed for -- %s", - client_name); + r->client_name); goto out; } if (p != NULL) { ret = _krb5_pac_sign(context, p, et.authtime, - client->entry.principal, + r->client->entry.principal, &skey->key, /* Server key */ &skey->key, /* FIXME: should be krbtgt key */ &data); krb5_pac_free(context, p); if (ret) { kdc_log(context, config, 0, "PAC signing failed for -- %s", - client_name); + r->client_name); goto out; } @@ -2284,19 +2308,19 @@ _kdc_as_rep(krb5_context context, /* do this as the last thing since this signs the EncTicketPart */ ret = _kdc_add_KRB5SignedPath(context, config, - server, + r->server, setype, - client->entry.principal, + r->client->entry.principal, NULL, NULL, &et); if (ret) goto out; - log_as_req(context, config, reply_key->keytype, setype, b); + log_as_req(context, config, r->reply_key.keytype, setype, b); { - PA_DATA *pa; + const PA_DATA *pa; int i = 0; pa = _kdc_find_padata(req, &i, KRB5_PADATA_REQ_ENC_PA_REP); @@ -2305,10 +2329,10 @@ _kdc_as_rep(krb5_context context, } ret = _kdc_encode_reply(context, config, req_buffer, - armor_crypto, req->req_body.nonce, - &rep, &et, &ek, setype, server->entry.kvno, - &skey->key, client->entry.kvno, - reply_key, 0, &e_text, reply); + r->armor_crypto, req->req_body.nonce, + &rep, &et, &ek, setype, r->server->entry.kvno, + &skey->key, r->client->entry.kvno, + &r->reply_key, 0, &r->e_text, reply); if (ret) goto out; @@ -2316,7 +2340,7 @@ _kdc_as_rep(krb5_context context, if (datagram_reply && reply->length > config->max_datagram_reply_length) { krb5_data_free(reply); ret = KRB5KRB_ERR_RESPONSE_TOO_BIG; - e_text = "Reply packet too large"; + r->e_text = "Reply packet too large"; } out: @@ -2329,10 +2353,10 @@ out: kdc_log(context, config, 10, "as-req: sending error: %d to client", ret); ret = _kdc_fast_mk_error(context, &error_method, - armor_crypto, + r->armor_crypto, &req->req_body, - ret, e_text, - client_princ, server_princ, + ret, r->e_text, + r->client_princ, r->server_princ, NULL, NULL, reply); if (ret) @@ -2348,18 +2372,34 @@ out2: if (error_method.len) free_METHOD_DATA(&error_method); - if (client_princ) - krb5_free_principal(context, client_princ); - free(client_name); - if (server_princ) - krb5_free_principal(context, server_princ); - free(server_name); - if(client) - _kdc_free_ent(context, client); - if(server) - _kdc_free_ent(context, server); - if (armor_crypto) - krb5_crypto_destroy(context, armor_crypto); + if (r->outpadata.len) + free_METHOD_DATA(&r->outpadata); + if (r->client_princ) { + krb5_free_principal(context, r->client_princ); + r->client_princ = NULL; + } + if (r->client_name) { + free(r->client_name); + r->client_name = NULL; + } + if (r->server_princ){ + krb5_free_principal(context, r->server_princ); + r->server_princ = NULL; + } + if (r->server_name) { + free(r->server_name); + r->server_name = NULL; + } + if (r->client) + _kdc_free_ent(context, r->client); + if (r->server) + _kdc_free_ent(context, r->server); + if (r->armor_crypto) { + krb5_crypto_destroy(r->context, r->armor_crypto); + r->armor_crypto = NULL; + } + krb5_free_keyblock_contents(r->context, &r->reply_key); + krb5_free_keyblock_contents(r->context, &r->session_key); return ret; } diff --git a/kdc/pkinit.c b/kdc/pkinit.c index d85b15650..7d81829b7 100644 --- a/kdc/pkinit.c +++ b/kdc/pkinit.c @@ -1237,7 +1237,7 @@ _kdc_pk_mk_pa_reply(krb5_context context, krb5_enctype sessionetype, const KDC_REQ *req, const krb5_data *req_buffer, - krb5_keyblock **reply_key, + krb5_keyblock *reply_key, krb5_keyblock *sessionkey, METHOD_DATA *md) { @@ -1563,7 +1563,7 @@ out: hx509_cert_free(kdc_cert); if (ret == 0) - *reply_key = &cp->reply_key; + ret = krb5_copy_keyblock_contents(context, &cp->reply_key, reply_key); return ret; } diff --git a/kdc/process.c b/kdc/process.c index 6f3691580..c6535bb22 100644 --- a/kdc/process.c +++ b/kdc/process.c @@ -57,19 +57,25 @@ kdc_as_req(krb5_context context, int datagram_reply, int *claim) { + struct kdc_request_desc r; krb5_error_code ret; - KDC_REQ req; size_t len; - ret = decode_AS_REQ(req_buffer->data, req_buffer->length, &req, &len); + memset(&r, 0, sizeof(r)); + + ret = decode_AS_REQ(req_buffer->data, req_buffer->length, &r.req, &len); if (ret) return ret; + r.context = context; + r.config = config; + r.request.data = req_buffer->data; + r.request.length = req_buffer->length; + *claim = 1; - ret = _kdc_as_rep(context, config, &req, req_buffer, - reply, from, addr, datagram_reply); - free_AS_REQ(&req); + ret = _kdc_as_rep(&r, reply, from, addr, datagram_reply); + free_AS_REQ(&r.req); return ret; } diff --git a/tests/kdc/check-fast.in b/tests/kdc/check-fast.in index c565f25db..15321bb90 100644 --- a/tests/kdc/check-fast.in +++ b/tests/kdc/check-fast.in @@ -43,7 +43,7 @@ export KRB5_CONFIG testfailed="echo test failed; cat messages.log; exit 1" # If there is no useful db support compile in, disable test -${have_db} || exit 77 +#${have_db} || exit 77 R=TEST.H5L.SE @@ -139,6 +139,9 @@ if [ -f ${mit}/kinit ] ; then echo "Checking for FAST avail" ${klist} --hidden | grep fast_avail > /dev/null || { exit 1; } + echo "Getting service ticket" + ${mit}/kvno -c ${cache} ${server}@${R} || { exit 1; } + fi From 07342aa1388d0212d7721b3543ee1ff020daed8e Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Wed, 11 May 2011 09:53:28 -0700 Subject: [PATCH 050/119] Add and use _kdc_set_e_text() --- kdc/kerberos5.c | 58 +++++++++++++++++++++---------------------------- 1 file changed, 25 insertions(+), 33 deletions(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index db1494208..435dee11f 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -241,6 +241,13 @@ _kdc_make_anonymous_principalname (PrincipalName *pn) return 0; } +static void +_kdc_set_e_text(kdc_request_t r, const char *e_text) +{ + r->e_text = e_text; + kdc_log(r->context, r->config, 0, "%s", e_text); +} + void _kdc_log_timestamp(krb5_context context, krb5_kdc_configuration *config, @@ -457,8 +464,7 @@ pa_enc_ts_validate(kdc_request_t r, const PA_DATA *pa) if (r->req.req_body.kdc_options.request_anonymous) { ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; - r->e_text = "ENC-TS doesn't suport anon"; - kdc_log(r->context, r->config, 0, "ENC-TS doesn't support anon"); + _kdc_set_e_text(r, "ENC-TS doesn't suport anon"); goto out; } @@ -477,7 +483,7 @@ pa_enc_ts_validate(kdc_request_t r, const PA_DATA *pa) enc_data.etype, &pa_key); if(ret){ char *estr; - r->e_text = "No key matching entype"; + _kdc_set_e_text(r, "No key matching entype"); ret = KRB5KDC_ERR_ETYPE_NOSUPP; if(krb5_enctype_to_string(r->context, enc_data.etype, &estr)) estr = NULL; @@ -1688,7 +1694,7 @@ _kdc_as_rep(kdc_request_t r, if(b->sname == NULL){ ret = KRB5KRB_ERR_GENERIC; - r->e_text = "No server in request"; + _kdc_set_e_text(r, "No server in request"); } else{ ret = _krb5_principalname2krb5_principal (context, &r->server_princ, @@ -1704,7 +1710,7 @@ _kdc_as_rep(kdc_request_t r, } if(b->cname == NULL){ ret = KRB5KRB_ERR_GENERIC; - r->e_text = "No client in request"; + _kdc_set_e_text(r, "No client in request"); } else { ret = _krb5_principalname2krb5_principal (context, &r->client_princ, @@ -1842,7 +1848,7 @@ _kdc_as_rep(kdc_request_t r, kdc_log(context, config, 5, "Looking for PKINIT pa-data -- %s", r->client_name); - r->e_text = "No PKINIT PA found"; + _kdc_set_e_text(r, "No PKINIT PA found"); i = 0; pa = _kdc_find_padata(req, &i, KRB5_PADATA_PK_AS_REQ); @@ -1871,11 +1877,9 @@ _kdc_as_rep(kdc_request_t r, pkp, &client_cert); if (ret) { - r->e_text = "PKINIT certificate not allowed to " - "impersonate principal"; + _kdc_set_e_text(r, "PKINIT certificate not allowed to " + "impersonate principal"); _kdc_pk_free_client_param(context, pkp); - - kdc_log(context, config, 0, "%s", r->e_text); pkp = NULL; goto out; } @@ -1946,11 +1950,7 @@ _kdc_as_rep(kdc_request_t r, } ret = KRB5KDC_ERR_PREAUTH_REQUIRED; - r->e_text ="Need to use PA-ENC-TIMESTAMP/PA-PK-AS-REQ", - - kdc_log(context, config, 0, - "No preauth found, returning PREAUTH-REQUIRED -- %s", - r->client_name); + _kdc_set_e_text(r, "Need to use PA-ENC-TIMESTAMP/PA-PK-AS-REQ"); goto out; } @@ -1983,8 +1983,7 @@ _kdc_as_rep(kdc_request_t r, if(f.renew || f.validate || f.proxy || f.forwarded || f.enc_tkt_in_skey || (f.request_anonymous && !config->allow_anonymous)) { ret = KRB5KDC_ERR_BADOPTION; - r->e_text = "Bad KDC options"; - kdc_log(context, config, 0, "Bad KDC options -- %s", r->client_name); + _kdc_set_e_text(r, "Bad KDC options"); goto out; } @@ -2013,37 +2012,29 @@ _kdc_as_rep(kdc_request_t r, if(r->client->entry.flags.forwardable && r->server->entry.flags.forwardable) et.flags.forwardable = f.forwardable; else if (f.forwardable) { - r->e_text = "Ticket may not be forwardable"; + _kdc_set_e_text(r, "Ticket may not be forwardable"); ret = KRB5KDC_ERR_POLICY; - kdc_log(context, config, 0, - "Ticket may not be forwardable -- %s", r->client_name); goto out; } if(r->client->entry.flags.proxiable && r->server->entry.flags.proxiable) et.flags.proxiable = f.proxiable; else if (f.proxiable) { - r->e_text = "Ticket may not be proxiable"; + _kdc_set_e_text(r, "Ticket may not be proxiable"); ret = KRB5KDC_ERR_POLICY; - kdc_log(context, config, 0, - "Ticket may not be proxiable -- %s", r->client_name); goto out; } if(r->client->entry.flags.postdate && r->server->entry.flags.postdate) et.flags.may_postdate = f.allow_postdate; else if (f.allow_postdate){ - r->e_text = "Ticket may not be postdate"; + _kdc_set_e_text(r, "Ticket may not be postdate"); ret = KRB5KDC_ERR_POLICY; - kdc_log(context, config, 0, - "Ticket may not be postdatable -- %s", r->client_name); goto out; } /* check for valid set of addresses */ if(!_kdc_check_addresses(context, config, b->addresses, from_addr)) { - r->e_text = "Bad address list in requested"; + _kdc_set_e_text(r, "Bad address list in requested"); ret = KRB5KRB_AP_ERR_BADADDR; - kdc_log(context, config, 0, - "Bad address list requested -- %s", r->client_name); goto out; } @@ -2181,12 +2172,13 @@ _kdc_as_rep(kdc_request_t r, #if PKINIT if (pkp) { - r->e_text = "Failed to build PK-INIT reply"; ret = _kdc_pk_mk_pa_reply(context, config, pkp, r->client, sessionetype, req, req_buffer, &r->reply_key, &et.key, rep.padata); - if (ret) + if (ret) { + _kdc_set_e_text(r, "Failed to build PK-INIT reply"); goto out; + } ret = _kdc_add_inital_verified_cas(context, config, pkp, @@ -2203,7 +2195,7 @@ _kdc_as_rep(kdc_request_t r, } if (r->reply_key.keytype == ETYPE_NULL) { - r->e_text = "Client have no reply key"; + _kdc_set_e_text(r, "Client have no reply key"); ret = KRB5KDC_ERR_CLIENT_NOTYET; goto out; } @@ -2340,7 +2332,7 @@ _kdc_as_rep(kdc_request_t r, if (datagram_reply && reply->length > config->max_datagram_reply_length) { krb5_data_free(reply); ret = KRB5KRB_ERR_RESPONSE_TOO_BIG; - r->e_text = "Reply packet too large"; + _kdc_set_e_text(r, "Reply packet too large"); } out: From 68bd6f63e8ab4e882ae2769140c5273d6e2f62b8 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Wed, 11 May 2011 23:17:48 -0700 Subject: [PATCH 051/119] move PKINIT to a preauth mech too --- kdc/kdc_locl.h | 2 +- kdc/kerberos5.c | 201 +++++++++++++++++++++++++----------------------- 2 files changed, 106 insertions(+), 97 deletions(-) diff --git a/kdc/kdc_locl.h b/kdc/kdc_locl.h index 40dcae16b..2ed399716 100644 --- a/kdc/kdc_locl.h +++ b/kdc/kdc_locl.h @@ -66,7 +66,7 @@ struct kdc_request_desc { EncKDCRepPart ek; /* PA methods can affect both the reply key and the session key (pkinit) */ - krb5_keyblock sessionetype; + krb5_enctype sessionetype; krb5_keyblock reply_key; krb5_keyblock session_key; diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 435dee11f..b3dc9db45 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -278,6 +278,69 @@ _kdc_log_timestamp(krb5_context context, type, authtime_str, starttime_str, endtime_str, renewtime_str); } +/* + * + */ + +#ifdef PKINIT + +static krb5_error_code +pa_pkinit_validate(kdc_request_t r, const PA_DATA *pa) +{ + char *client_cert = NULL; + krb5_error_code ret; + pk_client_params *pkp = NULL; + + ret = _kdc_pk_rd_padata(r->context, r->config, &r->req, pa, r->client, &pkp); + if (ret || pkp == NULL) { + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + kdc_log(r->context, r->config, 5, + "Failed to decode PKINIT PA-DATA -- %s", + r->client_name); + goto out; + } + + ret = _kdc_pk_check_client(r->context, + r->config, + r->clientdb, + r->client, + pkp, + &client_cert); + if (ret) { + _kdc_set_e_text(r, "PKINIT certificate not allowed to " + "impersonate principal"); + goto out; + } + + kdc_log(r->context, r->config, 0, + "PKINIT pre-authentication succeeded -- %s using %s", + r->client_name, client_cert); + free(client_cert); + + ret = _kdc_pk_mk_pa_reply(r->context, r->config, pkp, r->client, + r->sessionetype, &r->req, &r->request, + &r->reply_key, &r->session_key, &r->outpadata); + if (ret) { + _kdc_set_e_text(r, "Failed to build PK-INIT reply"); + goto out; + } +#if 0 + ret = _kdc_add_inital_verified_cas(r->context, r->config, + pkp, &r->et); +#endif + out: + if (pkp) + _kdc_pk_free_client_param(r->context, pkp); + + return ret; +} + +#endif /* PKINIT */ + +/* + * + */ + static krb5_error_code make_pa_enc_challange(krb5_context context, METHOD_DATA *md, krb5_crypto crypto) @@ -620,13 +683,19 @@ struct kdc_patypes { static const struct kdc_patypes pat[] = { #ifdef PKINIT - { KRB5_PADATA_PK_AS_REQ, "PK-INIT(ietf)", PA_ANNOUNCE }, - { KRB5_PADATA_PK_AS_REQ_WIN, "PK-INIT(win2k)", PA_ANNOUNCE }, + { + KRB5_PADATA_PK_AS_REQ, "PK-INIT(ietf)", PA_ANNOUNCE, + pa_pkinit_validate + }, + { + KRB5_PADATA_PK_AS_REQ_WIN, "PK-INIT(win2k)", PA_ANNOUNCE, + pa_pkinit_validate + }, #else - { KRB5_PADATA_PK_AS_REQ, "PK-INIT(ietf)", 0 }, - { KRB5_PADATA_PK_AS_REQ_WIN, "PK-INIT(win2k)", 0 }, + { KRB5_PADATA_PK_AS_REQ, "PK-INIT(ietf)", 0, NULL }, + { KRB5_PADATA_PK_AS_REQ_WIN, "PK-INIT(win2k)", 0, NULL }, #endif - { KRB5_PADATA_PA_PK_OCSP_RESPONSE , "OCSP", 0 }, + { KRB5_PADATA_PA_PK_OCSP_RESPONSE , "OCSP", 0, NULL }, { KRB5_PADATA_ENC_TIMESTAMP , "ENC-TS", PA_ANNOUNCE, @@ -637,10 +706,10 @@ static const struct kdc_patypes pat[] = { PA_ANNOUNCE | PA_REQ_FAST, pa_enc_chal_validate }, - { KRB5_PADATA_REQ_ENC_PA_REP , "REQ-ENC-PA-REP", 0 }, - { KRB5_PADATA_FX_FAST, "FX-FAST", PA_ANNOUNCE }, - { KRB5_PADATA_FX_ERROR, "FX-ERROR", 0 }, - { KRB5_PADATA_FX_COOKIE, "FX-COOKIE", 0 } + { KRB5_PADATA_REQ_ENC_PA_REP , "REQ-ENC-PA-REP", 0, NULL }, + { KRB5_PADATA_FX_FAST, "FX-FAST", PA_ANNOUNCE, NULL }, + { KRB5_PADATA_FX_ERROR, "FX-ERROR", 0, NULL }, + { KRB5_PADATA_FX_COOKIE, "FX-COOKIE", 0, NULL } }; static void @@ -1658,15 +1727,12 @@ _kdc_as_rep(kdc_request_t r, KDC_REQ_BODY *b = NULL; AS_REP rep; KDCOptions f; - krb5_enctype setype, sessionetype; + krb5_enctype setype; EncTicketPart et; EncKDCRepPart ek; krb5_error_code ret = 0; Key *ckey, *skey; int flags = 0; -#ifdef PKINIT - pk_client_params *pkp = NULL; -#endif METHOD_DATA error_method; memset(&rep, 0, sizeof(rep)); @@ -1675,10 +1741,6 @@ _kdc_as_rep(kdc_request_t r, error_method.len = 0; error_method.val = NULL; - ALLOC(rep.padata); - rep.padata->len = 0; - rep.padata->val = NULL; - /* * Look for FAST armor and unwrap */ @@ -1794,6 +1856,7 @@ _kdc_as_rep(kdc_request_t r, * enctype that an older version of a KDC in the same realm can't * decrypt. */ + ret = _kdc_find_etype(context, config->as_use_strongest_session_key, FALSE, client, b->etype.val, b->etype.len, &sessionetype, NULL); @@ -1841,58 +1904,8 @@ _kdc_as_rep(kdc_request_t r, if (found_pa) { et.flags.pre_authent = 1; - goto preauth_done; } -#ifdef PKINIT - kdc_log(context, config, 5, - "Looking for PKINIT pa-data -- %s", r->client_name); - - _kdc_set_e_text(r, "No PKINIT PA found"); - - i = 0; - pa = _kdc_find_padata(req, &i, KRB5_PADATA_PK_AS_REQ); - if (pa == NULL) { - i = 0; - pa = _kdc_find_padata(req, &i, KRB5_PADATA_PK_AS_REQ_WIN); - } - if (pa) { - char *client_cert = NULL; - - ret = _kdc_pk_rd_padata(context, config, req, pa, r->client, &pkp); - if (ret) { - ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; - kdc_log(context, config, 5, - "Failed to decode PKINIT PA-DATA -- %s", - r->client_name); - goto out; - } - if (ret == 0 && pkp == NULL) - goto out; - - ret = _kdc_pk_check_client(context, - config, - r->clientdb, - r->client, - pkp, - &client_cert); - if (ret) { - _kdc_set_e_text(r, "PKINIT certificate not allowed to " - "impersonate principal"); - _kdc_pk_free_client_param(context, pkp); - pkp = NULL; - goto out; - } - - found_pa = 1; - et.flags.pre_authent = 1; - kdc_log(context, config, 0, - "PKINIT pre-authentication succeeded -- %s using %s", - r->client_name, client_cert); - free(client_cert); - } - preauth_done: -#endif if(found_pa == 0 && config->require_preauth) goto use_pa; /* We come here if we found a pa-enc-timestamp, but if there @@ -2170,26 +2183,12 @@ _kdc_as_rep(kdc_request_t r, copy_HostAddresses(et.caddr, ek.caddr); } -#if PKINIT - if (pkp) { - ret = _kdc_pk_mk_pa_reply(context, config, pkp, r->client, - sessionetype, req, req_buffer, - &r->reply_key, &et.key, rep.padata); - if (ret) { - _kdc_set_e_text(r, "Failed to build PK-INIT reply"); - goto out; - } - ret = _kdc_add_inital_verified_cas(context, - config, - pkp, - &et); - if (ret) - goto out; + /* + * Check and session and reply keys + */ - } else -#endif - { - ret = krb5_generate_random_keyblock(context, sessionetype, &et.key); + if (r->session_key.keytype == ETYPE_NULL) { + ret = krb5_generate_random_keyblock(context, r->sessionetype, &r->session_key); if (ret) goto out; } @@ -2200,11 +2199,18 @@ _kdc_as_rep(kdc_request_t r, goto out; } - ret = copy_EncryptionKey(&et.key, &ek.key); + ret = copy_EncryptionKey(&r->session_key, &et.key); if (ret) goto out; - /* Add signing of alias referral */ + ret = copy_EncryptionKey(&r->session_key, &ek.key); + if (ret) + goto out; + + /* + * Add signing of alias referral + */ + if (f.canonicalize) { PA_ClientCanonicalized canon; krb5_data data; @@ -2250,15 +2256,22 @@ _kdc_as_rep(kdc_request_t r, pa.padata_type = KRB5_PADATA_CLIENT_CANONICALIZED; pa.padata_value = data; - ret = add_METHOD_DATA(rep.padata, &pa); + ret = add_METHOD_DATA(&r->outpadata, &pa); free(data.data); if (ret) goto out; } - if (rep.padata->len == 0) { - free(rep.padata); - rep.padata = NULL; + if (r->outpadata.len) { + + ALLOC(rep.padata); + if (rep.padata == NULL) { + ret = ENOMEM; + goto out; + } + ret = copy_METHOD_DATA(&r->outpadata, rep.padata); + if (ret) + goto out; } /* Add the PAC */ @@ -2355,10 +2368,6 @@ out: goto out2; } out2: -#ifdef PKINIT - if (pkp) - _kdc_pk_free_client_param(context, pkp); -#endif free_EncTicketPart(&et); free_EncKDCRepPart(&ek); From 1e048065c12f998dc22c111a287ae98a1ca30308 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Wed, 11 May 2011 23:25:02 -0700 Subject: [PATCH 052/119] switch to _kdc_r_log --- kdc/kerberos5.c | 93 +++++++++++++++++++++++++------------------------ 1 file changed, 48 insertions(+), 45 deletions(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index b3dc9db45..9979fbad6 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -241,6 +241,17 @@ _kdc_make_anonymous_principalname (PrincipalName *pn) return 0; } +static void +_kdc_r_log(kdc_request_t r, int level, const char *fmt, ...) +{ + va_list ap; + char *s; + va_start(ap, fmt); + s = kdc_log_msg_va(r->context, r->config, level, fmt, ap); + if(s) free(s); + va_end(ap); +} + static void _kdc_set_e_text(kdc_request_t r, const char *e_text) { @@ -287,16 +298,15 @@ _kdc_log_timestamp(krb5_context context, static krb5_error_code pa_pkinit_validate(kdc_request_t r, const PA_DATA *pa) { + pk_client_params *pkp = NULL; char *client_cert = NULL; krb5_error_code ret; - pk_client_params *pkp = NULL; ret = _kdc_pk_rd_padata(r->context, r->config, &r->req, pa, r->client, &pkp); if (ret || pkp == NULL) { ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; - kdc_log(r->context, r->config, 5, - "Failed to decode PKINIT PA-DATA -- %s", - r->client_name); + _kdc_r_log(r, 5, "Failed to decode PKINIT PA-DATA -- %s", + r->client_name); goto out; } @@ -312,9 +322,8 @@ pa_pkinit_validate(kdc_request_t r, const PA_DATA *pa) goto out; } - kdc_log(r->context, r->config, 0, - "PKINIT pre-authentication succeeded -- %s using %s", - r->client_name, client_cert); + _kdc_r_log(r, 0, "PKINIT pre-authentication succeeded -- %s using %s", + r->client_name, client_cert); free(client_cert); ret = _kdc_pk_mk_pa_reply(r->context, r->config, pkp, r->client, @@ -414,8 +423,8 @@ pa_enc_chal_validate(kdc_request_t r, const PA_DATA *pa) &size); if (ret) { ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; - kdc_log(r->context, r->config, 5, "Failed to decode PA-DATA -- %s", - r->client_name); + _kdc_r_log(r, 5, "Failed to decode PA-DATA -- %s", + r->client_name); return ret; } @@ -464,9 +473,8 @@ pa_enc_chal_validate(kdc_request_t r, const PA_DATA *pa) if(ret){ krb5_crypto_destroy(r->context, challangecrypto); ret = KRB5KDC_ERR_PREAUTH_FAILED; - kdc_log(r->context, r->config, - 5, "Failed to decode PA-ENC-TS_ENC -- %s", - r->client_name); + _kdc_r_log(r, 5, "Failed to decode PA-ENC-TS_ENC -- %s", + r->client_name); continue; } @@ -479,13 +487,12 @@ pa_enc_chal_validate(kdc_request_t r, const PA_DATA *pa) client_time, sizeof(client_time), TRUE); ret = KRB5KRB_AP_ERR_SKEW; - kdc_log(r->context, r->config, 0, - "Too large time skew, " - "client time %s is out by %u > %u seconds -- %s", - client_time, - (unsigned)abs(kdc_time - p.patimestamp), - r->context->max_skew, - r->client_name); + _kdc_r_log(r, 0, "Too large time skew, " + "client time %s is out by %u > %u seconds -- %s", + client_time, + (unsigned)abs(kdc_time - p.patimestamp), + r->context->max_skew, + r->client_name); free_PA_ENC_TS_ENC(&p); goto out; @@ -537,8 +544,8 @@ pa_enc_ts_validate(kdc_request_t r, const PA_DATA *pa) &len); if (ret) { ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; - kdc_log(r->context, r->config, 5, "Failed to decode PA-DATA -- %s", - r->client_name); + _kdc_r_log(r, 5, "Failed to decode PA-DATA -- %s", + r->client_name); goto out; } @@ -551,13 +558,13 @@ pa_enc_ts_validate(kdc_request_t r, const PA_DATA *pa) if(krb5_enctype_to_string(r->context, enc_data.etype, &estr)) estr = NULL; if(estr == NULL) - kdc_log(r->context, r->config, 5, - "No client key matching pa-data (%d) -- %s", - enc_data.etype, r->client_name); + _kdc_r_log(r, 5, + "No client key matching pa-data (%d) -- %s", + enc_data.etype, r->client_name); else - kdc_log(r->context, r->config, 5, - "No client key matching pa-data (%s) -- %s", - estr, r->client_name); + _kdc_r_log(r, 5, + "No client key matching pa-data (%s) -- %s", + estr, r->client_name); free(estr); free_EncryptedData(&enc_data); goto out; @@ -567,7 +574,7 @@ pa_enc_ts_validate(kdc_request_t r, const PA_DATA *pa) ret = krb5_crypto_init(r->context, &pa_key->key, 0, &crypto); if (ret) { const char *msg = krb5_get_error_message(r->context, ret); - kdc_log(r->context, r->config, 0, "krb5_crypto_init failed: %s", msg); + _kdc_r_log(r, 0, "krb5_crypto_init failed: %s", msg); krb5_free_error_message(r->context, msg); free_EncryptedData(&enc_data); goto out; @@ -592,10 +599,9 @@ pa_enc_ts_validate(kdc_request_t r, const PA_DATA *pa) pa_key->key.keytype, &str); if (ret2) str = NULL; - kdc_log(r->context, r->config, 5, - "Failed to decrypt PA-DATA -- %s " - "(enctype %s) error %s", - r->client_name, str ? str : "unknown enctype", msg); + _kdc_r_log(r, 5, "Failed to decrypt PA-DATA -- %s " + "(enctype %s) error %s", + r->client_name, str ? str : "unknown enctype", msg); krb5_free_error_message(r->context, msg); free(str); @@ -620,9 +626,8 @@ pa_enc_ts_validate(kdc_request_t r, const PA_DATA *pa) krb5_data_free(&ts_data); if(ret){ ret = KRB5KDC_ERR_PREAUTH_FAILED; - kdc_log(r->context, r->config, - 5, "Failed to decode PA-ENC-TS_ENC -- %s", - r->client_name); + _kdc_r_log(r, 5, "Failed to decode PA-ENC-TS_ENC -- %s", + r->client_name); goto out; } if (abs(kdc_time - p.patimestamp) > r->context->max_skew) { @@ -632,13 +637,12 @@ pa_enc_ts_validate(kdc_request_t r, const PA_DATA *pa) client_time, sizeof(client_time), TRUE); ret = KRB5KRB_AP_ERR_SKEW; - kdc_log(r->context, r->config, 0, - "Too large time skew, " - "client time %s is out by %u > %u seconds -- %s", - client_time, - (unsigned)abs(kdc_time - p.patimestamp), - r->context->max_skew, - r->client_name); + _kdc_r_log(r, 0, "Too large time skew, " + "client time %s is out by %u > %u seconds -- %s", + client_time, + (unsigned)abs(kdc_time - p.patimestamp), + r->context->max_skew, + r->client_name); /* * The following is needed to make windows clients to @@ -660,9 +664,8 @@ pa_enc_ts_validate(kdc_request_t r, const PA_DATA *pa) ret = krb5_enctype_to_string(r->context, pa_key->key.keytype, &str); if (ret) str = NULL; - kdc_log(r->context, r->config, 2, - "ENC-TS Pre-authentication succeeded -- %s using %s", - r->client_name, str ? str : "unknown enctype"); + _kdc_r_log(r, 2, "ENC-TS Pre-authentication succeeded -- %s using %s", + r->client_name, str ? str : "unknown enctype"); free(str); ret = 0; From 6319f31ecfee3d4425af8002117a998bb49ffa29 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Thu, 12 May 2011 20:47:24 -0700 Subject: [PATCH 053/119] break out KRB5_PADATA_REQ_ENC_PA_REP --- kdc/kerberos5.c | 358 ++++++++++-------------------------------------- 1 file changed, 75 insertions(+), 283 deletions(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 9979fbad6..2ee98dd52 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -752,6 +752,62 @@ log_patypes(krb5_context context, * */ +static krb5_error_code +add_enc_pa_rep(krb5_context context, + krb5_kdc_configuration *config, + EncTicketPart *et, EncKDCRepPart *ek, + const krb5_data *req_buffer, + const krb5_keyblock *reply_key) +{ + krb5_error_code ret; + krb5_crypto crypto; + Checksum checksum; + krb5_data cdata; + size_t len; + + et->flags.enc_pa_rep = ek->flags.enc_pa_rep = 1; + + ret = krb5_crypto_init(context, reply_key, 0, &crypto); + if (ret) { + const char *msg = krb5_get_error_message(context, ret); + kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg); + krb5_free_error_message(context, msg); + return ret; + } + + ret = krb5_create_checksum(context, crypto, + KRB5_KU_AS_REQ, 0, + req_buffer->data, req_buffer->length, + &checksum); + krb5_crypto_destroy(context, crypto); + if (ret) + return ret; + + ASN1_MALLOC_ENCODE(Checksum, cdata.data, cdata.length, + &checksum, &len, ret); + free_Checksum(&checksum); + if (ret) + return ret; + + if (ek->encrypted_pa_data == NULL) { + ALLOC(ek->encrypted_pa_data); + if (ek->encrypted_pa_data == NULL) + return ENOMEM; + } + ret = krb5_padata_add(context, ek->encrypted_pa_data, + KRB5_PADATA_REQ_ENC_PA_REP, cdata.data, cdata.length); + if (ret) + return ret; + + ret = krb5_padata_add(context, ek->encrypted_pa_data, + KRB5_PADATA_FX_FAST, NULL, 0); + + return ret; +} + +/* + * + */ krb5_error_code _kdc_encode_reply(krb5_context context, @@ -772,44 +828,9 @@ _kdc_encode_reply(krb5_context context, krb5_error_code ret; krb5_crypto crypto; - if (rep->msg_type == krb_as_rep && req_buffer) { - Checksum checksum; - krb5_data cdata; - - et->flags.enc_pa_rep = 1; - ek->flags.enc_pa_rep = 1; - - ret = krb5_crypto_init(context, reply_key, 0, &crypto); - if (ret) { - const char *msg = krb5_get_error_message(context, ret); - free(buf); - kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg); - krb5_free_error_message(context, msg); - return ret; - } - - ret = krb5_create_checksum(context, crypto, - KRB5_KU_AS_REQ, 0, - req_buffer->data, req_buffer->length, - &checksum); - krb5_crypto_destroy(context, crypto); - if (ret) { - return ret; - } - ASN1_MALLOC_ENCODE(Checksum, cdata.data, cdata.length, - &checksum, &len, ret); - free_Checksum(&checksum); - if (ret) { - return ret; - } - ek->encrypted_pa_data = calloc(1, sizeof(*ek->encrypted_pa_data)); - ret = krb5_padata_add(context, ek->encrypted_pa_data, - KRB5_PADATA_REQ_ENC_PA_REP, cdata.data, cdata.length); - if (ret) { - return ret; - } - ret = krb5_padata_add(context, ek->encrypted_pa_data, - KRB5_PADATA_FX_FAST, NULL, 0); + if (req_buffer && rep->msg_type == krb_as_rep) { + ret = add_enc_pa_rep(context, config, + et, ek, req_buffer, reply_key); if (ret) return ret; } @@ -1483,232 +1504,12 @@ _kdc_is_anonymous(krb5_context context, krb5_principal principal) return 1; } -static krb5_error_code -unwrap_fast(krb5_context context, - krb5_kdc_configuration *config, - KDC_REQ *req, - krb5_crypto *armor_crypto) +static int +require_preauth_p(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(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(context, 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(context, config, 0, - "AS-REQ armor missing"); - ret = KRB5KDC_ERR_PREAUTH_FAILED; - goto out; - } - - if (fxreq.u.armored_data.armor->armor_type != 1) { - kdc_log(context, config, 0, - "AS-REQ armor type not ap-req"); - ret = KRB5KDC_ERR_PREAUTH_FAILED; - goto out; - } - - ret = krb5_decode_ap_req(context, - &fxreq.u.armored_data.armor->armor_value, - &ap_req); - if(ret) { - kdc_log(context, config, 0, "AP-REQ decode failed"); - goto out; - } - - /* Save that principal that was in the request */ - ret = _krb5_principalname2krb5_principal(context, - &armor_server, - ap_req.ticket.sname, - ap_req.ticket.realm); - if (ret) { - free_AP_REQ(&ap_req); - goto out; - } - - ret = _kdc_db_fetch(context, config, armor_server, - HDB_F_GET_SERVER, NULL, NULL, &armor_user); - if(ret == HDB_ERR_NOT_FOUND_HERE) { - kdc_log(context, 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(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(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(context, ac); - kdc_log(context, config, 0, - "FAST AP-REQ remote subkey missing"); - ret = KRB5KDC_ERR_PREAUTH_FAILED; - goto out; - } - - ret = krb5_crypto_init(context, ac->remote_subkey, - 0, &crypto_subkey); - if (ret) { - krb5_auth_con_free(context, ac); - krb5_free_ticket(context, ticket); - goto out; - } - ret = krb5_crypto_init(context, &ticket->ticket.key, - 0, &crypto_session); - krb5_free_ticket(context, ticket); - if (ret) { - krb5_auth_con_free(context, ac); - krb5_crypto_destroy(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(context, crypto_subkey, crypto_session, - &pepper1, &pepper2, - ac->remote_subkey->keytype, - &armorkey); - krb5_crypto_destroy(context, crypto_subkey); - krb5_crypto_destroy(context, crypto_session); - krb5_auth_con_free(context, ac); - if (ret) - goto out; - - ret = krb5_crypto_init(context, &armorkey, 0, armor_crypto); - if (ret) - goto out; - krb5_free_keyblock_contents(context, &armorkey); - - /* verify req-checksum of the outer body */ - - ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, len, &req->req_body, &size, ret); - if (ret) - goto out; - if (size != len) { - ret = KRB5KDC_ERR_PREAUTH_FAILED; - goto out; - } - - ret = krb5_verify_checksum(context, *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(context, *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(&req->req_body); - ret = copy_KDC_REQ_BODY(&fastreq.req_body, &req->req_body); - if (ret) - goto out; - - /* check for unsupported mandatory options */ - if (FastOptions2int(fastreq.fast_options) & 0xfffc) { - kdc_log(context, 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 */ - free_METHOD_DATA(req->padata); - ret = copy_METHOD_DATA(&fastreq.padata, req->padata); - if (ret) - goto out; - - free_KrbFastReq(&fastreq); - free_PA_FX_FAST_REQUEST(&fxreq); - - out: - if (armor_server) - krb5_free_principal(context, armor_server); - if(armor_user) - _kdc_free_ent(context, armor_user); - - return ret; + return r->config->require_preauth + || r->client->entry.flags.require_preauth + || r->server->entry.flags.require_preauth; } @@ -1735,6 +1536,7 @@ _kdc_as_rep(kdc_request_t r, EncKDCRepPart ek; krb5_error_code ret = 0; Key *ckey, *skey; + int found_pa = 0; int flags = 0; METHOD_DATA error_method; @@ -1747,7 +1549,7 @@ _kdc_as_rep(kdc_request_t r, /* * Look for FAST armor and unwrap */ - ret = unwrap_fast(context, config, req, &r->armor_crypto); + ret = _kdc_fast_unwrap_request(r); if (ret) goto out; @@ -1877,7 +1679,6 @@ _kdc_as_rep(kdc_request_t r, if(req->padata){ const PA_DATA *pa; - int found_pa = 0; unsigned int n; int i; @@ -1890,6 +1691,7 @@ _kdc_as_rep(kdc_request_t r, continue; if (r->armor_crypto == NULL && (pat[n].flags & PA_REQ_FAST)) continue; + kdc_log(context, config, 5, "Looking for %s pa-data -- %s", pat[n].name, r->client_name); i = 0; @@ -1901,29 +1703,15 @@ _kdc_as_rep(kdc_request_t r, "%s pre-authentication succeeded -- %s", pat[n].name, r->client_name); found_pa = 1; + et.flags.pre_authent = 1; } } } + } - if (found_pa) { - et.flags.pre_authent = 1; - } - - if(found_pa == 0 && config->require_preauth) - goto use_pa; - /* We come here if we found a pa-enc-timestamp, but if there - was some problem with it, other than too large skew */ - if(found_pa && et.flags.pre_authent == 0){ - kdc_log(context, config, 0, "%s -- %s", r->e_text, r->client_name); - r->e_text = NULL; - goto out; - } - }else if (config->require_preauth - || b->kdc_options.request_anonymous /* hack to force anon */ - || r->client->entry.flags.require_preauth - || r->server->entry.flags.require_preauth) { + if ((found_pa == 0 && require_preauth_p(r)) || b->kdc_options.request_anonymous) { size_t n; - use_pa: + for (n = 0; n < sizeof(pat) / sizeof(pat[0]); n++) { if ((pat[n].flags & PA_ANNOUNCE) == 0) continue; @@ -2003,6 +1791,10 @@ _kdc_as_rep(kdc_request_t r, goto out; } + /* + * Build repy + */ + rep.pvno = 5; rep.msg_type = krb_as_rep; From 9a21fddb7057afaaff3a62ed5272f83d0a68c5c1 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Thu, 12 May 2011 21:06:25 -0700 Subject: [PATCH 054/119] use kdc_request_t for add_enc_pa_req --- kdc/kerberos5.c | 142 +++++++++++++++++++++++------------------------- 1 file changed, 67 insertions(+), 75 deletions(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 2ee98dd52..2470f7f32 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -748,63 +748,6 @@ log_patypes(krb5_context context, free(str); } -/* - * - */ - -static krb5_error_code -add_enc_pa_rep(krb5_context context, - krb5_kdc_configuration *config, - EncTicketPart *et, EncKDCRepPart *ek, - const krb5_data *req_buffer, - const krb5_keyblock *reply_key) -{ - krb5_error_code ret; - krb5_crypto crypto; - Checksum checksum; - krb5_data cdata; - size_t len; - - et->flags.enc_pa_rep = ek->flags.enc_pa_rep = 1; - - ret = krb5_crypto_init(context, reply_key, 0, &crypto); - if (ret) { - const char *msg = krb5_get_error_message(context, ret); - kdc_log(context, config, 0, "krb5_crypto_init failed: %s", msg); - krb5_free_error_message(context, msg); - return ret; - } - - ret = krb5_create_checksum(context, crypto, - KRB5_KU_AS_REQ, 0, - req_buffer->data, req_buffer->length, - &checksum); - krb5_crypto_destroy(context, crypto); - if (ret) - return ret; - - ASN1_MALLOC_ENCODE(Checksum, cdata.data, cdata.length, - &checksum, &len, ret); - free_Checksum(&checksum); - if (ret) - return ret; - - if (ek->encrypted_pa_data == NULL) { - ALLOC(ek->encrypted_pa_data); - if (ek->encrypted_pa_data == NULL) - return ENOMEM; - } - ret = krb5_padata_add(context, ek->encrypted_pa_data, - KRB5_PADATA_REQ_ENC_PA_REP, cdata.data, cdata.length); - if (ret) - return ret; - - ret = krb5_padata_add(context, ek->encrypted_pa_data, - KRB5_PADATA_FX_FAST, NULL, 0); - - return ret; -} - /* * */ @@ -828,13 +771,6 @@ _kdc_encode_reply(krb5_context context, krb5_error_code ret; krb5_crypto crypto; - if (req_buffer && rep->msg_type == krb_as_rep) { - ret = add_enc_pa_rep(context, config, - et, ek, req_buffer, reply_key); - if (ret) - return ret; - } - ASN1_MALLOC_ENCODE(EncTicketPart, buf, buf_size, et, &len, ret); if(ret) { const char *msg = krb5_get_error_message(context, ret); @@ -1513,6 +1449,53 @@ require_preauth_p(kdc_request_t r) } +/* + * + */ + +static krb5_error_code +add_enc_pa_rep(kdc_request_t r) +{ + krb5_error_code ret; + krb5_crypto crypto; + Checksum checksum; + krb5_data cdata; + size_t len; + + r->et.flags.enc_pa_rep = r->ek.flags.enc_pa_rep = 1; + + ret = krb5_crypto_init(r->context, &r->reply_key, 0, &crypto); + if (ret) + return ret; + + ret = krb5_create_checksum(r->context, crypto, + KRB5_KU_AS_REQ, 0, + r->request.data, r->request.length, + &checksum); + krb5_crypto_destroy(r->context, crypto); + if (ret) + return ret; + + ASN1_MALLOC_ENCODE(Checksum, cdata.data, cdata.length, + &checksum, &len, ret); + free_Checksum(&checksum); + if (ret) + return ret; + + if (r->ek.encrypted_pa_data == NULL) { + ALLOC(r->ek.encrypted_pa_data); + if (r->ek.encrypted_pa_data == NULL) + return ENOMEM; + } + ret = krb5_padata_add(r->context, r->ek.encrypted_pa_data, + KRB5_PADATA_REQ_ENC_PA_REP, cdata.data, cdata.length); + if (ret) + return ret; + + return krb5_padata_add(r->context, r->ek.encrypted_pa_data, + KRB5_PADATA_FX_FAST, NULL, 0); +} + /* * */ @@ -1527,7 +1510,6 @@ _kdc_as_rep(kdc_request_t r, krb5_context context = r->context; krb5_kdc_configuration *config = r->config; KDC_REQ *req = &r->req; - const krb5_data *req_buffer = &r->request; KDC_REQ_BODY *b = NULL; AS_REP rep; KDCOptions f; @@ -1537,8 +1519,9 @@ _kdc_as_rep(kdc_request_t r, krb5_error_code ret = 0; Key *ckey, *skey; int found_pa = 0; - int flags = 0; + int i, flags = 0; METHOD_DATA error_method; + const PA_DATA *pa; memset(&rep, 0, sizeof(rep)); memset(&et, 0, sizeof(et)); @@ -1678,7 +1661,6 @@ _kdc_as_rep(kdc_request_t r, */ if(req->padata){ - const PA_DATA *pa; unsigned int n; int i; @@ -2119,16 +2101,26 @@ _kdc_as_rep(kdc_request_t r, log_as_req(context, config, r->reply_key.keytype, setype, b); - { - const PA_DATA *pa; - int i = 0; - - pa = _kdc_find_padata(req, &i, KRB5_PADATA_REQ_ENC_PA_REP); - if (pa == NULL) - req_buffer = NULL; + /* + * Add REQ_ENC_PA_REP if client supports it + */ + i = 0; + pa = _kdc_find_padata(req, &i, KRB5_PADATA_REQ_ENC_PA_REP); + if (pa) { + ret = add_enc_pa_rep(r); + if (ret) { + const char *msg = krb5_get_error_message(r->context, ret); + _kdc_r_log(r, 0, "add_enc_pa_rep failed: %d: %s", ret, msg); + krb5_free_error_message(r->context, msg); + goto out; + } } - ret = _kdc_encode_reply(context, config, req_buffer, + /* + * + */ + + ret = _kdc_encode_reply(context, config, NULL, r->armor_crypto, req->req_body.nonce, &rep, &et, &ek, setype, r->server->entry.kvno, &skey->key, r->client->entry.kvno, From b8c168e565ebac826f6db77025e025e117b7c95d Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Thu, 12 May 2011 21:09:28 -0700 Subject: [PATCH 055/119] check return length --- kdc/kerberos5.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 2470f7f32..80b290776 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -1481,6 +1481,7 @@ add_enc_pa_rep(kdc_request_t r) free_Checksum(&checksum); if (ret) return ret; + heim_assert(cdata.length == len, "ASN.1 internal error"); if (r->ek.encrypted_pa_data == NULL) { ALLOC(r->ek.encrypted_pa_data); From 333471097d280a68cb1883f9b88b2b5f57c35905 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Thu, 12 May 2011 21:10:52 -0700 Subject: [PATCH 056/119] 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; +} From 94157d44106c00243970ca83f8db5af5919443e8 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Thu, 12 May 2011 21:11:05 -0700 Subject: [PATCH 057/119] dont pass req buffer to _kdc_encode_reply --- kdc/kerberos5.c | 3 +-- kdc/krb5tgs.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 80b290776..fdb7608f8 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -755,7 +755,6 @@ log_patypes(krb5_context context, krb5_error_code _kdc_encode_reply(krb5_context context, krb5_kdc_configuration *config, - const krb5_data *req_buffer, krb5_crypto armor_crypto, uint32_t nonce, KDC_REP *rep, EncTicketPart *et, EncKDCRepPart *ek, krb5_enctype etype, @@ -2121,7 +2120,7 @@ _kdc_as_rep(kdc_request_t r, * */ - ret = _kdc_encode_reply(context, config, NULL, + ret = _kdc_encode_reply(context, config, r->armor_crypto, req->req_body.nonce, &rep, &et, &ek, setype, r->server->entry.kvno, &skey->key, r->client->entry.kvno, diff --git a/kdc/krb5tgs.c b/kdc/krb5tgs.c index 9b7c21346..1ad13e777 100644 --- a/kdc/krb5tgs.c +++ b/kdc/krb5tgs.c @@ -987,7 +987,7 @@ tgs_make_reply(krb5_context context, CAST session key. Should the DES3 etype be added to the etype list, even if we don't want a session key with DES3? */ - ret = _kdc_encode_reply(context, config, NULL, NULL, 0, + ret = _kdc_encode_reply(context, config, NULL, 0, &rep, &et, &ek, et.key.keytype, kvno, serverkey, 0, replykey, rk_is_subkey, From 4d63c98125f6a4b07f1e664fe37f9831d46faf6a Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Thu, 12 May 2011 21:22:42 -0700 Subject: [PATCH 058/119] Break out PAC generation --- kdc/kerberos5.c | 80 +++++++++++++++++++++++++++++-------------------- 1 file changed, 48 insertions(+), 32 deletions(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index fdb7608f8..81ae26c5b 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -1428,6 +1428,50 @@ send_pac_p(krb5_context context, KDC_REQ *req) return TRUE; } +/* + * + */ + +static krb5_error_code +generate_pac(kdc_request_t r, Key *skey) +{ + krb5_error_code ret; + krb5_pac p = NULL; + krb5_data data; + + ret = _kdc_pac_generate(r->context, r->client, &p); + if (ret) { + _kdc_r_log(r, 0, "PAC generation failed for -- %s", + r->client_name); + return ret; + } + if (p == NULL) + return 0; + + ret = _krb5_pac_sign(r->context, p, r->et.authtime, + r->client->entry.principal, + &skey->key, /* Server key */ + &skey->key, /* FIXME: should be krbtgt key */ + &data); + krb5_pac_free(r->context, p); + if (ret) { + _kdc_r_log(r, 0, "PAC signing failed for -- %s", + r->client_name); + return ret; + } + + ret = _kdc_tkt_add_if_relevant_ad(r->context, &r->et, + KRB5_AUTHDATA_WIN2K_PAC, + &data); + krb5_data_free(&data); + + return ret; +} + +/* + * + */ + krb5_boolean _kdc_is_anonymous(krb5_context context, krb5_principal principal) { @@ -1691,7 +1735,7 @@ _kdc_as_rep(kdc_request_t r, } } - if ((found_pa == 0 && require_preauth_p(r)) || b->kdc_options.request_anonymous) { + if (found_pa == 0 && (require_preauth_p(r) || b->kdc_options.request_anonymous)) { size_t n; for (n = 0; n < sizeof(pat) / sizeof(pat[0]); n++) { @@ -2053,35 +2097,7 @@ _kdc_as_rep(kdc_request_t r, /* Add the PAC */ if (send_pac_p(context, req)) { - krb5_pac p = NULL; - krb5_data data; - - ret = _kdc_pac_generate(context, r->client, &p); - if (ret) { - kdc_log(context, config, 0, "PAC generation failed for -- %s", - r->client_name); - goto out; - } - if (p != NULL) { - ret = _krb5_pac_sign(context, p, et.authtime, - r->client->entry.principal, - &skey->key, /* Server key */ - &skey->key, /* FIXME: should be krbtgt key */ - &data); - krb5_pac_free(context, p); - if (ret) { - kdc_log(context, config, 0, "PAC signing failed for -- %s", - r->client_name); - goto out; - } - - ret = _kdc_tkt_add_if_relevant_ad(context, &et, - KRB5_AUTHDATA_WIN2K_PAC, - &data); - krb5_data_free(&data); - if (ret) - goto out; - } + generate_pac(r, skey); } _kdc_log_timestamp(context, config, "AS-REQ", et.authtime, et.starttime, @@ -2110,7 +2126,7 @@ _kdc_as_rep(kdc_request_t r, ret = add_enc_pa_rep(r); if (ret) { const char *msg = krb5_get_error_message(r->context, ret); - _kdc_r_log(r, 0, "add_enc_pa_rep failed: %d: %s", ret, msg); + _kdc_r_log(r, 0, "add_enc_pa_rep failed: %s: %d", msg, ret); krb5_free_error_message(r->context, msg); goto out; } @@ -2141,7 +2157,7 @@ out: /* * In case of a non proxy error, build an error message. */ - if(ret != 0 && ret != HDB_ERR_NOT_FOUND_HERE){ + if(ret != 0 && ret != HDB_ERR_NOT_FOUND_HERE) { kdc_log(context, config, 10, "as-req: sending error: %d to client", ret); ret = _kdc_fast_mk_error(context, &error_method, From 035afb17db62b3586509014fa67d6a3ec3a16975 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Thu, 12 May 2011 21:32:46 -0700 Subject: [PATCH 059/119] use et, ek from r-> --- kdc/kerberos5.c | 138 +++++++++++++++++++++++------------------------- 1 file changed, 66 insertions(+), 72 deletions(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 81ae26c5b..ddd74c662 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -1558,8 +1558,6 @@ _kdc_as_rep(kdc_request_t r, AS_REP rep; KDCOptions f; krb5_enctype setype; - EncTicketPart et; - EncKDCRepPart ek; krb5_error_code ret = 0; Key *ckey, *skey; int found_pa = 0; @@ -1568,8 +1566,6 @@ _kdc_as_rep(kdc_request_t r, const PA_DATA *pa; memset(&rep, 0, sizeof(rep)); - memset(&et, 0, sizeof(et)); - memset(&ek, 0, sizeof(ek)); error_method.len = 0; error_method.val = NULL; @@ -1675,9 +1671,6 @@ _kdc_as_rep(kdc_request_t r, goto out; } - memset(&et, 0, sizeof(et)); - memset(&ek, 0, sizeof(ek)); - /* * Select a session enctype from the list of the crypto system * supported enctypes that is supported by the client and is one of @@ -1729,7 +1722,7 @@ _kdc_as_rep(kdc_request_t r, "%s pre-authentication succeeded -- %s", pat[n].name, r->client_name); found_pa = 1; - et.flags.pre_authent = 1; + r->et.flags.pre_authent = 1; } } } @@ -1842,23 +1835,23 @@ _kdc_as_rep(kdc_request_t r, rep.ticket.sname.name_type = b->sname->name_type; #undef CNT - et.flags.initial = 1; + r->et.flags.initial = 1; if(r->client->entry.flags.forwardable && r->server->entry.flags.forwardable) - et.flags.forwardable = f.forwardable; + r->et.flags.forwardable = f.forwardable; else if (f.forwardable) { _kdc_set_e_text(r, "Ticket may not be forwardable"); ret = KRB5KDC_ERR_POLICY; goto out; } if(r->client->entry.flags.proxiable && r->server->entry.flags.proxiable) - et.flags.proxiable = f.proxiable; + r->et.flags.proxiable = f.proxiable; else if (f.proxiable) { _kdc_set_e_text(r, "Ticket may not be proxiable"); ret = KRB5KDC_ERR_POLICY; goto out; } if(r->client->entry.flags.postdate && r->server->entry.flags.postdate) - et.flags.may_postdate = f.allow_postdate; + r->et.flags.may_postdate = f.allow_postdate; else if (f.allow_postdate){ _kdc_set_e_text(r, "Ticket may not be postdate"); ret = KRB5KDC_ERR_POLICY; @@ -1872,24 +1865,24 @@ _kdc_as_rep(kdc_request_t r, goto out; } - ret = copy_PrincipalName(&rep.cname, &et.cname); + ret = copy_PrincipalName(&rep.cname, &r->et.cname); if (ret) goto out; - ret = copy_Realm(&rep.crealm, &et.crealm); + ret = copy_Realm(&rep.crealm, &r->et.crealm); if (ret) goto out; { time_t start; time_t t; - - start = et.authtime = kdc_time; + + start = r->et.authtime = kdc_time; if(f.postdated && req->req_body.from){ - ALLOC(et.starttime); - start = *et.starttime = *req->req_body.from; - et.flags.invalid = 1; - et.flags.postdated = 1; /* XXX ??? */ + ALLOC(r->et.starttime); + start = *r->et.starttime = *req->req_body.from; + r->et.flags.invalid = 1; + r->et.flags.postdated = 1; /* XXX ??? */ } _kdc_fix_time(&b->till); t = *b->till; @@ -1903,8 +1896,8 @@ _kdc_as_rep(kdc_request_t r, #if 0 t = min(t, start + realm->max_life); #endif - et.endtime = t; - if(f.renewable_ok && et.endtime < *b->till){ + r->et.endtime = t; + if(f.renewable_ok && r->et.endtime < *b->till){ f.renewable = 1; if(b->rtime == NULL){ ALLOC(b->rtime); @@ -1924,22 +1917,22 @@ _kdc_as_rep(kdc_request_t r, #if 0 t = min(t, start + realm->max_renew); #endif - ALLOC(et.renew_till); - *et.renew_till = t; - et.flags.renewable = 1; + ALLOC(r->et.renew_till); + *r->et.renew_till = t; + r->et.flags.renewable = 1; } } if (f.request_anonymous) - et.flags.anonymous = 1; + r->et.flags.anonymous = 1; if(b->addresses){ - ALLOC(et.caddr); - copy_HostAddresses(b->addresses, et.caddr); + ALLOC(r->et.caddr); + copy_HostAddresses(b->addresses, r->et.caddr); } - et.transited.tr_type = DOMAIN_X500_COMPRESS; - krb5_data_zero(&et.transited.contents); + r->et.transited.tr_type = DOMAIN_X500_COMPRESS; + krb5_data_zero(&r->et.transited.contents); /* The MIT ASN.1 library (obviously) doesn't tell lengths encoded * as 0 and as 0x80 (meaning indefinite length) apart, and is thus @@ -1950,58 +1943,58 @@ _kdc_as_rep(kdc_request_t r, * If there's a pw_end or valid_end we will use that, * otherwise just a dummy lr. */ - ek.last_req.val = malloc(2 * sizeof(*ek.last_req.val)); - if (ek.last_req.val == NULL) { + r->ek.last_req.val = malloc(2 * sizeof(*r->ek.last_req.val)); + if (r->ek.last_req.val == NULL) { ret = ENOMEM; goto out; } - ek.last_req.len = 0; + r->ek.last_req.len = 0; if (r->client->entry.pw_end && (config->kdc_warn_pwexpire == 0 || kdc_time + config->kdc_warn_pwexpire >= *r->client->entry.pw_end)) { - ek.last_req.val[ek.last_req.len].lr_type = LR_PW_EXPTIME; - ek.last_req.val[ek.last_req.len].lr_value = *r->client->entry.pw_end; - ++ek.last_req.len; + r->ek.last_req.val[r->ek.last_req.len].lr_type = LR_PW_EXPTIME; + r->ek.last_req.val[r->ek.last_req.len].lr_value = *r->client->entry.pw_end; + ++r->ek.last_req.len; } if (r->client->entry.valid_end) { - ek.last_req.val[ek.last_req.len].lr_type = LR_ACCT_EXPTIME; - ek.last_req.val[ek.last_req.len].lr_value = *r->client->entry.valid_end; - ++ek.last_req.len; + r->ek.last_req.val[r->ek.last_req.len].lr_type = LR_ACCT_EXPTIME; + r->ek.last_req.val[r->ek.last_req.len].lr_value = *r->client->entry.valid_end; + ++r->ek.last_req.len; } - if (ek.last_req.len == 0) { - ek.last_req.val[ek.last_req.len].lr_type = LR_NONE; - ek.last_req.val[ek.last_req.len].lr_value = 0; - ++ek.last_req.len; + if (r->ek.last_req.len == 0) { + r->ek.last_req.val[r->ek.last_req.len].lr_type = LR_NONE; + r->ek.last_req.val[r->ek.last_req.len].lr_value = 0; + ++r->ek.last_req.len; } - ek.nonce = b->nonce; + r->ek.nonce = b->nonce; if (r->client->entry.valid_end || r->client->entry.pw_end) { - ALLOC(ek.key_expiration); + ALLOC(r->ek.key_expiration); if (r->client->entry.valid_end) { if (r->client->entry.pw_end) - *ek.key_expiration = min(*r->client->entry.valid_end, + *r->ek.key_expiration = min(*r->client->entry.valid_end, *r->client->entry.pw_end); else - *ek.key_expiration = *r->client->entry.valid_end; + *r->ek.key_expiration = *r->client->entry.valid_end; } else - *ek.key_expiration = *r->client->entry.pw_end; + *r->ek.key_expiration = *r->client->entry.pw_end; } else - ek.key_expiration = NULL; - ek.flags = et.flags; - ek.authtime = et.authtime; - if (et.starttime) { - ALLOC(ek.starttime); - *ek.starttime = *et.starttime; + r->ek.key_expiration = NULL; + r->ek.flags = r->et.flags; + r->ek.authtime = r->et.authtime; + if (r->et.starttime) { + ALLOC(r->ek.starttime); + *r->ek.starttime = *r->et.starttime; } - ek.endtime = et.endtime; - if (et.renew_till) { - ALLOC(ek.renew_till); - *ek.renew_till = *et.renew_till; + r->ek.endtime = r->et.endtime; + if (r->et.renew_till) { + ALLOC(r->ek.renew_till); + *r->ek.renew_till = *r->et.renew_till; } - copy_Realm(&rep.ticket.realm, &ek.srealm); - copy_PrincipalName(&rep.ticket.sname, &ek.sname); - if(et.caddr){ - ALLOC(ek.caddr); - copy_HostAddresses(et.caddr, ek.caddr); + copy_Realm(&rep.ticket.realm, &r->ek.srealm); + copy_PrincipalName(&rep.ticket.sname, &r->ek.sname); + if(r->et.caddr){ + ALLOC(r->ek.caddr); + copy_HostAddresses(r->et.caddr, r->ek.caddr); } /* @@ -2020,11 +2013,11 @@ _kdc_as_rep(kdc_request_t r, goto out; } - ret = copy_EncryptionKey(&r->session_key, &et.key); + ret = copy_EncryptionKey(&r->session_key, &r->et.key); if (ret) goto out; - ret = copy_EncryptionKey(&r->session_key, &ek.key); + ret = copy_EncryptionKey(&r->session_key, &r->ek.key); if (ret) goto out; @@ -2052,7 +2045,7 @@ _kdc_as_rep(kdc_request_t r, krb5_abortx(context, "internal asn.1 error"); /* sign using "returned session key" */ - ret = krb5_crypto_init(context, &et.key, 0, &cryptox); + ret = krb5_crypto_init(context, &r->et.key, 0, &cryptox); if (ret) { free(data.data); goto out; @@ -2100,8 +2093,8 @@ _kdc_as_rep(kdc_request_t r, generate_pac(r, skey); } - _kdc_log_timestamp(context, config, "AS-REQ", et.authtime, et.starttime, - et.endtime, et.renew_till); + _kdc_log_timestamp(context, config, "AS-REQ", r->et.authtime, r->et.starttime, + r->et.endtime, r->et.renew_till); /* do this as the last thing since this signs the EncTicketPart */ ret = _kdc_add_KRB5SignedPath(context, @@ -2111,7 +2104,7 @@ _kdc_as_rep(kdc_request_t r, r->client->entry.principal, NULL, NULL, - &et); + &r->et); if (ret) goto out; @@ -2120,6 +2113,7 @@ _kdc_as_rep(kdc_request_t r, /* * Add REQ_ENC_PA_REP if client supports it */ + i = 0; pa = _kdc_find_padata(req, &i, KRB5_PADATA_REQ_ENC_PA_REP); if (pa) { @@ -2138,7 +2132,7 @@ _kdc_as_rep(kdc_request_t r, ret = _kdc_encode_reply(context, config, r->armor_crypto, req->req_body.nonce, - &rep, &et, &ek, setype, r->server->entry.kvno, + &rep, &r->et, &r->ek, setype, r->server->entry.kvno, &skey->key, r->client->entry.kvno, &r->reply_key, 0, &r->e_text, reply); if (ret) @@ -2171,8 +2165,8 @@ out: goto out2; } out2: - free_EncTicketPart(&et); - free_EncKDCRepPart(&ek); + free_EncTicketPart(&r->et); + free_EncKDCRepPart(&r->ek); if (error_method.len) free_METHOD_DATA(&error_method); From b6e56322f37ea4695372a3838dc56d14cc243abe Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Thu, 12 May 2011 21:44:01 -0700 Subject: [PATCH 060/119] Check if message too large --- kdc/kerberos5.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index ddd74c662..3c67a3bad 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -2138,7 +2138,9 @@ _kdc_as_rep(kdc_request_t r, if (ret) goto out; - /* */ + /* + * Check if message too large + */ if (datagram_reply && reply->length > config->max_datagram_reply_length) { krb5_data_free(reply); ret = KRB5KRB_ERR_RESPONSE_TOO_BIG; From 3f0a3c4795513b37b293d29e4616340a8ced5dad Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Sat, 14 May 2011 19:44:27 -0700 Subject: [PATCH 061/119] Add fast armor bits --- kuser/kinit.c | 82 +++++++++++++++++++++++++++------------------------ 1 file changed, 44 insertions(+), 38 deletions(-) diff --git a/kuser/kinit.c b/kuser/kinit.c index e872fef9b..c98bb7055 100644 --- a/kuser/kinit.c +++ b/kuser/kinit.c @@ -74,6 +74,7 @@ int pk_use_enckey = 0; static int canonicalize_flag = 0; static int enterprise_flag = 0; static int ok_as_delegate_flag = 0; +static char *fast_armor_cache_string = NULL; static int use_referrals_flag = 0; static int windows_flag = 0; #ifndef NO_NTLM @@ -187,6 +188,9 @@ static struct getargs args[] = { { "ok-as-delegate", 0, arg_flag, &ok_as_delegate_flag, NP_("honor ok-as-delegate on tickets", ""), NULL }, + { "fast-armor-cache", 0, arg_string, &fast_armor_cache_string, + NP_("use this credential cache as FAST armor cache", ""), "cache" }, + { "use-referrals", 0, arg_flag, &use_referrals_flag, NP_("only use referrals, no dns canalisation", ""), NULL }, @@ -360,6 +364,8 @@ get_new_tickets(krb5_context context, const char *renewstr = NULL; krb5_enctype *enctype = NULL; krb5_ccache tempccache; + krb5_keytab kt = NULL; + krb5_init_creds_context ctx; #ifndef NO_NTLM struct ntlm_buf ntlmkey; memset(&ntlmkey, 0, sizeof(ntlmkey)); @@ -498,32 +504,37 @@ get_new_tickets(krb5_context context, etype_str.num_strings); } + ret = krb5_init_creds_init(context, principal, krb5_prompter_posix, NULL, start_time, opt, &ctx); + if (ret) + krb5_err(context, 1, ret, "krb5_init_creds_init"); + + if (fast_armor_cache_string) { + krb5_ccache fastid; + + ret = krb5_cc_resolve(context, fast_armor_cache_string, &fastid); + if (ret) + krb5_err(context, 1, ret, "krb5_cc_resolve(FAST cache)"); + + ret = krb5_init_creds_set_fast_ccache(context, ctx, fastid); + if (ret) + krb5_err(context, 1, ret, "krb5_init_creds_set_fast_ccache"); + } + if(use_keytab || keytab_str) { - krb5_keytab kt; + if(keytab_str) ret = krb5_kt_resolve(context, keytab_str, &kt); else ret = krb5_kt_default(context, &kt); if (ret) - krb5_err (context, 1, ret, "resolving keytab"); - ret = krb5_get_init_creds_keytab (context, - &cred, - principal, - kt, - start_time, - server_str, - opt); - krb5_kt_close(context, kt); + krb5_err(context, 1, ret, "resolving keytab"); + + ret = krb5_init_creds_set_keytab(context, ctx, kt); + if (ret) + krb5_err(context, 1, ret, "krb5_init_creds_set_keytab"); + } else if (pk_user_id || ent_user_id || anonymous_flag) { - ret = krb5_get_init_creds_password (context, - &cred, - principal, - passwd, - krb5_prompter_posix, - NULL, - start_time, - server_str, - opt); + } else if (!interactive) { krb5_warnx(context, "Not interactive, failed to get initial ticket"); krb5_get_init_creds_opt_free(context, opt); @@ -539,22 +550,20 @@ get_new_tickets(krb5_context context, if (UI_UTIL_read_pw_string(passwd, sizeof(passwd)-1, prompt, 0)){ memset(passwd, 0, sizeof(passwd)); - exit(1); + errx(1, "failed to read password"); } free (prompt); } - - ret = krb5_get_init_creds_password (context, - &cred, - principal, - passwd, - krb5_prompter_posix, - NULL, - start_time, - server_str, - opt); + if (passwd[0]) { + ret = krb5_init_creds_set_password(context, ctx, passwd); + if (ret) + krb5_err(context, 1, ret, "krb5_init_creds_set_password"); + } } + + ret = krb5_init_creds_get(context, ctx); + krb5_get_init_creds_opt_free(context, opt); #ifndef NO_NTLM if (ntlm_domain && passwd[0]) @@ -603,15 +612,11 @@ get_new_tickets(krb5_context context, if (ret) krb5_err (context, 1, ret, "krb5_cc_new_unique"); - ret = krb5_cc_initialize (context, tempccache, cred.client); + ret = krb5_init_creds_store(context, ctx, tempccache); if (ret) - krb5_err (context, 1, ret, "krb5_cc_initialize"); + krb5_err(context, 1, ret, "krb5_init_creds_store"); - ret = krb5_cc_store_cred (context, tempccache, &cred); - if (ret) - krb5_err (context, 1, ret, "krb5_cc_store_cred"); - - krb5_free_cred_contents (context, &cred); + krb5_init_creds_free(context, ctx); ret = krb5_cc_move(context, tempccache, ccache); if (ret) @@ -640,7 +645,8 @@ get_new_tickets(krb5_context context, krb5_cc_set_config(context, ccache, NULL, "realm-config", &data); } - + if (kt) + krb5_kt_close(context, kt); if (enctype) free(enctype); From 7c55029060e056de22d9be8326e8b4e19a1407f8 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Sat, 14 May 2011 19:44:36 -0700 Subject: [PATCH 062/119] Add fast armor bits --- lib/krb5/init_creds_pw.c | 59 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/lib/krb5/init_creds_pw.c b/lib/krb5/init_creds_pw.c index f34fc30cf..e16390939 100644 --- a/lib/krb5/init_creds_pw.c +++ b/lib/krb5/init_creds_pw.c @@ -75,6 +75,8 @@ typedef struct krb5_get_init_creds_ctx { krb5_prompter_fct prompter; void *prompter_data; + krb5_ccache fast_ccache; + struct pa_info_data *ppaid; struct fast_state { int flags; @@ -1245,6 +1247,10 @@ process_pa_data_to_md(krb5_context context, pa_data_add_pac_request(context, ctx, *out_md); + ret = krb5_padata_add(context, *out_md, KRB5_PADATA_REQ_ENC_PA_REP, NULL, 0); + if (ret) + return ret; + if ((*out_md)->len == 0) { free(*out_md); *out_md = NULL; @@ -1626,6 +1632,15 @@ krb5_init_creds_set_keyblock(krb5_context context, return 0; } +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +krb5_init_creds_set_fast_ccache(krb5_context context, + krb5_init_creds_context ctx, + krb5_ccache fast_ccache) +{ + ctx->fast_ccache = fast_ccache; + return 0; +} + /** * The core loop if krb5_get_init_creds() function family. Create the * packets and have the caller send them off to the KDC. @@ -1720,15 +1735,16 @@ krb5_init_creds_step(krb5_context context, NULL, ctx->nonce, eflags, + &ctx->req_buffer, NULL, NULL); + if (ret == 0) + ret = copy_EncKDCRepPart(&rep.enc_part, &ctx->enc_part); + krb5_free_keyblock(context, ctx->fast_state.reply_key); ctx->fast_state.reply_key = NULL; *flags = 0; - if (ret == 0) - ret = copy_EncKDCRepPart(&rep.enc_part, &ctx->enc_part); - free_AS_REP(&rep.kdc_rep); free_EncASRepPart(&rep.enc_part); @@ -1890,6 +1906,43 @@ krb5_init_creds_get_error(krb5_context context, return ret; } +/** + * + * @ingroup krb5_credential + */ + +krb5_error_code +krb5_init_creds_store(krb5_context context, + krb5_init_creds_context ctx, + krb5_ccache id) +{ + krb5_error_code ret; + + if (ctx->cred.client == NULL) { + ret = KRB5KDC_ERR_PREAUTH_REQUIRED; + krb5_set_error_message(context, ret, "init creds not completed yet"); + return ret; + } + + ret = krb5_cc_initialize(context, id, ctx->cred.client); + if (ret) + return ret; + + ret = krb5_cc_store_cred(context, id, &ctx->cred); + if (ret) + return ret; + + if (ctx->cred.flags.b.enc_pa_rep) { + krb5_data data = { 3, rk_UNCONST("yes") }; + ret = krb5_cc_set_config(context, id, ctx->cred.server, + "fast_avail", &data); + if (ret) + return ret; + } + + return ret; +} + /** * Free the krb5_init_creds_context allocated by krb5_init_creds_init(). * From 2991ed7e7730692c89e9598ec63c91e090dd7303 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Sat, 14 May 2011 19:46:29 -0700 Subject: [PATCH 063/119] check for FAST --- tests/kdc/check-fast.in | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/tests/kdc/check-fast.in b/tests/kdc/check-fast.in index 15321bb90..a28be9db8 100644 --- a/tests/kdc/check-fast.in +++ b/tests/kdc/check-fast.in @@ -57,6 +57,7 @@ cache="FILE:${objdir}/cache.krb5" acache="FILE:${objdir}/acache.krb5" kinit="${kinit} -c $cache ${afs_no_afslog}" +akinit="${kinit} -c $acache ${afs_no_afslog}" klist="${klist} -c $cache" aklist="${klist} -c $acache" kgetcred="${kgetcred} -c $cache" @@ -102,13 +103,26 @@ ec=0 echo "Getting client initial tickets"; > messages.log ${kinit} --password-file=${objdir}/foopassword foo@$R || \ { ec=1 ; eval "${testfailed}"; } +echo "Checking for FAST avail" +${klist} --hidden | grep fast_avail > /dev/null || { exit 1; } echo "Getting tickets"; > messages.log ${kgetcred} ${server}@${R} || { ec=1 ; eval "${testfailed}"; } echo "Listing tickets"; > messages.log ${klist} > /dev/null || { ec=1 ; eval "${testfailed}"; } ${kdestroy} -echo foo > ${objdir}/foopassword +echo "Acquire host ticket" +${akinit} --password-file=${objdir}/foopassword ${server}@${R} >/dev/null|| { exit 1; } +echo "Checking for FAST avail" +${aklist} --hidden | grep fast_avail > /dev/null || { exit 1; } + +echo "Checking out with FAST armor ticket" +${kinit} --fast-armor-cache=${acache} \ + --password-file=${objdir}/foopassword foo@$R || \ + { ec=1 ; eval "${testfailed}"; } + + + kinitpty=${objdir}/foopassword.rkpty cat > ${kinitpty} </dev/null|| { exit 1; } - (${aklist} | grep ${server} > /dev/null ) || { exit 1; } + (${klist} | grep foo > /dev/null ) || { exit 1; } echo "Using FAST to get a initial ticket" ${rkpty} ${kinitpty} ${mit}/kinit -c ${cache} -T ${acache} foo@${R} >/dev/null || { exit 1; } - (${aklist} | grep ${server} > /dev/null ) || { exit 1; } + (${klist} | grep foo > /dev/null ) || { exit 1; } echo "Checking for FAST avail" ${klist} --hidden | grep fast_avail > /dev/null || { exit 1; } From 2e8b550e7bfa69c1d391eb2a0573b250977fa8dc Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Sun, 15 May 2011 11:55:47 -0700 Subject: [PATCH 064/119] punt if caller passed us a crypto object, we didn't find a keyed checksum type --- lib/krb5/crypto.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/krb5/crypto.c b/lib/krb5/crypto.c index 732311bec..236f60f86 100644 --- a/lib/krb5/crypto.c +++ b/lib/krb5/crypto.c @@ -466,6 +466,12 @@ verify_checksum(krb5_context context, ret = get_checksum_key(context, crypto, usage, ct, &dkey); if (ret) return ret; + } else if (crypto) { + krb5_set_error_message(context, KRB5_PROG_SUMTYPE_NOSUPP, + N_("Checksum type %s is unkeyed, " + "but caller expected key checksum %s", ""), + ct->name, crypto->et->name); + return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */ } else dkey = NULL; From 8e65528f844c2b0eb14adc16bc828ad549d3bd26 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Sun, 15 May 2011 11:55:55 -0700 Subject: [PATCH 065/119] disable none --- lib/krb5/crypto-null.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/krb5/crypto-null.c b/lib/krb5/crypto-null.c index b647a6d10..e8ed19c6d 100644 --- a/lib/krb5/crypto-null.c +++ b/lib/krb5/crypto-null.c @@ -64,7 +64,7 @@ struct _krb5_checksum_type _krb5_checksum_none = { "none", 1, 0, - 0, + F_DISABLED, NONE_checksum, NULL }; From 204166e001564d448c84ad84a1e0424d103a0044 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Sun, 15 May 2011 12:04:26 -0700 Subject: [PATCH 066/119] Name the choice enum type. --- lib/asn1/gen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/asn1/gen.c b/lib/asn1/gen.c index 2194b329c..afe23cbf7 100644 --- a/lib/asn1/gen.c +++ b/lib/asn1/gen.c @@ -888,7 +888,7 @@ define_type (int level, const char *name, const char *basename, Type *t, int typ fprintf(headerfile, "heim_octet_string _save;\n"); } space(level + 1); - fprintf (headerfile, "enum {\n"); + fprintf (headerfile, "enum %s_enum {\n", newbasename); m = have_ellipsis(t); if (m) { space(level + 2); From 99ed826f7fe8340ca86f329e973af6773f005ed8 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Sun, 15 May 2011 13:24:42 -0700 Subject: [PATCH 067/119] use _krb5_fast_armor_key() --- kdc/fast.c | 50 +++++++++++++++----------------------------------- 1 file changed, 15 insertions(+), 35 deletions(-) diff --git a/kdc/fast.c b/kdc/fast.c index 9d5aa1b0c..82230767e 100644 --- a/kdc/fast.c +++ b/kdc/fast.c @@ -197,10 +197,8 @@ _kdc_fast_mk_error(krb5_context context, 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; @@ -233,7 +231,7 @@ _kdc_fast_unwrap_request(kdc_request_t r) if (fxreq.element != choice_PA_FX_FAST_REQUEST_armored_data) { kdc_log(r->context, r->config, 0, - "AS-REQ FAST contain unknown type"); + "AS-REQ FAST contain unknown type: %d", (int)fxreq.element); ret = KRB5KDC_ERR_PREAUTH_FAILED; goto out; } @@ -313,40 +311,16 @@ _kdc_fast_unwrap_request(kdc_request_t r) 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); + ret = _krb5_fast_armor_key(r->context, + &ticket->ticket.key, + ac->remote_subkey, + &armorkey, + &r->armor_crypto); krb5_auth_con_free(r->context, ac); + krb5_free_ticket(r->context, ticket); 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 */ @@ -364,15 +338,21 @@ _kdc_fast_unwrap_request(kdc_request_t r) buf, len, &fxreq.u.armored_data.req_checksum); free(buf); - if (ret) + if (ret) { + kdc_log(r->context, r->config, 0, + "FAST request have a bad checksum"); 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) + if (ret) { + kdc_log(r->context, r->config, 0, + "Failed to decrypt FAST request"); goto out; + } ret = decode_KrbFastReq(data.data, data.length, &fastreq, &size); if (ret) { From 0ca5e4495591f77629166b83ee7435f5a10093d3 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Sun, 15 May 2011 13:25:49 -0700 Subject: [PATCH 068/119] shared key for _krb5_fast_armor_key --- lib/krb5/fast.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 lib/krb5/fast.c diff --git a/lib/krb5/fast.c b/lib/krb5/fast.c new file mode 100644 index 000000000..67e812df0 --- /dev/null +++ b/lib/krb5/fast.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2011 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + + +krb5_error_code +_krb5_fast_armor_key(krb5_context context, + krb5_keyblock *sessionkey, + krb5_keyblock *subkey, + krb5_keyblock *armorkey, + krb5_crypto *armor_crypto) +{ + krb5_crypto crypto_subkey, crypto_session; + krb5_data pepper1, pepper2; + krb5_error_code ret; + + ret = krb5_crypto_init(context, subkey, 0, &crypto_subkey); + if (ret) + return ret; + + ret = krb5_crypto_init(context, sessionkey, 0, &crypto_session); + if (ret) { + krb5_crypto_destroy(context, crypto_subkey); + return ret; + } + + pepper1.data = "subkeyarmor"; + pepper1.length = strlen(pepper1.data); + pepper2.data = "ticketarmor"; + pepper2.length = strlen(pepper2.data); + + ret = krb5_crypto_fx_cf2(context, crypto_subkey, crypto_session, + &pepper1, &pepper2, + subkey->keytype, + armorkey); + krb5_crypto_destroy(context, crypto_subkey); + krb5_crypto_destroy(context, crypto_session); + if (ret) + return ret; + + ret = krb5_crypto_init(context, armorkey, 0, armor_crypto); + if (ret) + krb5_free_keyblock_contents(context, armorkey); + + return ret; +} From 7b398263da8867caeb16eacdfd1849f7314c463b Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Sun, 15 May 2011 13:26:13 -0700 Subject: [PATCH 069/119] Partial FAST --- lib/krb5/init_creds_pw.c | 283 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 278 insertions(+), 5 deletions(-) diff --git a/lib/krb5/init_creds_pw.c b/lib/krb5/init_creds_pw.c index e16390939..2a6a64ee9 100644 --- a/lib/krb5/init_creds_pw.c +++ b/lib/krb5/init_creds_pw.c @@ -75,17 +75,20 @@ typedef struct krb5_get_init_creds_ctx { krb5_prompter_fct prompter; void *prompter_data; - krb5_ccache fast_ccache; - struct pa_info_data *ppaid; struct fast_state { - int flags; + enum PA_FX_FAST_REQUEST_enum type; + unsigned int flags; #define KRB5_FAST_REPLY_KEY_USE_TO_ENCRYPT_THE_REPLY 1 #define KRB5_FAST_REPLY_KEY_USE_IN_TRANSACTION 2 #define KRB5_FAST_KDC_REPLY_KEY_REPLACED 4 #define KRB5_FAST_REPLY_REPLY_VERIFED 8 #define KRB5_FAST_STRONG 16 +#define KRB5_FAST_EXPECTED 32 krb5_keyblock *reply_key; + krb5_ccache armor_ccache; + krb5_crypto armor_crypto; + krb5_keyblock armor_key; } fast_state; } krb5_get_init_creds_ctx; @@ -150,6 +153,15 @@ free_init_creds_ctx(krb5_context context, krb5_init_creds_context ctx) memset(ctx->password, 0, strlen(ctx->password)); free(ctx->password); } + /* + * FAST state + */ + if (ctx->fast_state.armor_ccache) + krb5_cc_close(context, ctx->fast_state.armor_ccache); + if (ctx->fast_state.armor_crypto) + krb5_crypto_destroy(context, ctx->fast_state.armor_crypto); + krb5_free_keyblock_contents(context, &ctx->fast_state.armor_key); + krb5_data_free(&ctx->req_buffer); krb5_free_cred_contents(context, &ctx->cred); free_METHOD_DATA(&ctx->md); @@ -1637,10 +1649,240 @@ krb5_init_creds_set_fast_ccache(krb5_context context, krb5_init_creds_context ctx, krb5_ccache fast_ccache) { - ctx->fast_ccache = fast_ccache; + ctx->fast_state.armor_ccache = fast_ccache; return 0; } +/* + * FAST + */ + +static krb5_error_code +check_fast(krb5_context context, struct fast_state *state) +{ + if (state->flags & KRB5_FAST_EXPECTED) { + krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, + "Expected FAST not not found"); + return KRB5KRB_AP_ERR_MODIFIED; + } + return 0; +} + + +static krb5_error_code +fast_unwrap_as_rep(krb5_context context, struct fast_state *state, AS_REP *rep) +{ + if (state->armor_crypto == NULL) + return check_fast(context, state); + + /* + unwrap_req(rep); + */ + + return 0; +} + +static krb5_error_code +fast_unwrap_error(krb5_context context, struct fast_state *state, KRB_ERROR *error) +{ + if (state->armor_crypto == NULL) + return check_fast(context, state); + + return 0; +} + +static krb5_error_code +make_fast_ap_fxarmor(krb5_context context, + struct fast_state *state, + KrbFastArmor **armor) +{ + KrbFastArmor *fxarmor = NULL; + krb5_auth_context auth_context = NULL; + krb5_creds cred, *credp = NULL; + krb5_error_code ret; + + ALLOC(fxarmor, 1); + if (fxarmor == NULL) { + ret = ENOMEM; + goto out; + } + + fxarmor->armor_type = 1; + + memset(&cred, 0, sizeof(cred)); + + ret = krb5_auth_con_init (context, &auth_context); + if (ret) + goto out; + + ret = krb5_cc_get_principal(context, state->armor_ccache, &cred.client); + if (ret) + goto out; + + ret = krb5_make_principal(context, &cred.server, + cred.client->realm, + KRB5_TGS_NAME, + cred.client->realm, + NULL); + if (ret) { + krb5_free_principal(context, cred.client); + goto out; + } + + ret = krb5_get_credentials(context, 0, state->armor_ccache, &cred, &credp); + krb5_free_principal(context, cred.server); + krb5_free_principal(context, cred.client); + if (ret) + goto out; + + ret = krb5_mk_req_extended(context, + &auth_context, + AP_OPTS_USE_SUBKEY, + NULL, + credp, + &fxarmor->armor_value); + krb5_free_creds(context, credp); + if (ret) + goto out; + + if (state->armor_crypto) + krb5_crypto_destroy(context, state->armor_crypto); + krb5_free_keyblock_contents(context, &state->armor_key); + + ret = _krb5_fast_armor_key(context, + auth_context->keyblock, + auth_context->local_subkey, + &state->armor_key, + &state->armor_crypto); + if (ret) + goto out; + + *armor = fxarmor; + fxarmor = NULL; + out: + if (fxarmor) + free_KrbFastArmor(fxarmor); + return ret; +} + + +static krb5_error_code +fast_wrap_req(krb5_context context, struct fast_state *state, KDC_REQ *req) +{ + KrbFastArmor *fxarmor = NULL; + PA_FX_FAST_REQUEST fxreq; + krb5_error_code ret; + KrbFastReq fastreq; + krb5_data data; + size_t size; + + memset(&fxreq, 0, sizeof(fxreq)); + memset(&fastreq, 0, sizeof(fastreq)); + krb5_data_zero(&data); + + if (state->armor_crypto == NULL) { + if (state->armor_ccache) { + /* + * Instead of keeping state in FX_COOKIE in the KDC, we + * rebuild a new armor key for every request, because this + * is what the MIT KDC expect and RFC6113 is vage about + * what the behavior should be. + */ + state->type = choice_PA_FX_FAST_REQUEST_armored_data; + } else { + return check_fast(context, state); + } + } + + state->flags |= KRB5_FAST_EXPECTED; + + fastreq.fast_options.hide_client_names = 1; + + ret = copy_KDC_REQ_BODY(&req->req_body, &fastreq.req_body); + free_KDC_REQ_BODY(&req->req_body); + + req->req_body.realm = strdup(KRB5_ANON_REALM); + ALLOC(req->req_body.cname, 1); + req->req_body.cname->name_type = KRB5_NT_PRINCIPAL; + ALLOC(req->req_body.cname->name_string.val, 2); + req->req_body.cname->name_string.len = 2; + req->req_body.cname->name_string.val[0] = strdup(KRB5_WELLKNOWN_NAME); + req->req_body.cname->name_string.val[1] = strdup(KRB5_ANON_NAME); + + if (req->padata) { + ret = copy_METHOD_DATA(req->padata, &fastreq.padata); + free_METHOD_DATA(req->padata); + } else { + ALLOC(req->padata, 1); + } + + + ASN1_MALLOC_ENCODE(KrbFastReq, data.data, data.length, &fastreq, &size, ret); + if (ret) + goto out; + heim_assert(data.length == size, "ASN.1 internal error"); + + fxreq.element = state->type; + + if (state->type == choice_PA_FX_FAST_REQUEST_armored_data) { + size_t len; + void *buf; + + ret = make_fast_ap_fxarmor(context, state, &fxreq.u.armored_data.armor); + if (ret) + goto out; + + heim_assert(state->armor_crypto != NULL, "FAST armor key missing when FAST started"); + + ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, len, &req->req_body, &size, ret); + if (ret) + goto out; + heim_assert(len == size, "ASN.1 internal error"); + + ret = krb5_create_checksum(context, state->armor_crypto, + KRB5_KU_FAST_REQ_CHKSUM, 0, + buf, len, + &fxreq.u.armored_data.req_checksum); + free(buf); + if (ret) + goto out; + + ret = krb5_encrypt_EncryptedData(context, state->armor_crypto, + KRB5_KU_FAST_ENC, + data.data, + data.length, + 0, + &fxreq.u.armored_data.enc_fast_req); + krb5_data_free(&data); + + } else { + krb5_data_free(&data); + heim_assert(false, "unknown FAST type, internal error"); + } + + ASN1_MALLOC_ENCODE(PA_FX_FAST_REQUEST, data.data, data.length, &fxreq, &size, ret); + if (ret) + goto out; + heim_assert(data.length == size, "ASN.1 internal error"); + + + ret = krb5_padata_add(context, req->padata, KRB5_PADATA_FX_FAST, data.data, data.length); + if (ret) + goto out; + krb5_data_zero(&data); + + out: + free_PA_FX_FAST_REQUEST(&fxreq); + if (fxarmor) { + free_KrbFastArmor(fxarmor); + free(fxarmor); + } + krb5_data_free(&data); + + return ret; +} + + /** * The core loop if krb5_get_init_creds() function family. Create the * packets and have the caller send them off to the KDC. @@ -1673,6 +1915,7 @@ krb5_init_creds_step(krb5_context context, krb5_error_code ret; size_t len = 0; size_t size; + AS_REQ req2; krb5_data_zero(out); @@ -1709,6 +1952,13 @@ krb5_init_creds_step(krb5_context context, if (ret == 0) { unsigned eflags = EXTRACT_TICKET_AS_REQ | EXTRACT_TICKET_TIMESYNC; + /* + * Unwrap AS-REP + */ + ret = fast_unwrap_as_rep(context, &ctx->fast_state, &rep.kdc_rep); + if (ret) + goto out; + if (ctx->flags.canonicalize) { eflags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH; eflags |= EXTRACT_TICKET_MATCH_REALM; @@ -1765,6 +2015,17 @@ krb5_init_creds_step(krb5_context context, goto out; } + /* + * Unwrap KRB-ERROR + */ + ret = fast_unwrap_error(context, &ctx->fast_state, &ctx->error); + if (ret) + goto out; + + /* + * + */ + ret = krb5_error_from_rd_error(context, &ctx->error, &ctx->cred); _krb5_debug(context, 5, "krb5_get_init_creds: KRB-ERROR %d", ret); @@ -1845,11 +2106,23 @@ krb5_init_creds_step(krb5_context context, if (ret) goto out; + /* + * Wrap with FAST + */ + copy_AS_REQ(&ctx->as_req, &req2); + + ret = fast_wrap_req(context, &ctx->fast_state, &req2); + if (ret) { + free_AS_REQ(&req2); + goto out; + } + krb5_data_free(&ctx->req_buffer); ASN1_MALLOC_ENCODE(AS_REQ, ctx->req_buffer.data, ctx->req_buffer.length, - &ctx->as_req, &len, ret); + &req2, &len, ret); + free_AS_REQ(&req2); if (ret) goto out; if(len != ctx->req_buffer.length) From d9b36b3155fd2c19f6a8bf65632a4b754d5a499a Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Sun, 15 May 2011 13:26:19 -0700 Subject: [PATCH 070/119] add fast.c --- lib/krb5/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/krb5/Makefile.am b/lib/krb5/Makefile.am index 9429535eb..5cd24fa6f 100644 --- a/lib/krb5/Makefile.am +++ b/lib/krb5/Makefile.am @@ -147,6 +147,7 @@ dist_libkrb5_la_SOURCES = \ error_string.c \ expand_hostname.c \ expand_path.c \ + fast.c \ fcache.c \ free.c \ free_host_realm.c \ From 57b96a269e963cc5af9afd192ed57d4b2733a7e9 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Sun, 15 May 2011 13:48:39 -0700 Subject: [PATCH 071/119] different logging --- kdc/kerberos5.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 3c67a3bad..799553373 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -1573,8 +1573,10 @@ _kdc_as_rep(kdc_request_t r, * Look for FAST armor and unwrap */ ret = _kdc_fast_unwrap_request(r); - if (ret) + if (ret) { + _kdc_r_log(r, 0, "FAST unwrap request from %s failed: %d", from, ret); goto out; + } b = &req->req_body; f = b->kdc_options; @@ -2117,6 +2119,7 @@ _kdc_as_rep(kdc_request_t r, i = 0; pa = _kdc_find_padata(req, &i, KRB5_PADATA_REQ_ENC_PA_REP); if (pa) { + ret = add_enc_pa_rep(r); if (ret) { const char *msg = krb5_get_error_message(r->context, ret); @@ -2154,7 +2157,6 @@ out: * In case of a non proxy error, build an error message. */ if(ret != 0 && ret != HDB_ERR_NOT_FOUND_HERE) { - kdc_log(context, config, 10, "as-req: sending error: %d to client", ret); ret = _kdc_fast_mk_error(context, &error_method, r->armor_crypto, From 102d4f5762b2fbf5bd0ae2bcfd8b5800137dcb39 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Sun, 15 May 2011 13:48:52 -0700 Subject: [PATCH 072/119] export KrbFastArmor --- lib/asn1/krb5.asn1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/asn1/krb5.asn1 b/lib/asn1/krb5.asn1 index 31a4c767d..eed3b9399 100644 --- a/lib/asn1/krb5.asn1 +++ b/lib/asn1/krb5.asn1 @@ -77,7 +77,8 @@ EXPORTS TypedData, KrbFastResponse, KrbFastFinished, - KrbFastReq + KrbFastReq, + KrbFastArmor ; NAME-TYPE ::= INTEGER { From f76cf44d8233785853e9812b287457569479f448 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Sun, 15 May 2011 13:49:06 -0700 Subject: [PATCH 073/119] add KRB5_ANON_REALM --- lib/krb5/krb5.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/krb5/krb5.h b/lib/krb5/krb5.h index f0f08a8d4..5c9028a88 100644 --- a/lib/krb5/krb5.h +++ b/lib/krb5/krb5.h @@ -683,6 +683,7 @@ typedef EncAPRepPart krb5_ap_rep_enc_part; #define KRB5_TGS_NAME ("krbtgt") #define KRB5_WELLKNOWN_NAME ("WELLKNOWN") #define KRB5_ANON_NAME ("ANONYMOUS") +#define KRB5_ANON_REALM ("WELLKNOWN:ANONYMOUS") #define KRB5_DIGEST_NAME ("digest") typedef enum { From aaf9594429a97ca31bf5e42a6347c1239384132c Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Sun, 15 May 2011 13:49:39 -0700 Subject: [PATCH 074/119] new use of _krb5_extract_ticket --- lib/krb5/get_cred.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/krb5/get_cred.c b/lib/krb5/get_cred.c index e3bb23a2e..eb5f8efeb 100644 --- a/lib/krb5/get_cred.c +++ b/lib/krb5/get_cred.c @@ -556,6 +556,7 @@ get_cred_kdc(krb5_context context, &krbtgt->addresses, nonce, eflags, + NULL, decrypt_tkt_with_subkey, subkey); out2: From adf772865c7630aaea22b06d71696be3c6cdbc4b Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Sun, 15 May 2011 13:49:46 -0700 Subject: [PATCH 075/119] new use of _krb5_extract_ticket --- lib/krb5/get_in_tkt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/krb5/get_in_tkt.c b/lib/krb5/get_in_tkt.c index 41618b961..c4b16c9a2 100644 --- a/lib/krb5/get_in_tkt.c +++ b/lib/krb5/get_in_tkt.c @@ -510,6 +510,7 @@ krb5_get_in_cred(krb5_context context, NULL, nonce, flags, + NULL, decrypt_proc, decryptarg); } From a01520cb5020368f951e3897f9784f22ebcedb50 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Sun, 15 May 2011 13:50:14 -0700 Subject: [PATCH 076/119] validate KRB5_PADATA_REQ_ENC_PA_REP --- lib/krb5/ticket.c | 55 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/lib/krb5/ticket.c b/lib/krb5/ticket.c index 4845a93d9..979d5ffa6 100644 --- a/lib/krb5/ticket.c +++ b/lib/krb5/ticket.c @@ -592,7 +592,9 @@ check_client_referral(krb5_context context, return 0; noreferral: - if (krb5_principal_compare(context, requested, mapped) == FALSE) { + if (krb5_principal_compare(context, requested, mapped) == FALSE && + !rep->enc_part.flags.enc_pa_rep) + { krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, N_("Not same client principal returned " "as requested", "")); @@ -656,6 +658,7 @@ _krb5_extract_ticket(krb5_context context, krb5_addresses *addrs, unsigned nonce, unsigned flags, + krb5_data *request, krb5_decrypt_proc decrypt_proc, krb5_const_pointer decryptarg) { @@ -674,6 +677,48 @@ _krb5_extract_ticket(krb5_context context, if (ret) goto out; + if (rep->enc_part.flags.enc_pa_rep && request) { + krb5_crypto crypto = NULL; + Checksum cksum; + PA_DATA *pa = NULL; + int idx = 0; + + _krb5_debug(context, 5, "processing enc-ap-rep"); + + if (rep->enc_part.encrypted_pa_data == NULL || + (pa = krb5_find_padata(rep->enc_part.encrypted_pa_data->val, + rep->enc_part.encrypted_pa_data->len, + KRB5_PADATA_REQ_ENC_PA_REP, + &idx)) == NULL) + { + _krb5_debug(context, 5, "KRB5_PADATA_REQ_ENC_PA_REP missing"); + ret = KRB5KRB_AP_ERR_MODIFIED; + goto out; + } + + ret = krb5_crypto_init(context, key, 0, &crypto); + if (ret) + goto out; + + ret = decode_Checksum(pa->padata_value.data, + pa->padata_value.length, + &cksum, NULL); + if (ret) { + krb5_crypto_destroy(context, crypto); + goto out; + } + + ret = krb5_verify_checksum(context, crypto, + KRB5_KU_AS_REQ, + request->data, request->length, + &cksum); + krb5_crypto_destroy(context, crypto); + free_Checksum(&cksum); + _krb5_debug(context, 5, "enc-ap-rep: %svalid", (ret == 0) ? "" : "in"); + if (ret) + goto out; + } + /* save session key */ creds->session.keyvalue.length = 0; @@ -688,10 +733,10 @@ _krb5_extract_ticket(krb5_context context, } /* compare client and save */ - ret = _krb5_principalname2krb5_principal (context, - &tmp_principal, - rep->kdc_rep.cname, - rep->kdc_rep.crealm); + ret = _krb5_principalname2krb5_principal(context, + &tmp_principal, + rep->kdc_rep.cname, + rep->kdc_rep.crealm); if (ret) goto out; From 03e73522a34cab0cea6895844216493cde5a9601 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Sun, 15 May 2011 13:50:34 -0700 Subject: [PATCH 077/119] better status message --- tests/kdc/check-fast.in | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/kdc/check-fast.in b/tests/kdc/check-fast.in index a28be9db8..046ca120b 100644 --- a/tests/kdc/check-fast.in +++ b/tests/kdc/check-fast.in @@ -116,14 +116,13 @@ ${akinit} --password-file=${objdir}/foopassword ${server}@${R} >/dev/null|| { ex echo "Checking for FAST avail" ${aklist} --hidden | grep fast_avail > /dev/null || { exit 1; } -echo "Checking out with FAST armor ticket" +echo "Getting client initial tickets with FAST armor ticket" ${kinit} --fast-armor-cache=${acache} \ --password-file=${objdir}/foopassword foo@$R || \ { ec=1 ; eval "${testfailed}"; } - kinitpty=${objdir}/foopassword.rkpty cat > ${kinitpty} < Date: Sun, 15 May 2011 13:52:19 -0700 Subject: [PATCH 078/119] remove to strict usage --- lib/krb5/crypto.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/krb5/crypto.c b/lib/krb5/crypto.c index 236f60f86..732311bec 100644 --- a/lib/krb5/crypto.c +++ b/lib/krb5/crypto.c @@ -466,12 +466,6 @@ verify_checksum(krb5_context context, ret = get_checksum_key(context, crypto, usage, ct, &dkey); if (ret) return ret; - } else if (crypto) { - krb5_set_error_message(context, KRB5_PROG_SUMTYPE_NOSUPP, - N_("Checksum type %s is unkeyed, " - "but caller expected key checksum %s", ""), - ct->name, crypto->et->name); - return KRB5_PROG_SUMTYPE_NOSUPP; /* XXX */ } else dkey = NULL; From 8a5c96e6804b77227f2b1b6b053856ae24260379 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Sun, 15 May 2011 15:07:06 -0700 Subject: [PATCH 079/119] process last request and pass in server name --- kuser/kinit.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/kuser/kinit.c b/kuser/kinit.c index c98bb7055..cbe762478 100644 --- a/kuser/kinit.c +++ b/kuser/kinit.c @@ -508,6 +508,12 @@ get_new_tickets(krb5_context context, if (ret) krb5_err(context, 1, ret, "krb5_init_creds_init"); + if (server_str) { + ret = krb5_init_creds_set_service(context, ctx, server_str); + if (ret) + krb5_err(context, 1, ret, "krb5_init_creds_set_service"); + } + if (fast_armor_cache_string) { krb5_ccache fastid; @@ -564,7 +570,6 @@ get_new_tickets(krb5_context context, ret = krb5_init_creds_get(context, ctx); - krb5_get_init_creds_opt_free(context, opt); #ifndef NO_NTLM if (ntlm_domain && passwd[0]) heim_ntlm_nt_key(passwd, &ntlmkey); @@ -588,6 +593,8 @@ get_new_tickets(krb5_context context, krb5_err(context, 1, ret, "krb5_get_init_creds"); } + krb5_process_last_request(context, opt, ctx); + if(ticket_life != 0) { if(abs(cred.times.endtime - cred.times.starttime - ticket_life) > 30) { char life[64]; @@ -645,6 +652,8 @@ get_new_tickets(krb5_context context, krb5_cc_set_config(context, ccache, NULL, "realm-config", &data); } + krb5_get_init_creds_opt_free(context, opt); + if (kt) krb5_kt_close(context, kt); if (enctype) From b73d402a47556ab41f61a12eb9ef640d871507f9 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Sun, 15 May 2011 15:07:23 -0700 Subject: [PATCH 080/119] export process last request --- lib/krb5/init_creds_pw.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/krb5/init_creds_pw.c b/lib/krb5/init_creds_pw.c index 2a6a64ee9..f2284f75c 100644 --- a/lib/krb5/init_creds_pw.c +++ b/lib/krb5/init_creds_pw.c @@ -273,10 +273,10 @@ report_expiration (krb5_context context, * @param ctx The krb5_init_creds_context check for expiration. */ -static krb5_error_code -process_last_request(krb5_context context, - krb5_get_init_creds_opt *options, - krb5_init_creds_context ctx) +krb5_error_code +krb5_process_last_request(krb5_context context, + krb5_get_init_creds_opt *options, + krb5_init_creds_context ctx) { krb5_const_realm realm; LastReq *lr; @@ -2350,7 +2350,7 @@ krb5_get_init_creds_password(krb5_context context, ret = krb5_init_creds_get(context, ctx); if (ret == 0) - process_last_request(context, options, ctx); + krb5_process_last_request(context, options, ctx); if (ret == KRB5KDC_ERR_KEY_EXPIRED && chpw == 0) { @@ -2425,7 +2425,7 @@ krb5_get_init_creds_keyblock(krb5_context context, ret = krb5_init_creds_get(context, ctx); if (ret == 0) - process_last_request(context, options, ctx); + krb5_process_last_request(context, options, ctx); out: if (ret == 0) @@ -2471,7 +2471,7 @@ krb5_get_init_creds_keytab(krb5_context context, ret = krb5_init_creds_get(context, ctx); if (ret == 0) - process_last_request(context, options, ctx); + krb5_process_last_request(context, options, ctx); out: if (ret == 0) From 19e572db60b7f7b04d0a222db80075921eed5a8e Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Sun, 15 May 2011 15:54:56 -0700 Subject: [PATCH 081/119] add krb5_process_last_request --- lib/krb5/version-script.map | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/krb5/version-script.map b/lib/krb5/version-script.map index 818e6e071..c267af305 100644 --- a/lib/krb5/version-script.map +++ b/lib/krb5/version-script.map @@ -764,6 +764,7 @@ HEIMDAL_KRB5_2.0 { # kinit helper krb5_get_init_creds_opt_set_pkinit_user_certs; krb5_pk_enterprise_cert; + krb5_process_last_request; # testing _krb5_aes_cts_encrypt; From 91df0a81202832981a6450165423982c4ebf6ac6 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Mon, 16 May 2011 19:48:20 -0700 Subject: [PATCH 082/119] add _krb5_fast_cf2 --- lib/krb5/fast.c | 44 ++++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/lib/krb5/fast.c b/lib/krb5/fast.c index 67e812df0..3af610989 100644 --- a/lib/krb5/fast.c +++ b/lib/krb5/fast.c @@ -35,11 +35,13 @@ krb5_error_code -_krb5_fast_armor_key(krb5_context context, - krb5_keyblock *sessionkey, - krb5_keyblock *subkey, - krb5_keyblock *armorkey, - krb5_crypto *armor_crypto) +_krb5_fast_cf2(krb5_context context, + krb5_keyblock *sessionkey, + const char *sessionpepper, + krb5_keyblock *subkey, + const char *subkeypepper, + krb5_keyblock *armorkey, + krb5_crypto *armor_crypto) { krb5_crypto crypto_subkey, crypto_session; krb5_data pepper1, pepper2; @@ -55,10 +57,10 @@ _krb5_fast_armor_key(krb5_context context, return ret; } - pepper1.data = "subkeyarmor"; - pepper1.length = strlen(pepper1.data); - pepper2.data = "ticketarmor"; - pepper2.length = strlen(pepper2.data); + pepper1.data = rk_UNCONST(sessionpepper); + pepper1.length = strlen(sessionpepper); + pepper2.data = rk_UNCONST(subkeypepper); + pepper2.length = strlen(subkeypepper); ret = krb5_crypto_fx_cf2(context, crypto_subkey, crypto_session, &pepper1, &pepper2, @@ -69,9 +71,27 @@ _krb5_fast_armor_key(krb5_context context, if (ret) return ret; - ret = krb5_crypto_init(context, armorkey, 0, armor_crypto); - if (ret) - krb5_free_keyblock_contents(context, armorkey); + if (armor_crypto) { + ret = krb5_crypto_init(context, armorkey, 0, armor_crypto); + if (ret) + krb5_free_keyblock_contents(context, armorkey); + } return ret; } + +krb5_error_code +_krb5_fast_armor_key(krb5_context context, + krb5_keyblock *sessionkey, + krb5_keyblock *subkey, + krb5_keyblock *armorkey, + krb5_crypto *armor_crypto) +{ + return _krb5_fast_cf2(context, + sessionkey, + "ticketarmor", + subkey, + "subkeyarmor", + armorkey, + armor_crypto); +} From 04c7dd7cee4b003746f21ccfc30e57b3d8c9f08d Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Mon, 16 May 2011 20:32:00 -0700 Subject: [PATCH 083/119] start completion of KrbFastFinished --- lib/krb5/init_creds_pw.c | 92 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 87 insertions(+), 5 deletions(-) diff --git a/lib/krb5/init_creds_pw.c b/lib/krb5/init_creds_pw.c index f2284f75c..a4a85b968 100644 --- a/lib/krb5/init_creds_pw.c +++ b/lib/krb5/init_creds_pw.c @@ -1672,14 +1672,96 @@ check_fast(krb5_context context, struct fast_state *state) static krb5_error_code fast_unwrap_as_rep(krb5_context context, struct fast_state *state, AS_REP *rep) { - if (state->armor_crypto == NULL) + PA_FX_FAST_REPLY fxfastrep; + KrbFastResponse fastrep; + KrbFastFinished finished; + krb5_error_code ret; + PA_DATA *pa = NULL; + int idx = 0; + + if (state->armor_crypto == NULL || rep->padata == NULL) return check_fast(context, state); - /* - unwrap_req(rep); - */ + /* find PA_FX_FAST_REPLY */ - return 0; + pa = krb5_find_padata(rep->padata->val, rep->padata->len, + KRB5_PADATA_FX_FAST, &idx); + if (pa == NULL) + return check_fast(context, state); + + memset(&fxfastrep, 0, sizeof(fxfastrep)); + memset(&fastrep, 0, sizeof(fastrep)); + memset(&finished, 0, sizeof(finished)); + + ret = decode_PA_FX_FAST_REPLY(pa->padata_value.data, pa->padata_value.length, &fxfastrep, NULL); + if (ret) + return ret; + + if (fxfastrep.element == choice_PA_FX_FAST_REPLY_armored_data) { + krb5_data data; + ret = krb5_decrypt_EncryptedData(context, + state->armor_crypto, + KRB5_KU_FAST_REP, + &fxfastrep.u.armored_data.enc_fast_rep, + &data); + if (ret) + goto out; + + ret = decode_KrbFastResponse(data.data, data.length, &fastrep, NULL); + krb5_data_free(&data); + if (ret) + goto out; + + } else { + ret = EINVAL; + goto out; + } + + free_METHOD_DATA(rep->padata); + ret = copy_METHOD_DATA(&fastrep.padata, rep->padata); + if (ret) + goto out; + + if (fastrep.strengthen_key) { + krb5_keyblock result; + + ret = _krb5_fast_cf2(context, + state->reply_key, + "", + fastrep.strengthen_key, + "", + &result, + NULL); + if (ret) + goto out; + krb5_free_keyblock(context, state->reply_key); + state->reply_key = NULL; + + ret = krb5_copy_keyblock(context, &result, &state->reply_key); + if (ret) + goto out; + krb5_free_keyblock_contents(context, &result); + } +#if 0 + /* extract and replace */ + fastrep.nonce; + + if (fastrep.finished) { + /* validate */ + finished.ticket_checksum; + /* store */ + finished.timestamp; + finished.usec = 0; + /* update */ + finished.crealm; + finished.cname; + } +#endif + + out: + free_PA_FX_FAST_REPLY(&fxfastrep); + + return ret; } static krb5_error_code From 7e1468ca5216c3b529b00c6c00ffff9af0747abe Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Mon, 16 May 2011 20:58:50 -0700 Subject: [PATCH 084/119] new call order too _krb5_fast_armor_key --- kdc/fast.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kdc/fast.c b/kdc/fast.c index 82230767e..c0b2c4d3c 100644 --- a/kdc/fast.c +++ b/kdc/fast.c @@ -312,8 +312,8 @@ _kdc_fast_unwrap_request(kdc_request_t r) } ret = _krb5_fast_armor_key(r->context, - &ticket->ticket.key, ac->remote_subkey, + &ticket->ticket.key, &armorkey, &r->armor_crypto); krb5_auth_con_free(r->context, ac); From 7635eee8c45562d8ba788e2034b1c39d385adfc9 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Mon, 16 May 2011 21:01:33 -0700 Subject: [PATCH 085/119] simplify --- lib/krb5/fast.c | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/lib/krb5/fast.c b/lib/krb5/fast.c index 3af610989..6da482d41 100644 --- a/lib/krb5/fast.c +++ b/lib/krb5/fast.c @@ -36,38 +36,36 @@ krb5_error_code _krb5_fast_cf2(krb5_context context, - krb5_keyblock *sessionkey, - const char *sessionpepper, - krb5_keyblock *subkey, - const char *subkeypepper, + krb5_keyblock *key1, + const char *pepper1, + krb5_keyblock *key2, + const char *pepper2, krb5_keyblock *armorkey, krb5_crypto *armor_crypto) { - krb5_crypto crypto_subkey, crypto_session; - krb5_data pepper1, pepper2; + krb5_crypto crypto1, crypto2; + krb5_data pa1, pa2; krb5_error_code ret; - ret = krb5_crypto_init(context, subkey, 0, &crypto_subkey); + ret = krb5_crypto_init(context, key1, 0, &crypto1); if (ret) return ret; - ret = krb5_crypto_init(context, sessionkey, 0, &crypto_session); + ret = krb5_crypto_init(context, key2, 0, &crypto2); if (ret) { - krb5_crypto_destroy(context, crypto_subkey); + krb5_crypto_destroy(context, crypto1); return ret; } - pepper1.data = rk_UNCONST(sessionpepper); - pepper1.length = strlen(sessionpepper); - pepper2.data = rk_UNCONST(subkeypepper); - pepper2.length = strlen(subkeypepper); + pa1.data = rk_UNCONST(pepper1); + pa1.length = strlen(pepper1); + pa2.data = rk_UNCONST(pepper2); + pa2.length = strlen(pepper2); - ret = krb5_crypto_fx_cf2(context, crypto_subkey, crypto_session, - &pepper1, &pepper2, - subkey->keytype, - armorkey); - krb5_crypto_destroy(context, crypto_subkey); - krb5_crypto_destroy(context, crypto_session); + ret = krb5_crypto_fx_cf2(context, crypto1, crypto2, &pa1, &pa2, + key1->keytype, armorkey); + krb5_crypto_destroy(context, crypto1); + krb5_crypto_destroy(context, crypto2); if (ret) return ret; @@ -82,16 +80,16 @@ _krb5_fast_cf2(krb5_context context, krb5_error_code _krb5_fast_armor_key(krb5_context context, - krb5_keyblock *sessionkey, krb5_keyblock *subkey, + krb5_keyblock *sessionkey, krb5_keyblock *armorkey, krb5_crypto *armor_crypto) { return _krb5_fast_cf2(context, - sessionkey, - "ticketarmor", subkey, "subkeyarmor", + sessionkey, + "ticketarmor", armorkey, armor_crypto); } From b6d5637b6176f12398a73496e4ec48c6b94fa8df Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Mon, 16 May 2011 21:02:05 -0700 Subject: [PATCH 086/119] fill in more bits --- lib/krb5/init_creds_pw.c | 58 +++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/lib/krb5/init_creds_pw.c b/lib/krb5/init_creds_pw.c index a4a85b968..f3f8ef934 100644 --- a/lib/krb5/init_creds_pw.c +++ b/lib/krb5/init_creds_pw.c @@ -1670,7 +1670,9 @@ check_fast(krb5_context context, struct fast_state *state) static krb5_error_code -fast_unwrap_as_rep(krb5_context context, struct fast_state *state, AS_REP *rep) +fast_unwrap_as_rep(krb5_context context, int32_t nonce, + krb5_data *chksumdata, + struct fast_state *state, AS_REP *rep) { PA_FX_FAST_REPLY fxfastrep; KrbFastResponse fastrep; @@ -1726,37 +1728,48 @@ fast_unwrap_as_rep(krb5_context context, struct fast_state *state, AS_REP *rep) krb5_keyblock result; ret = _krb5_fast_cf2(context, - state->reply_key, - "", fastrep.strengthen_key, - "", + "strengthenkey", + state->reply_key, + "replykey", &result, NULL); if (ret) goto out; - krb5_free_keyblock(context, state->reply_key); - state->reply_key = NULL; - ret = krb5_copy_keyblock(context, &result, &state->reply_key); + krb5_free_keyblock_contents(context, state->reply_key); + *state->reply_key = result; + } + + if (nonce != fastrep.nonce) { + ret = EINVAL; + goto out; + } + if (fastrep.finished) { + if (chksumdata == NULL) + return EINVAL; + + ret = krb5_verify_checksum(context, state->armor_crypto, + KRB5_KU_FAST_FINISHED, + chksumdata->data, chksumdata->length, + &fastrep.finished->ticket_checksum); if (ret) goto out; - krb5_free_keyblock_contents(context, &result); - } -#if 0 - /* extract and replace */ - fastrep.nonce; - if (fastrep.finished) { - /* validate */ - finished.ticket_checksum; /* store */ +#if 0 finished.timestamp; finished.usec = 0; +#endif /* update */ +#if 0 finished.crealm; finished.cname; - } #endif + } else if (chksumdata) { + /* expected fastrep.finish but didn't get it */ + ret = EINVAL; + } out: free_PA_FX_FAST_REPLY(&fxfastrep); @@ -1832,8 +1845,8 @@ make_fast_ap_fxarmor(krb5_context context, krb5_free_keyblock_contents(context, &state->armor_key); ret = _krb5_fast_armor_key(context, - auth_context->keyblock, auth_context->local_subkey, + auth_context->keyblock, &state->armor_key, &state->armor_crypto); if (ret) @@ -2033,11 +2046,20 @@ krb5_init_creds_step(krb5_context context, ret = decode_AS_REP(in->data, in->length, &rep.kdc_rep, &size); if (ret == 0) { unsigned eflags = EXTRACT_TICKET_AS_REQ | EXTRACT_TICKET_TIMESYNC; + krb5_data data; /* * Unwrap AS-REP */ - ret = fast_unwrap_as_rep(context, &ctx->fast_state, &rep.kdc_rep); + ASN1_MALLOC_ENCODE(Ticket, data.data, data.length, + &rep.kdc_rep.ticket, &size, ret); + if (ret) + goto out; + heim_assert(data.length == size, "ASN.1 internal error"); + + ret = fast_unwrap_as_rep(context, ctx->nonce, &data, + &ctx->fast_state, &rep.kdc_rep); + krb5_data_free(&data); if (ret) goto out; From 067072f81e03adb23bea332adea7b1cc32896b1a Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Mon, 16 May 2011 21:18:08 -0700 Subject: [PATCH 087/119] complete KrbFastFinished message work --- lib/krb5/init_creds_pw.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/lib/krb5/init_creds_pw.c b/lib/krb5/init_creds_pw.c index f3f8ef934..1befd204f 100644 --- a/lib/krb5/init_creds_pw.c +++ b/lib/krb5/init_creds_pw.c @@ -1676,7 +1676,6 @@ fast_unwrap_as_rep(krb5_context context, int32_t nonce, { PA_FX_FAST_REPLY fxfastrep; KrbFastResponse fastrep; - KrbFastFinished finished; krb5_error_code ret; PA_DATA *pa = NULL; int idx = 0; @@ -1693,7 +1692,6 @@ fast_unwrap_as_rep(krb5_context context, int32_t nonce, memset(&fxfastrep, 0, sizeof(fxfastrep)); memset(&fastrep, 0, sizeof(fastrep)); - memset(&finished, 0, sizeof(finished)); ret = decode_PA_FX_FAST_REPLY(pa->padata_value.data, pa->padata_value.length, &fxfastrep, NULL); if (ret) @@ -1746,6 +1744,9 @@ fast_unwrap_as_rep(krb5_context context, int32_t nonce, goto out; } if (fastrep.finished) { + PrincipalName cname; + krb5_realm crealm = NULL; + if (chksumdata == NULL) return EINVAL; @@ -1756,16 +1757,24 @@ fast_unwrap_as_rep(krb5_context context, int32_t nonce, if (ret) goto out; - /* store */ -#if 0 - finished.timestamp; - finished.usec = 0; -#endif /* update */ -#if 0 - finished.crealm; - finished.cname; + ret = copy_Realm(&fastrep.finished->crealm, &crealm); + if (ret) + goto out; + free_Realm(&rep->crealm); + rep->crealm = crealm; + + ret = copy_PrincipalName(&fastrep.finished->cname, &cname); + if (ret) + goto out; + free_PrincipalName(&rep->cname); + rep->cname = cname; + +#if 0 /* store authenticated checksum as kdc-offset */ + fastrep->finished.timestamp; + fastrep->finished.usec = 0; #endif + } else if (chksumdata) { /* expected fastrep.finish but didn't get it */ ret = EINVAL; From 5d1ae998f9f96d73a8d9823d239155c1df8b6e46 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Mon, 16 May 2011 22:53:54 -0700 Subject: [PATCH 088/119] "better" error codes --- lib/krb5/init_creds_pw.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/krb5/init_creds_pw.c b/lib/krb5/init_creds_pw.c index 1befd204f..04b3f890e 100644 --- a/lib/krb5/init_creds_pw.c +++ b/lib/krb5/init_creds_pw.c @@ -1713,7 +1713,7 @@ fast_unwrap_as_rep(krb5_context context, int32_t nonce, goto out; } else { - ret = EINVAL; + ret = KRB5KDC_ERR_PREAUTH_FAILED; goto out; } @@ -1740,15 +1740,17 @@ fast_unwrap_as_rep(krb5_context context, int32_t nonce, } if (nonce != fastrep.nonce) { - ret = EINVAL; + ret = KRB5KDC_ERR_PREAUTH_FAILED; goto out; } if (fastrep.finished) { PrincipalName cname; krb5_realm crealm = NULL; - if (chksumdata == NULL) - return EINVAL; + if (chksumdata == NULL) { + ret = KRB5KDC_ERR_PREAUTH_FAILED; + goto out; + } ret = krb5_verify_checksum(context, state->armor_crypto, KRB5_KU_FAST_FINISHED, @@ -1777,7 +1779,7 @@ fast_unwrap_as_rep(krb5_context context, int32_t nonce, } else if (chksumdata) { /* expected fastrep.finish but didn't get it */ - ret = EINVAL; + ret = KRB5KDC_ERR_PREAUTH_FAILED; } out: From 242d7e1602a1f5441a4ad37e408441b71d7a1782 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Mon, 16 May 2011 22:56:48 -0700 Subject: [PATCH 089/119] comment --- lib/krb5/init_creds_pw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/krb5/init_creds_pw.c b/lib/krb5/init_creds_pw.c index 04b3f890e..f74e67671 100644 --- a/lib/krb5/init_creds_pw.c +++ b/lib/krb5/init_creds_pw.c @@ -2074,6 +2074,10 @@ krb5_init_creds_step(krb5_context context, if (ret) goto out; + /* + * Now check and extract the ticket + */ + if (ctx->flags.canonicalize) { eflags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH; eflags |= EXTRACT_TICKET_MATCH_REALM; From b00f1ceeb956c32f43217f81a96f8cc7d7c0e8c2 Mon Sep 17 00:00:00 2001 From: Love Hornquist Astrand Date: Tue, 17 May 2011 07:31:04 -0700 Subject: [PATCH 090/119] should use hide_client_names --- kdc/kerberos5.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 799553373..c60ed9282 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -861,9 +861,11 @@ _kdc_encode_reply(krb5_context context, /* * Hide client name of privacy reasons */ - rep->crealm[0] = '\0'; - free_PrincipalName(&rep->cname); - rep->cname.name_type = 0; + if (1 /* r->fast_options.hide_client_names */) { + rep->crealm[0] = '\0'; + free_PrincipalName(&rep->cname); + rep->cname.name_type = 0; + } } if(rep->msg_type == krb_as_rep && !config->encode_as_rep_as_tgs_rep) From 407fcf35fc2f8583fb448a51158c542fb0d5344c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Mon, 23 May 2011 21:37:03 -0700 Subject: [PATCH 091/119] update client_access --- tests/plugin/windc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/plugin/windc.c b/tests/plugin/windc.c index 0956ce831..44518dcf7 100644 --- a/tests/plugin/windc.c +++ b/tests/plugin/windc.c @@ -69,7 +69,7 @@ client_access(void *ctx, hdb_entry_ex *client, const char *client_name, hdb_entry_ex *server, const char *server_name, KDC_REQ *req, - krb5_data *e_data) + METHOD_DATA *data) { krb5_warnx(context, "client_access"); return 0; From eaa23ce96f0898bd2236efad76f6586bd0a15c9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Tue, 24 May 2011 08:26:30 -0700 Subject: [PATCH 092/119] proxy request if needed --- kdc/fast.c | 1 - 1 file changed, 1 deletion(-) diff --git a/kdc/fast.c b/kdc/fast.c index c0b2c4d3c..cccda17c7 100644 --- a/kdc/fast.c +++ b/kdc/fast.c @@ -275,7 +275,6 @@ _kdc_fast_unwrap_request(kdc_request_t r) 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); From d99c2eda401b273d5800a66da6fe63e94d015e62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Tue, 24 May 2011 08:26:52 -0700 Subject: [PATCH 093/119] use else if --- kdc/fast.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kdc/fast.c b/kdc/fast.c index cccda17c7..c8fa04e12 100644 --- a/kdc/fast.c +++ b/kdc/fast.c @@ -276,7 +276,7 @@ _kdc_fast_unwrap_request(kdc_request_t r) "armor key does not have secrets at this KDC, " "need to proxy"); goto out; - } if(ret){ + } else if (ret) { free_AP_REQ(&ap_req); ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; goto out; From e5c66a70cd275eb686a75663df29317dab263852 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Mon, 13 Jun 2011 20:23:28 -0700 Subject: [PATCH 094/119] parse fast cookie --- kdc/fast.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/kdc/fast.c b/kdc/fast.c index c8fa04e12..168ded210 100644 --- a/kdc/fast.c +++ b/kdc/fast.c @@ -193,6 +193,71 @@ _kdc_fast_mk_error(krb5_context context, return ret; } +static krb5_error_code +fast_parse_cookie(kdc_request_t r, const PA_DATA *pa) +{ + krb5_principal fast_princ; + hdb_entry_ex *fast_user = NULL; + krb5_crypto crypto = NULL; + Key *cookie_key = NULL; + krb5_error_code ret; + KDCFastCookie data; + krb5_data d1; + size_t len; + + ret = decode_KDCFastCookie(pa->padata_value.data, + pa->padata_value.length, + &data, &len); + if (ret) + return ret; + + if (len != pa->padata_value.length || strcmp("H5L1", data.version) != 0) { + free_KDCFastCookie(&data); + return KRB5KDC_ERR_POLICY; + } + + ret = krb5_make_principal(r->context, &fast_princ, + "WELLKNOWN:ORG.H5L", + "WELLKNOWN", "org.h5l.fast-cookie", NULL); + if (ret) + goto out; + + ret = _kdc_db_fetch(r->context, r->config, fast_princ, + HDB_F_GET_CLIENT, NULL, NULL, &fast_user); + krb5_free_principal(r->context, fast_princ); + if (ret) + goto out; + + ret = hdb_enctype2key(r->context, &fast_user->entry, + data.cookie.e0type, &cookie_key); + if (ret) + goto out; + + ret = krb5_crypto_init(r->context, &cookie_key->key, 0, &crypto); + if (ret) + goto out; + + ret = krb5_decode_EncryptedData(crypto, crypto, + KRB5_KU_H5L_COOKIE, + &data.cookie, &d1); + krb5_crypto_destroy(r->context, crypto); + if (ret) + goto out; + + ret = decode_KDCFastState(d1.data, d1.length, &r->fast, &len); + krb5_data_free(&d1); + if (ret) + goto out; + + out: + free_KDCFastCookie(&data); + if (fast_user) + _kdc_free_ent(r->context, fast_user); + + return ret; +} + + krb5_error_code _kdc_fast_unwrap_request(kdc_request_t r) @@ -214,6 +279,17 @@ _kdc_fast_unwrap_request(kdc_request_t r) const PA_DATA *pa; int i = 0; + /* + * First look for FX_COOKIE and and process it + */ + pa = _kdc_find_padata(&r->req, &i, KRB5_PADATA_FX_COOKIE); + if (pa) { + ret = fast_parse_cookie(r, pa); + if (ret) + goto out; + } + + i = 0; pa = _kdc_find_padata(&r->req, &i, KRB5_PADATA_FX_FAST); if (pa == NULL) return 0; From 72308645a2c0af82b39da6c6a4a626ab84b70fc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Mon, 13 Jun 2011 20:23:36 -0700 Subject: [PATCH 095/119] fast cookie --- kdc/kdc_locl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kdc/kdc_locl.h b/kdc/kdc_locl.h index 2ed399716..1b369db0f 100644 --- a/kdc/kdc_locl.h +++ b/kdc/kdc_locl.h @@ -84,7 +84,7 @@ struct kdc_request_desc { krb5_crypto armor_crypto; - heim_dict_t pastate; + KDCFastState fast; }; From 6b942e6ec243c370c8f2a46e82ca40d7c5604a4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Mon, 13 Jun 2011 20:23:44 -0700 Subject: [PATCH 096/119] free fast cookie --- kdc/kerberos5.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index c60ed9282..561907ccc 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -2173,6 +2173,7 @@ out: out2: free_EncTicketPart(&r->et); free_EncKDCRepPart(&r->ek); + free_KDCFastState(&r->fast); if (error_method.len) free_METHOD_DATA(&error_method); From 1a8f7caf8651d232c92efa2303651844e6bcc2c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Mon, 13 Jun 2011 20:24:00 -0700 Subject: [PATCH 097/119] add Fast cookie --- lib/asn1/krb5.asn1 | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/lib/asn1/krb5.asn1 b/lib/asn1/krb5.asn1 index eed3b9399..9a472b655 100644 --- a/lib/asn1/krb5.asn1 +++ b/lib/asn1/krb5.asn1 @@ -78,7 +78,9 @@ EXPORTS KrbFastResponse, KrbFastFinished, KrbFastReq, - KrbFastArmor + KrbFastArmor, + KDCFastState, + KDCFastCookie ; NAME-TYPE ::= INTEGER { @@ -826,6 +828,25 @@ PA-FX-FAST-REPLY ::= CHOICE { ... } +KDCFastFlags ::= BIT STRING { + use_reply_key(0), + reply_key_used(1), + reply_key_replaced(2), + kdc_verfied(3) +} + +-- KDCFastState is stored in FX_COOKIE +KDCFastState ::= SEQUENCE { + flags [0] KDCFastFlags, + expiration [1] GeneralizedTime, + fast-state [2] METHOD-DATA +} + +KDCFastCookie ::= SEQUENCE { + version [0] UTF8String, + cookie [1] EncryptedData +} + END -- etags -r '/\([A-Za-z][-A-Za-z0-9]*\).*::=/\1/' k5.asn1 From e9053800f18962da4ea48c5ab0a6231945bea18a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Mon, 13 Jun 2011 20:24:11 -0700 Subject: [PATCH 098/119] add Fast cookie --- lib/krb5/krb5.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/krb5/krb5.h b/lib/krb5/krb5.h index 5c9028a88..de3753a1c 100644 --- a/lib/krb5/krb5.h +++ b/lib/krb5/krb5.h @@ -292,8 +292,10 @@ typedef enum krb5_key_usage { /* Checksum key usage used in the digest opaque field */ KRB5_KU_KRB5SIGNEDPATH = -21, /* Checksum key usage on KRB5SignedPath */ - KRB5_KU_CANONICALIZED_NAMES = -23 + KRB5_KU_CANONICALIZED_NAMES = -23, /* Checksum key usage on PA-CANONICALIZED */ + KRB5_KU_H5L_COOKIE = -25 + /* encrypted foo */ } krb5_key_usage; typedef krb5_key_usage krb5_keyusage; From 294c2786fa285dde887ebc3bb810e3c4eb7ff6bc Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Fri, 15 Jul 2011 14:10:55 +0200 Subject: [PATCH 099/119] Fix typo. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Love Hörnquist Åstrand --- kdc/fast.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kdc/fast.c b/kdc/fast.c index 168ded210..8d519cb6f 100644 --- a/kdc/fast.c +++ b/kdc/fast.c @@ -229,7 +229,7 @@ fast_parse_cookie(kdc_request_t r, const PA_DATA *pa) goto out; ret = hdb_enctype2key(r->context, &fast_user->entry, - data.cookie.e0type, &cookie_key); + data.cookie.etype, &cookie_key); if (ret) goto out; From 888780c9e7813e206a87fb09b85c02c8b519789a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Sat, 16 Jul 2011 10:32:30 -0700 Subject: [PATCH 100/119] add fast symbols --- lib/krb5/version-script.map | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/krb5/version-script.map b/lib/krb5/version-script.map index c267af305..686e27829 100644 --- a/lib/krb5/version-script.map +++ b/lib/krb5/version-script.map @@ -770,6 +770,11 @@ HEIMDAL_KRB5_2.0 { _krb5_aes_cts_encrypt; _krb5_n_fold; _krb5_expand_default_cc_name; + + # FAST + _krb5_fast_cf2; + _krb5_fast_armor_key; + local: *; }; From bebb50797ff9f2ec7707fbe18e9f960d40d89e52 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Wed, 20 Jul 2011 20:46:39 +0200 Subject: [PATCH 101/119] Add krb5_init_creds symbols needed by kinit. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Love Hörnquist Åstrand --- lib/krb5/version-script.map | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/krb5/version-script.map b/lib/krb5/version-script.map index 686e27829..9ede0d837 100644 --- a/lib/krb5/version-script.map +++ b/lib/krb5/version-script.map @@ -765,6 +765,14 @@ HEIMDAL_KRB5_2.0 { krb5_get_init_creds_opt_set_pkinit_user_certs; krb5_pk_enterprise_cert; krb5_process_last_request; + krb5_init_creds_init; + krb5_init_creds_set_service; + krb5_init_creds_set_fast_ccache; + krb5_init_creds_set_keytab; + krb5_init_creds_get; + krb5_init_creds_set_password; + krb5_init_creds_store; + krb5_init_creds_free; # testing _krb5_aes_cts_encrypt; From 12203f0fab196453fdd2746efa3116fa0739a847 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Wed, 20 Jul 2011 23:46:43 +0200 Subject: [PATCH 102/119] s/krb5_decode_EncryptedData/krb5_decrypt_EncryptedData/1. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Love Hörnquist Åstrand --- kdc/fast.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kdc/fast.c b/kdc/fast.c index 8d519cb6f..4a22188a8 100644 --- a/kdc/fast.c +++ b/kdc/fast.c @@ -237,9 +237,9 @@ fast_parse_cookie(kdc_request_t r, const PA_DATA *pa) if (ret) goto out; - ret = krb5_decode_EncryptedData(crypto, crypto, - KRB5_KU_H5L_COOKIE, - &data.cookie, &d1); + ret = krb5_decrypt_EncryptedData(crypto, crypto, + KRB5_KU_H5L_COOKIE, + &data.cookie, &d1); krb5_crypto_destroy(r->context, crypto); if (ret) goto out; From 721c5634d55543c6fc2b18da6fd0c895e2717e48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Sun, 24 Jul 2011 19:46:28 -0700 Subject: [PATCH 103/119] make compile after rebase --- kdc/kerberos5.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 561907ccc..1372831a9 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -775,7 +775,6 @@ _kdc_encode_reply(krb5_context context, const char *msg = krb5_get_error_message(context, ret); kdc_log(context, config, 0, "Failed to encode ticket: %s", msg); krb5_free_error_message(context, msg); - krb5_crypto_destroy(context, crypto); return ret; } if(buf_size != len) @@ -1687,13 +1686,13 @@ _kdc_as_rep(kdc_request_t r, */ ret = _kdc_find_etype(context, config->as_use_strongest_session_key, FALSE, - client, b->etype.val, b->etype.len, &sessionetype, + r->client, b->etype.val, b->etype.len, &r->sessionetype, NULL); if (ret) { kdc_log(context, config, 0, "Client (%s) from %s has no common enctypes with KDC " "to use for the session key", - client_name, from); + r->client_name, from); goto out; } @@ -1749,7 +1748,7 @@ _kdc_as_rep(kdc_request_t r, */ ret = _kdc_find_etype(context, config->preauth_use_strongest_session_key, TRUE, - client, b->etype.val, b->etype.len, NULL, &ckey); + r->client, b->etype.val, b->etype.len, NULL, &ckey); if (ret == 0) { /* From 7f6f4206c622af1ec1fd5cd8da126927f7105fad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Sun, 24 Jul 2011 19:46:45 -0700 Subject: [PATCH 104/119] make compile after rebase --- kdc/fast.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kdc/fast.c b/kdc/fast.c index 4a22188a8..9ecba519c 100644 --- a/kdc/fast.c +++ b/kdc/fast.c @@ -237,7 +237,7 @@ fast_parse_cookie(kdc_request_t r, const PA_DATA *pa) if (ret) goto out; - ret = krb5_decrypt_EncryptedData(crypto, crypto, + ret = krb5_decrypt_EncryptedData(r->context, crypto, KRB5_KU_H5L_COOKIE, &data.cookie, &d1); krb5_crypto_destroy(r->context, crypto); From 46f285bcc93ec99b389397eaeb98ebf3ead85290 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Sun, 24 Jul 2011 21:16:42 -0700 Subject: [PATCH 105/119] encode fast state in the fast cookie --- kadmin/init.c | 8 ++ kdc/fast.c | 218 ++++++++++++++++++++++++++++++++---------------- kdc/kerberos5.c | 2 +- kdc/krb5tgs.c | 2 +- 4 files changed, 155 insertions(+), 75 deletions(-) diff --git a/kadmin/init.c b/kadmin/init.c index 19f7328fc..f9f4703df 100644 --- a/kadmin/init.c +++ b/kadmin/init.c @@ -232,6 +232,14 @@ init(struct init_options *opt, int argc, char **argv) krb5_free_principal(context, princ); + /* Create `WELLKNONW/org.h5l.fast-cookie@WELLKNOWN:ORG.H5L' for FAST cookie */ + krb5_make_principal(context, &princ, "WELLKNOWN:ORG.H5L", + KRB5_WELLKNOWN_NAME, "org.h5l.fast-cookie", NULL); + create_random_entry(princ, 60*60, 60*60, + KRB5_KDB_REQUIRES_PRE_AUTH| + KRB5_KDB_DISALLOW_TGT_BASED); + krb5_free_principal(context, princ); + /* Create `default' */ { kadm5_principal_ent_rec ent; diff --git a/kdc/fast.c b/kdc/fast.c index 9ecba519c..8f663b0fe 100644 --- a/kdc/fast.c +++ b/kdc/fast.c @@ -35,6 +35,140 @@ #include "kdc_locl.h" +static krb5_error_code +get_fastuser_crypto(kdc_request_t r, krb5_enctype enctype, krb5_crypto *crypto) +{ + krb5_principal fast_princ; + hdb_entry_ex *fast_user = NULL; + Key *cookie_key = NULL; + krb5_error_code ret; + + *crypto = NULL; + + ret = krb5_make_principal(r->context, &fast_princ, + "WELLKNOWN:ORG.H5L", + "WELLKNOWN", "org.h5l.fast-cookie", NULL); + if (ret) + goto out; + + ret = _kdc_db_fetch(r->context, r->config, fast_princ, + HDB_F_GET_CLIENT, NULL, NULL, &fast_user); + krb5_free_principal(r->context, fast_princ); + if (ret) + goto out; + + if (enctype == KRB5_ENCTYPE_NULL) + ret = _kdc_get_preferred_key(r->context, r->config, fast_user, + "fast-cookie", &enctype, &cookie_key); + else + ret = hdb_enctype2key(r->context, &fast_user->entry, + enctype, &cookie_key); + if (ret) + goto out; + + ret = krb5_crypto_init(r->context, &cookie_key->key, 0, crypto); + if (ret) + goto out; + + out: + if (fast_user) + _kdc_free_ent(r->context, fast_user); + + return ret; +} + + +static krb5_error_code +fast_parse_cookie(kdc_request_t r, const PA_DATA *pa) +{ + krb5_crypto crypto = NULL; + krb5_error_code ret; + KDCFastCookie data; + krb5_data d1; + size_t len; + + ret = decode_KDCFastCookie(pa->padata_value.data, + pa->padata_value.length, + &data, &len); + if (ret) + return ret; + + if (len != pa->padata_value.length || strcmp("H5L1", data.version) != 0) { + free_KDCFastCookie(&data); + return KRB5KDC_ERR_POLICY; + } + + ret = get_fastuser_crypto(r, data.cookie.etype, &crypto); + if (ret) + goto out; + + ret = krb5_decrypt_EncryptedData(r->context, crypto, + KRB5_KU_H5L_COOKIE, + &data.cookie, &d1); + krb5_crypto_destroy(r->context, crypto); + if (ret) + goto out; + + ret = decode_KDCFastState(d1.data, d1.length, &r->fast, &len); + krb5_data_free(&d1); + if (ret) + goto out; + + out: + free_KDCFastCookie(&data); + + return ret; +} + +static krb5_error_code +fast_add_cookie(kdc_request_t r, METHOD_DATA *method_data) +{ + krb5_crypto crypto = NULL; + KDCFastCookie shell; + krb5_error_code ret; + krb5_data data; + size_t size; + + memset(&shell, 0, sizeof(shell)); + + ASN1_MALLOC_ENCODE(KDCFastState, data.data, data.length, + &r->fast, &size, ret); + if (ret) + return ret; + heim_assert(size == data.length, "internal asn1 encoder error"); + + ret = get_fastuser_crypto(r, KRB5_ENCTYPE_NULL, &crypto); + if (ret) + goto out; + + ret = krb5_encrypt_EncryptedData(r->context, crypto, + KRB5_KU_H5L_COOKIE, + data.data, data.length, 0, + &shell.cookie); + krb5_crypto_destroy(r->context, crypto); + if (ret) + goto out; + + free(data.data); + + shell.version = "H5L1"; + + ASN1_MALLOC_ENCODE(KDCFastCookie, data.data, data.length, + &shell, &size, ret); + free_EncryptedData(&shell.cookie); + if (ret) + return ret; + heim_assert(size == data.length, "internal asn1 encoder error"); + + ret = krb5_padata_add(r->context, method_data, + KRB5_PADATA_FX_COOKIE, + data.data, data.length); + out: + if (ret) + free(data.data); + return ret; +} + krb5_error_code _kdc_fast_mk_response(krb5_context context, krb5_crypto armor_crypto, @@ -96,6 +230,7 @@ _kdc_fast_mk_response(krb5_context context, krb5_error_code _kdc_fast_mk_error(krb5_context context, + kdc_request_t r, METHOD_DATA *error_method, krb5_crypto armor_crypto, const KDC_REQ_BODY *req_body, @@ -147,11 +282,17 @@ _kdc_fast_mk_error(krb5_context context, e_text = NULL; } - ret = krb5_padata_add(context, error_method, - KRB5_PADATA_FX_COOKIE, - NULL, 0); - if (ret) + if (r) + ret = fast_add_cookie(r, error_method); + else + ret = krb5_padata_add(context, error_method, + KRB5_PADATA_FX_COOKIE, + NULL, 0); + if (ret) { + kdc_log(r->context, r->config, 0, "failed to add fast cookie with: %d", ret); + free_METHOD_DATA(error_method); return ret; + } ret = _kdc_fast_mk_response(context, armor_crypto, error_method, NULL, NULL, @@ -165,9 +306,6 @@ _kdc_fast_mk_error(krb5_context context, e_data.data, e_data.length); if (ret) return ret; - - if (ret) - return ret; } if (error_method && error_method->len) { @@ -193,72 +331,6 @@ _kdc_fast_mk_error(krb5_context context, return ret; } -static krb5_error_code -fast_parse_cookie(kdc_request_t r, const PA_DATA *pa) -{ - krb5_principal fast_princ; - hdb_entry_ex *fast_user = NULL; - krb5_crypto crypto = NULL; - Key *cookie_key = NULL; - krb5_error_code ret; - KDCFastCookie data; - krb5_data d1; - size_t len; - - ret = decode_KDCFastCookie(pa->padata_value.data, - pa->padata_value.length, - &data, &len); - if (ret) - return ret; - - if (len != pa->padata_value.length || strcmp("H5L1", data.version) != 0) { - free_KDCFastCookie(&data); - return KRB5KDC_ERR_POLICY; - } - - ret = krb5_make_principal(r->context, &fast_princ, - "WELLKNOWN:ORG.H5L", - "WELLKNOWN", "org.h5l.fast-cookie", NULL); - if (ret) - goto out; - - ret = _kdc_db_fetch(r->context, r->config, fast_princ, - HDB_F_GET_CLIENT, NULL, NULL, &fast_user); - krb5_free_principal(r->context, fast_princ); - if (ret) - goto out; - - ret = hdb_enctype2key(r->context, &fast_user->entry, - data.cookie.etype, &cookie_key); - if (ret) - goto out; - - ret = krb5_crypto_init(r->context, &cookie_key->key, 0, &crypto); - if (ret) - goto out; - - ret = krb5_decrypt_EncryptedData(r->context, crypto, - KRB5_KU_H5L_COOKIE, - &data.cookie, &d1); - krb5_crypto_destroy(r->context, crypto); - if (ret) - goto out; - - ret = decode_KDCFastState(d1.data, d1.length, &r->fast, &len); - krb5_data_free(&d1); - if (ret) - goto out; - - out: - free_KDCFastCookie(&data); - if (fast_user) - _kdc_free_ent(r->context, fast_user); - - return ret; -} - - - krb5_error_code _kdc_fast_unwrap_request(kdc_request_t r) { diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 1372831a9..d56bfdde0 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -2158,7 +2158,7 @@ out: * In case of a non proxy error, build an error message. */ if(ret != 0 && ret != HDB_ERR_NOT_FOUND_HERE) { - ret = _kdc_fast_mk_error(context, + ret = _kdc_fast_mk_error(context, r, &error_method, r->armor_crypto, &req->req_body, diff --git a/kdc/krb5tgs.c b/kdc/krb5tgs.c index 1ad13e777..6bb903c00 100644 --- a/kdc/krb5tgs.c +++ b/kdc/krb5tgs.c @@ -2362,7 +2362,7 @@ out: kdc_log(context, config, 10, "tgs-req: sending error: %d to client", ret); - ret = _kdc_fast_mk_error(context, + ret = _kdc_fast_mk_error(context, NULL, &error_method, NULL, NULL, From f0371bb2ee8fbb8ed245910bc8f64c9d1eb7d4c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Sun, 24 Jul 2011 21:21:39 -0700 Subject: [PATCH 106/119] fast cookie expiration --- kdc/fast.c | 8 ++++++++ kdc/kdc_locl.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/kdc/fast.c b/kdc/fast.c index 8f663b0fe..372b1f836 100644 --- a/kdc/fast.c +++ b/kdc/fast.c @@ -114,6 +114,12 @@ fast_parse_cookie(kdc_request_t r, const PA_DATA *pa) if (ret) goto out; + if (r->fast.expiration < kdc_time) { + kdc_log(r->context, r->config, 0, "fast cookie expired"); + ret = KRB5KDC_ERR_POLICY; + goto out; + } + out: free_KDCFastCookie(&data); @@ -131,6 +137,8 @@ fast_add_cookie(kdc_request_t r, METHOD_DATA *method_data) memset(&shell, 0, sizeof(shell)); + r->fast.expiration = kdc_time + FAST_EXPIRATION_TIME; + ASN1_MALLOC_ENCODE(KDCFastState, data.data, data.length, &r->fast, &size, ret); if (ret) diff --git a/kdc/kdc_locl.h b/kdc/kdc_locl.h index 1b369db0f..9d3c73a32 100644 --- a/kdc/kdc_locl.h +++ b/kdc/kdc_locl.h @@ -47,6 +47,8 @@ typedef struct kdc_request_desc *kdc_request_t; #include +#define FAST_EXPIRATION_TIME (3 * 60) + struct kdc_request_desc { krb5_context context; krb5_kdc_configuration *config; From fb5e32e0f60a81922dab4603dab7c8bf152193c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Sun, 24 Jul 2011 21:23:53 -0700 Subject: [PATCH 107/119] goto out --- kdc/fast.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kdc/fast.c b/kdc/fast.c index 372b1f836..1d843f360 100644 --- a/kdc/fast.c +++ b/kdc/fast.c @@ -1,9 +1,9 @@ /* - * Copyright (c) 1997-2007 Kungliga Tekniska Högskolan + * Copyright (c) 1997-2011 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * - * Portions Copyright (c) 2010 Apple Inc. All rights reserved. + * Portions Copyright (c) 2010 - 2011 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -165,7 +165,7 @@ fast_add_cookie(kdc_request_t r, METHOD_DATA *method_data) &shell, &size, ret); free_EncryptedData(&shell.cookie); if (ret) - return ret; + goto out; heim_assert(size == data.length, "internal asn1 encoder error"); ret = krb5_padata_add(r->context, method_data, From 0941d6dbceba6c21a2d7d43700dc938f7c63f159 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Sun, 24 Jul 2011 21:29:27 -0700 Subject: [PATCH 108/119] add constant for WELLKNOWN:ORG.H5L realm --- kadmin/init.c | 2 +- kdc/fast.c | 4 ++-- lib/krb5/krb5.h | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/kadmin/init.c b/kadmin/init.c index f9f4703df..7b615448e 100644 --- a/kadmin/init.c +++ b/kadmin/init.c @@ -233,7 +233,7 @@ init(struct init_options *opt, int argc, char **argv) /* Create `WELLKNONW/org.h5l.fast-cookie@WELLKNOWN:ORG.H5L' for FAST cookie */ - krb5_make_principal(context, &princ, "WELLKNOWN:ORG.H5L", + krb5_make_principal(context, &princ, KRB5_WELLKNOWN_ORG_H5L_REALM, KRB5_WELLKNOWN_NAME, "org.h5l.fast-cookie", NULL); create_random_entry(princ, 60*60, 60*60, KRB5_KDB_REQUIRES_PRE_AUTH| diff --git a/kdc/fast.c b/kdc/fast.c index 1d843f360..38e96a0fc 100644 --- a/kdc/fast.c +++ b/kdc/fast.c @@ -46,8 +46,8 @@ get_fastuser_crypto(kdc_request_t r, krb5_enctype enctype, krb5_crypto *crypto) *crypto = NULL; ret = krb5_make_principal(r->context, &fast_princ, - "WELLKNOWN:ORG.H5L", - "WELLKNOWN", "org.h5l.fast-cookie", NULL); + KRB5_WELLKNOWN_ORG_H5L_REALM, + KRB5_WELLKNOWN_NAME, "org.h5l.fast-cookie", NULL); if (ret) goto out; diff --git a/lib/krb5/krb5.h b/lib/krb5/krb5.h index de3753a1c..5a7f4b2e1 100644 --- a/lib/krb5/krb5.h +++ b/lib/krb5/krb5.h @@ -686,6 +686,7 @@ typedef EncAPRepPart krb5_ap_rep_enc_part; #define KRB5_WELLKNOWN_NAME ("WELLKNOWN") #define KRB5_ANON_NAME ("ANONYMOUS") #define KRB5_ANON_REALM ("WELLKNOWN:ANONYMOUS") +#define KRB5_WELLKNOWN_ORG_H5L_REALM ("WELLKNOWN:ORG.H5L") #define KRB5_DIGEST_NAME ("digest") typedef enum { From 086477a9b5f34307755ff1e4b214a2cf1c628cf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Sun, 24 Jul 2011 21:31:48 -0700 Subject: [PATCH 109/119] disable operation ofn fast cookie principal --- kadmin/init.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kadmin/init.c b/kadmin/init.c index 7b615448e..ede740d4a 100644 --- a/kadmin/init.c +++ b/kadmin/init.c @@ -237,7 +237,8 @@ init(struct init_options *opt, int argc, char **argv) KRB5_WELLKNOWN_NAME, "org.h5l.fast-cookie", NULL); create_random_entry(princ, 60*60, 60*60, KRB5_KDB_REQUIRES_PRE_AUTH| - KRB5_KDB_DISALLOW_TGT_BASED); + KRB5_KDB_DISALLOW_TGT_BASED| + KRB5_KDB_DISALLOW_ALL_TIX); krb5_free_principal(context, princ); /* Create `default' */ From b6fc70019ebfe7bd48073bf2405c8a2178b3a627 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Sun, 24 Jul 2011 22:33:39 -0700 Subject: [PATCH 110/119] better error message --- lib/krb5/init_creds_pw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/krb5/init_creds_pw.c b/lib/krb5/init_creds_pw.c index f74e67671..118ba3e50 100644 --- a/lib/krb5/init_creds_pw.c +++ b/lib/krb5/init_creds_pw.c @@ -1662,7 +1662,8 @@ check_fast(krb5_context context, struct fast_state *state) { if (state->flags & KRB5_FAST_EXPECTED) { krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED, - "Expected FAST not not found"); + "Expected FAST, but no FAST " + "was in the response from the KDC"); return KRB5KRB_AP_ERR_MODIFIED; } return 0; From a48768fc26950a6305cfb86f3dfe550bb53c7f14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Sun, 24 Jul 2011 22:33:49 -0700 Subject: [PATCH 111/119] sprinkle more comments --- tests/kdc/check-fast.in | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/tests/kdc/check-fast.in b/tests/kdc/check-fast.in index 046ca120b..7f5354fc1 100644 --- a/tests/kdc/check-fast.in +++ b/tests/kdc/check-fast.in @@ -100,6 +100,10 @@ trap "kill -9 ${kdcpid}; echo signal killing kdc; exit 1;" EXIT ec=0 +# +# Check armor ticket +# + echo "Getting client initial tickets"; > messages.log ${kinit} --password-file=${objdir}/foopassword foo@$R || \ { ec=1 ; eval "${testfailed}"; } @@ -111,29 +115,42 @@ echo "Listing tickets"; > messages.log ${klist} > /dev/null || { ec=1 ; eval "${testfailed}"; } ${kdestroy} -echo "Acquire host ticket" +echo "Acquire host ticket to be used as an ARMOR ticket" ${akinit} --password-file=${objdir}/foopassword ${server}@${R} >/dev/null|| { exit 1; } -echo "Checking for FAST avail" +echo "Checking for FAST avail (in the FAST armor cache)" ${aklist} --hidden | grep fast_avail > /dev/null || { exit 1; } +# +# Client tests +# + echo "Getting client initial tickets with FAST armor ticket" ${kinit} --fast-armor-cache=${acache} \ --password-file=${objdir}/foopassword foo@$R || \ { ec=1 ; eval "${testfailed}"; } +echo "Checking for FAST avail (in the FAST acquired cache)" +${klist} --hidden | grep fast_avail > /dev/null || { exit 1; } +echo "Getting service ticket" +${kgetcred} ${server}@${R} || { exit 1; } +${kdestroy} -kinitpty=${objdir}/foopassword.rkpty -cat > ${kinitpty} < ${kinitpty} </dev/null|| { exit 1; } (${aklist} | grep ${server} > /dev/null ) || { exit 1; } From 5a31cf1a52f8a105162d2c571b34d89febee7d52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Sun, 24 Jul 2011 22:36:21 -0700 Subject: [PATCH 112/119] spelling --- kdc/kerberos5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index d56bfdde0..7770df124 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -1796,7 +1796,7 @@ _kdc_as_rep(kdc_request_t r, goto out; /* - * Selelct the best encryption type for the KDC with out regard to + * Select the best encryption type for the KDC with out regard to * the client since the client never needs to read that data. */ From 61f69ea5b10783e8e26d325ffd2f642b0c096cee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Sun, 24 Jul 2011 22:36:27 -0700 Subject: [PATCH 113/119] spelling --- kdc/kerberos5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 7770df124..67d27872f 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -1814,7 +1814,7 @@ _kdc_as_rep(kdc_request_t r, } /* - * Build repy + * Build reply */ rep.pvno = 5; From 6fefb328e3f7fbdf3e6f48eed95719c5bed6fb05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Sun, 24 Jul 2011 22:39:48 -0700 Subject: [PATCH 114/119] x --- README.fast | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 README.fast diff --git a/README.fast b/README.fast new file mode 100644 index 000000000..0cbc8bc1b --- /dev/null +++ b/README.fast @@ -0,0 +1,11 @@ + +-- in order of preference + +- client: support KRB5_PADATA_ENCRYPTED_CHALLENGE in lib/krb5/init_creds_pw.c +- client: don't support ENC-TS in FAST + +- client: plugin support for fast plugins +- kdc: plugin support for fast plugins + +- client: tgs-req fast support +- kdc: tgs-req fast support From 263157903a25f92ef0e09db8f01b3060f8de9717 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Sun, 24 Jul 2011 22:44:21 -0700 Subject: [PATCH 115/119] kcm bits --- README.fast | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.fast b/README.fast index 0cbc8bc1b..1791a309a 100644 --- a/README.fast +++ b/README.fast @@ -7,5 +7,9 @@ - client: plugin support for fast plugins - kdc: plugin support for fast plugins +- kcm: support FAST armor ticket +-- using PK-INIT anonymous +-- using host key + - client: tgs-req fast support - kdc: tgs-req fast support From 7dac559e8cc3b436e1046d4507610ab577de758f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Sun, 24 Jul 2011 22:45:55 -0700 Subject: [PATCH 116/119] kdc bits --- README.fast | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.fast b/README.fast index 1791a309a..389b6af47 100644 --- a/README.fast +++ b/README.fast @@ -5,7 +5,9 @@ - client: don't support ENC-TS in FAST - client: plugin support for fast plugins + - kdc: plugin support for fast plugins + partly done with "struct kdc_patypes" - kcm: support FAST armor ticket -- using PK-INIT anonymous From 990e1f30e7837522672239d5a7953ee8b965727e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Sun, 24 Jul 2011 22:49:40 -0700 Subject: [PATCH 117/119] add KDCFastState.expected-pa-types --- lib/asn1/krb5.asn1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/asn1/krb5.asn1 b/lib/asn1/krb5.asn1 index 9a472b655..85d15f3c0 100644 --- a/lib/asn1/krb5.asn1 +++ b/lib/asn1/krb5.asn1 @@ -839,7 +839,8 @@ KDCFastFlags ::= BIT STRING { KDCFastState ::= SEQUENCE { flags [0] KDCFastFlags, expiration [1] GeneralizedTime, - fast-state [2] METHOD-DATA + fast-state [2] METHOD-DATA, + expected-pa-types [3] SEQUENCE OF PADATA-TYPE OPTIONAL } KDCFastCookie ::= SEQUENCE { From 80f0f6fa1110e8f07922f02cca7716de5b483c11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Tue, 26 Jul 2011 20:14:53 -0700 Subject: [PATCH 118/119] plug memory leak --- lib/hdb/mkey.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/hdb/mkey.c b/lib/hdb/mkey.c index 6dcfc0294..dfda7b188 100644 --- a/lib/hdb/mkey.c +++ b/lib/hdb/mkey.c @@ -494,7 +494,6 @@ hdb_unseal_keys_kvno(krb5_context context, HDB *db, krb5_kvno kvno, size_t i, k; int exclude_dead = 0; KerberosTime now = 0; - time_t *set_time; if (kvno == 0) ret = 0; @@ -579,9 +578,6 @@ hdb_unseal_keys_kvno(krb5_context context, HDB *db, krb5_kvno kvno, * so there's no danger that we'll dump this entry and load it * again, repeatedly causing the history to grow boundelessly. */ - set_time = malloc(sizeof (*set_time)); - if (set_time == NULL) - return ENOMEM; /* Swap key sets */ ent->kvno = hist_keys->val[i].kvno; From 13341e42760355dad536044c4bc960880599f383 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Tue, 26 Jul 2011 20:18:57 -0700 Subject: [PATCH 119/119] generate sequence for HDB-Ext-KeySet and Keys --- lib/hdb/NTMakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/hdb/NTMakefile b/lib/hdb/NTMakefile index defcd3579..32b8df6e2 100644 --- a/lib/hdb/NTMakefile +++ b/lib/hdb/NTMakefile @@ -37,7 +37,7 @@ gen_files_hdb = $(OBJ)\asn1_hdb_asn1.x $(gen_files_hdb) $(OBJ)\hdb_asn1.hx $(OBJ)\hdb_asn1-priv.hx: $(BINDIR)\asn1_compile.exe hdb.asn1 cd $(OBJ) - $(BINDIR)\asn1_compile.exe --one-code-file $(SRCDIR)\hdb.asn1 hdb_asn1 + $(BINDIR)\asn1_compile.exe --sequence=HDB-Ext-KeySet --sequence=Keys --one-code-file $(SRCDIR)\hdb.asn1 hdb_asn1 cd $(SRCDIR) $(gen_files_hdb:.x=.c): $$(@R).x