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,7 +1872,11 @@ _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;
|
||||||
|
|
||||||
ret = copy_Realm(&r->client->entry.principal->realm, &rep.crealm);
|
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);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
ret = _krb5_principal2principalname(&rep.cname, r->client->entry.principal);
|
ret = _krb5_principal2principalname(&rep.cname, r->client->entry.principal);
|
||||||
@@ -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));
|
||||||
|
}
|
||||||
|
94
kdc/pkinit.c
94
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 */
|
||||||
ret = krb5_generate_random_keyblock(context, sessionetype,
|
{
|
||||||
sessionkey);
|
krb5_keyblock kdc_contribution_key;
|
||||||
if (ret) {
|
krb5_crypto reply_crypto;
|
||||||
free_PA_PK_AS_REP(&rep);
|
krb5_crypto kdccont_crypto;
|
||||||
goto out;
|
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,
|
||||||
|
&kdc_contribution_key);
|
||||||
|
if (ret) {
|
||||||
|
free_PA_PK_AS_REP(&rep);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
ret = krb5_crypto_init(context, &cp->reply_key, enctype, &reply_crypto);
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX Add PA-PKINIT-KX */
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#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