Merge pull request #110 from cg2v/anonymous-pkinit
Anonymous pkinit improvements
This commit is contained in:
		| @@ -432,7 +432,7 @@ pa_enc_chal_validate(kdc_request_t r, const PA_DATA *pa) | |||||||
|  |  | ||||||
|     heim_assert(r->armor_crypto != NULL, "ENC-CHAL called for non FAST"); |     heim_assert(r->armor_crypto != NULL, "ENC-CHAL called for non FAST"); | ||||||
|      |      | ||||||
|     if (b->kdc_options.request_anonymous) { |     if (_kdc_is_anon_request(b)) { | ||||||
| 	ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; | 	ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; | ||||||
| 	kdc_log(r->context, r->config, 0, "ENC-CHALL doesn't support anon"); | 	kdc_log(r->context, r->config, 0, "ENC-CHALL doesn't support anon"); | ||||||
| 	return ret; | 	return ret; | ||||||
| @@ -555,7 +555,7 @@ pa_enc_ts_validate(kdc_request_t r, const PA_DATA *pa) | |||||||
|     Key *pa_key; |     Key *pa_key; | ||||||
|     char *str; |     char *str; | ||||||
| 	 | 	 | ||||||
|     if (r->req.req_body.kdc_options.request_anonymous) { |     if (_kdc_is_anon_request(&r->req.req_body)) { | ||||||
| 	ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; | 	ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; | ||||||
| 	_kdc_set_e_text(r, "ENC-TS doesn't support anon"); | 	_kdc_set_e_text(r, "ENC-TS doesn't support anon"); | ||||||
| 	goto out; | 	goto out; | ||||||
| @@ -717,9 +717,14 @@ static const struct kdc_patypes pat[] = { | |||||||
| 	KRB5_PADATA_PK_AS_REQ_WIN, "PK-INIT(win2k)", PA_ANNOUNCE, | 	KRB5_PADATA_PK_AS_REQ_WIN, "PK-INIT(win2k)", PA_ANNOUNCE, | ||||||
| 	pa_pkinit_validate | 	pa_pkinit_validate | ||||||
|     }, |     }, | ||||||
|  |     { | ||||||
|  | 	KRB5_PADATA_PKINIT_KX, "Anonymous PK-INIT", PA_ANNOUNCE, | ||||||
|  | 	NULL | ||||||
|  |     }, | ||||||
| #else | #else | ||||||
|     { KRB5_PADATA_PK_AS_REQ, "PK-INIT(ietf)", 0, NULL }, |     { KRB5_PADATA_PK_AS_REQ, "PK-INIT(ietf)", 0, NULL }, | ||||||
|     { KRB5_PADATA_PK_AS_REQ_WIN, "PK-INIT(win2k)", 0, NULL }, |     { KRB5_PADATA_PK_AS_REQ_WIN, "PK-INIT(win2k)", 0, NULL }, | ||||||
|  |     { KRB5_PADATA_PKINIT_KX, "Anonymous PK-INIT", 0, NULL }, | ||||||
| #endif | #endif | ||||||
|     { KRB5_PADATA_PA_PK_OCSP_RESPONSE , "OCSP", 0, NULL }, |     { KRB5_PADATA_PA_PK_OCSP_RESPONSE , "OCSP", 0, NULL }, | ||||||
|     {  |     {  | ||||||
| @@ -1656,12 +1661,12 @@ _kdc_as_rep(kdc_request_t r, | |||||||
|      */ |      */ | ||||||
|  |  | ||||||
|     if (_kdc_is_anonymous(context, r->client_princ)) { |     if (_kdc_is_anonymous(context, r->client_princ)) { | ||||||
| 	if (!b->kdc_options.request_anonymous) { | 	if (!_kdc_is_anon_request(b)) { | ||||||
| 	    kdc_log(context, config, 0, "Anonymous ticket w/o anonymous flag"); | 	    kdc_log(context, config, 0, "Anonymous ticket w/o anonymous flag"); | ||||||
| 	    ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; | 	    ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; | ||||||
| 	    goto out; | 	    goto out; | ||||||
| 	} | 	} | ||||||
|     } else if (b->kdc_options.request_anonymous) { |     } else if (_kdc_is_anon_request(b)) { | ||||||
| 	kdc_log(context, config, 0, | 	kdc_log(context, config, 0, | ||||||
| 		"Request for a anonymous ticket with non " | 		"Request for a anonymous ticket with non " | ||||||
| 		"anonymous client name: %s", r->client_name); | 		"anonymous client name: %s", r->client_name); | ||||||
| @@ -1810,7 +1815,7 @@ _kdc_as_rep(kdc_request_t r, | |||||||
| 	 * send requre preauth is its required or anon is requested, | 	 * send requre preauth is its required or anon is requested, | ||||||
| 	 * anon is today only allowed via preauth mechanisms. | 	 * anon is today only allowed via preauth mechanisms. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (require_preauth_p(r) || b->kdc_options.request_anonymous) { | 	if (require_preauth_p(r) || _kdc_is_anon_request(b)) { | ||||||
| 	    ret = KRB5KDC_ERR_PREAUTH_REQUIRED; | 	    ret = KRB5KDC_ERR_PREAUTH_REQUIRED; | ||||||
| 	    _kdc_set_e_text(r, "Need to use PA-ENC-TIMESTAMP/PA-PK-AS-REQ"); | 	    _kdc_set_e_text(r, "Need to use PA-ENC-TIMESTAMP/PA-PK-AS-REQ"); | ||||||
| 	    goto out; | 	    goto out; | ||||||
| @@ -1854,7 +1859,7 @@ _kdc_as_rep(kdc_request_t r, | |||||||
| 	goto out; | 	goto out; | ||||||
|  |  | ||||||
|     if(f.renew || f.validate || f.proxy || f.forwarded || f.enc_tkt_in_skey |     if(f.renew || f.validate || f.proxy || f.forwarded || f.enc_tkt_in_skey | ||||||
|        || (f.request_anonymous && !config->allow_anonymous)) { |        || (_kdc_is_anon_request(b) && !config->allow_anonymous)) { | ||||||
| 	ret = KRB5KDC_ERR_BADOPTION; | 	ret = KRB5KDC_ERR_BADOPTION; | ||||||
| 	_kdc_set_e_text(r, "Bad KDC options"); | 	_kdc_set_e_text(r, "Bad KDC options"); | ||||||
| 	goto out; | 	goto out; | ||||||
| @@ -1867,6 +1872,10 @@ _kdc_as_rep(kdc_request_t r, | |||||||
|     rep.pvno = 5; |     rep.pvno = 5; | ||||||
|     rep.msg_type = krb_as_rep; |     rep.msg_type = krb_as_rep; | ||||||
|  |  | ||||||
|  |     if (_kdc_is_anonymous(context, r->client_princ)) { | ||||||
|  | 	Realm anon_realm=KRB5_ANON_REALM; | ||||||
|  | 	ret = copy_Realm(&anon_realm, &rep.crealm); | ||||||
|  |     } else | ||||||
| 	ret = copy_Realm(&r->client->entry.principal->realm, &rep.crealm); | 	ret = copy_Realm(&r->client->entry.principal->realm, &rep.crealm); | ||||||
|     if (ret) |     if (ret) | ||||||
| 	goto out; | 	goto out; | ||||||
| @@ -1973,7 +1982,7 @@ _kdc_as_rep(kdc_request_t r, | |||||||
| 	} | 	} | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (f.request_anonymous) |     if (_kdc_is_anon_request(b)) | ||||||
| 	r->et.flags.anonymous = 1; | 	r->et.flags.anonymous = 1; | ||||||
|  |  | ||||||
|     if(b->addresses){ |     if(b->addresses){ | ||||||
| @@ -2320,3 +2329,14 @@ _kdc_tkt_add_if_relevant_ad(krb5_context context, | |||||||
|  |  | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | krb5_boolean | ||||||
|  | _kdc_is_anon_request(const KDC_REQ_BODY *b) | ||||||
|  | { | ||||||
|  | 	/* some versions of heimdal use bit 14 instead of 16 for | ||||||
|  | 	   request_anonymous, as indicated in the anonymous draft prior to | ||||||
|  | 	   version 11. Bit 14 is assigned to S4U2Proxy, but all S4U2Proxy | ||||||
|  | 	   requests will have a second ticket; don't consider those anonymous */ | ||||||
|  | 	return (b->kdc_options.request_anonymous || | ||||||
|  | 		(b->kdc_options.constrained_delegation && !b->additional_tickets)); | ||||||
|  | } | ||||||
|   | |||||||
							
								
								
									
										86
									
								
								kdc/pkinit.c
									
									
									
									
									
								
							
							
						
						
									
										86
									
								
								kdc/pkinit.c
									
									
									
									
									
								
							| @@ -573,7 +573,7 @@ _kdc_pk_rd_padata(krb5_context context, | |||||||
|  |  | ||||||
| 	type = "PK-INIT-Win2k"; | 	type = "PK-INIT-Win2k"; | ||||||
|  |  | ||||||
| 	if (req->req_body.kdc_options.request_anonymous) { | 	if (_kdc_is_anon_request(&req->req_body)) { | ||||||
| 	    ret = KRB5_KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED; | 	    ret = KRB5_KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED; | ||||||
| 	    krb5_set_error_message(context, ret, | 	    krb5_set_error_message(context, ret, | ||||||
| 				   "Anon not supported in RSA mode"); | 				   "Anon not supported in RSA mode"); | ||||||
| @@ -719,7 +719,7 @@ _kdc_pk_rd_padata(krb5_context context, | |||||||
| 	hx509_certs signer_certs; | 	hx509_certs signer_certs; | ||||||
| 	int flags = HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH; /* BTMM */ | 	int flags = HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH; /* BTMM */ | ||||||
|  |  | ||||||
| 	if (req->req_body.kdc_options.request_anonymous) | 	if (_kdc_is_anon_request(&req->req_body)) | ||||||
| 	    flags |= HX509_CMS_VS_ALLOW_ZERO_SIGNER; | 	    flags |= HX509_CMS_VS_ALLOW_ZERO_SIGNER; | ||||||
|  |  | ||||||
| 	ret = hx509_cms_verify_signed(context->hx509ctx, | 	ret = hx509_cms_verify_signed(context->hx509ctx, | ||||||
| @@ -804,7 +804,7 @@ _kdc_pk_rd_padata(krb5_context context, | |||||||
| 	    goto out; | 	    goto out; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (req->req_body.kdc_options.request_anonymous && | 	if (_kdc_is_anon_request(&req->req_body) && | ||||||
| 	    ap.clientPublicValue == NULL) { | 	    ap.clientPublicValue == NULL) { | ||||||
| 	    free_AuthPack(&ap); | 	    free_AuthPack(&ap); | ||||||
| 	    ret = KRB5_KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED; | 	    ret = KRB5_KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED; | ||||||
| @@ -1370,16 +1370,86 @@ _kdc_pk_mk_pa_reply(krb5_context context, | |||||||
| 	    if (rep.u.encKeyPack.length != size) | 	    if (rep.u.encKeyPack.length != size) | ||||||
| 		krb5_abortx(context, "Internal ASN.1 encoder error"); | 		krb5_abortx(context, "Internal ASN.1 encoder error"); | ||||||
|  |  | ||||||
| 	    /* XXX KRB-FX-CF2 */ | 	    /* generate the session key using the method from RFC6112 */ | ||||||
|  | 	    { | ||||||
|  | 		krb5_keyblock kdc_contribution_key; | ||||||
|  | 		krb5_crypto reply_crypto; | ||||||
|  | 		krb5_crypto kdccont_crypto; | ||||||
|  | 		krb5_data p1 = { strlen("PKINIT"), "PKINIT"}; | ||||||
|  | 		krb5_data p2 = { strlen("KEYEXCHANGE"), "KEYEXCHANGE"}; | ||||||
|  | 		void *kckdata; | ||||||
|  | 		size_t kcklen; | ||||||
|  | 		EncryptedData kx; | ||||||
|  | 		void *kxdata; | ||||||
|  | 		size_t kxlen; | ||||||
|  |  | ||||||
| 		ret = krb5_generate_random_keyblock(context, sessionetype, | 		ret = krb5_generate_random_keyblock(context, sessionetype, | ||||||
| 						sessionkey); | 						&kdc_contribution_key); | ||||||
| 		if (ret) { | 		if (ret) { | ||||||
| 		    free_PA_PK_AS_REP(&rep); | 		    free_PA_PK_AS_REP(&rep); | ||||||
| 		    goto out; | 		    goto out; | ||||||
| 		} | 		} | ||||||
|  | 		ret = krb5_crypto_init(context, &cp->reply_key, enctype, &reply_crypto); | ||||||
| 	    /* XXX Add PA-PKINIT-KX */ | 		if (ret) { | ||||||
|  | 		    krb5_free_keyblock_contents(context, &kdc_contribution_key); | ||||||
|  | 		    free_PA_PK_AS_REP(&rep); | ||||||
|  | 		    goto out; | ||||||
|  | 		} | ||||||
|  | 		ret = krb5_crypto_init(context, &kdc_contribution_key, sessionetype, &kdccont_crypto); | ||||||
|  | 		if (ret) { | ||||||
|  | 		    krb5_crypto_destroy(context, reply_crypto); | ||||||
|  | 		    krb5_free_keyblock_contents(context, &kdc_contribution_key); | ||||||
|  | 		    free_PA_PK_AS_REP(&rep); | ||||||
|  | 		    goto out; | ||||||
|  | 		} | ||||||
|  | 		/* KRB-FX-CF2 */ | ||||||
|  | 		ret = krb5_crypto_fx_cf2(context, kdccont_crypto, reply_crypto, | ||||||
|  | 					 &p1, &p2, sessionetype, sessionkey); | ||||||
|  | 		krb5_crypto_destroy(context, kdccont_crypto); | ||||||
|  | 		if (ret) { | ||||||
|  | 		    krb5_crypto_destroy(context, reply_crypto); | ||||||
|  | 		    krb5_free_keyblock_contents(context, &kdc_contribution_key); | ||||||
|  | 		    free_PA_PK_AS_REP(&rep); | ||||||
|  | 		    goto out; | ||||||
|  | 		} | ||||||
|  | 		ASN1_MALLOC_ENCODE(EncryptionKey, kckdata, kcklen, | ||||||
|  | 				   &kdc_contribution_key, &size, ret); | ||||||
|  | 		krb5_free_keyblock_contents(context, &kdc_contribution_key); | ||||||
|  | 		if (ret) { | ||||||
|  | 		    krb5_set_error_message(context, ret, "encoding of PKINIT-KX Key failed %d", ret); | ||||||
|  | 		    krb5_crypto_destroy(context, reply_crypto); | ||||||
|  | 		    free_PA_PK_AS_REP(&rep); | ||||||
|  | 		    goto out; | ||||||
|  | 		} | ||||||
|  | 		if (kcklen != size) | ||||||
|  | 		    krb5_abortx(context, "Internal ASN.1 encoder error"); | ||||||
|  | 		ret = krb5_encrypt_EncryptedData(context, reply_crypto, KRB5_KU_PA_PKINIT_KX, | ||||||
|  | 					kckdata, kcklen, 0, &kx); | ||||||
|  | 		krb5_crypto_destroy(context, reply_crypto); | ||||||
|  | 		free(kckdata); | ||||||
|  | 		if (ret) { | ||||||
|  | 		    free_PA_PK_AS_REP(&rep); | ||||||
|  | 		    goto out; | ||||||
|  | 		} | ||||||
|  | 		ASN1_MALLOC_ENCODE(EncryptedData, kxdata, kxlen, | ||||||
|  | 				   &kx, &size, ret); | ||||||
|  | 		free_EncryptedData(&kx); | ||||||
|  | 		if (ret) { | ||||||
|  | 		    krb5_set_error_message(context, ret, "encoding of PKINIT-KX failed %d", ret); | ||||||
|  | 		    free_PA_PK_AS_REP(&rep); | ||||||
|  | 		    goto out; | ||||||
|  | 		} | ||||||
|  | 		if (kxlen != size) | ||||||
|  | 		    krb5_abortx(context, "Internal ASN.1 encoder error"); | ||||||
|  | 		/* Add PA-PKINIT-KX */ | ||||||
|  | 		ret = krb5_padata_add(context, md, KRB5_PADATA_PKINIT_KX, kxdata, kxlen); | ||||||
|  | 		if (ret) { | ||||||
|  | 		    krb5_set_error_message(context, ret, | ||||||
|  | 					   "Failed adding PKINIT-KX %d", ret); | ||||||
|  | 		    free(buf); | ||||||
|  | 		    goto out; | ||||||
|  | 		} | ||||||
|  | 	    } | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| #define use_btmm_with_enckey 0 | #define use_btmm_with_enckey 0 | ||||||
|   | |||||||
| @@ -338,8 +338,8 @@ TicketFlags ::= BIT STRING { | |||||||
| 	hw-authent(11), | 	hw-authent(11), | ||||||
| 	transited-policy-checked(12), | 	transited-policy-checked(12), | ||||||
| 	ok-as-delegate(13), | 	ok-as-delegate(13), | ||||||
| 	anonymous(14), | 	enc-pa-rep(15), | ||||||
| 	enc-pa-rep(15) | 	anonymous(16) | ||||||
| } | } | ||||||
|  |  | ||||||
| KDCOptions ::= BIT STRING { | KDCOptions ::= BIT STRING { | ||||||
| @@ -351,9 +351,9 @@ KDCOptions ::= BIT STRING { | |||||||
| 	allow-postdate(5), | 	allow-postdate(5), | ||||||
| 	postdated(6), | 	postdated(6), | ||||||
| 	renewable(8), | 	renewable(8), | ||||||
| 	request-anonymous(14), | 	constrained-delegation(14), -- ms extension (aka cname-in-addl-tkt) | ||||||
| 	canonicalize(15), | 	canonicalize(15), | ||||||
| 	constrained-delegation(16), -- ms extension | 	request-anonymous(16), | ||||||
| 	disable-transited-check(26), | 	disable-transited-check(26), | ||||||
| 	renewable-ok(27), | 	renewable-ok(27), | ||||||
| 	enc-tkt-in-skey(28), | 	enc-tkt-in-skey(28), | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Love Hörnquist Åstrand
					Love Hörnquist Åstrand