From 89eaef025376339ef25d07cdc4748920fceaa968 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 12 Jan 2010 18:16:45 +1100 Subject: s4:heimdal: import lorikeet-heimdal-201001120029 (commit a5e675fed7c5db8a7370b77ed0bfa724196aa84d) --- source4/heimdal/kdc/default_config.c | 119 ++++++++++++------------- source4/heimdal/kdc/headers.h | 3 +- source4/heimdal/kdc/kdc.h | 8 +- source4/heimdal/kdc/kdc_locl.h | 4 + source4/heimdal/kdc/kerberos5.c | 168 ++++++++++++++++------------------- source4/heimdal/kdc/krb5tgs.c | 5 +- source4/heimdal/kdc/kx509.c | 18 +++- source4/heimdal/kdc/log.c | 7 +- source4/heimdal/kdc/pkinit.c | 31 +++++-- 9 files changed, 197 insertions(+), 166 deletions(-) (limited to 'source4/heimdal/kdc') diff --git a/source4/heimdal/kdc/default_config.c b/source4/heimdal/kdc/default_config.c index bf65af3cb9..b568522fa4 100644 --- a/source4/heimdal/kdc/default_config.c +++ b/source4/heimdal/kdc/default_config.c @@ -1,9 +1,10 @@ /* * Copyright (c) 1997-2007 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). - * * All rights reserved. * + * Portions Copyright (c) 2009 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: @@ -215,7 +216,6 @@ krb5_kdc_get_config(krb5_context context, krb5_kdc_configuration **config) "kdc", "kdc_warn_pwexpire", NULL); -#ifdef PKINIT c->enable_pkinit = krb5_config_get_bool_default(context, NULL, @@ -223,74 +223,73 @@ krb5_kdc_get_config(krb5_context context, krb5_kdc_configuration **config) "kdc", "enable-pkinit", NULL); - if (c->enable_pkinit) { - const char *user_id, *anchors, *file; - char **pool_list, **revoke_list; - - user_id = - krb5_config_get_string(context, NULL, - "kdc", "pkinit_identity", NULL); - if (user_id == NULL) - krb5_errx(context, 1, "pkinit enabled but no identity"); - anchors = krb5_config_get_string(context, NULL, - "kdc", "pkinit_anchors", NULL); - if (anchors == NULL) - krb5_errx(context, 1, "pkinit enabled but no X509 anchors"); - pool_list = - krb5_config_get_strings(context, NULL, - "kdc", "pkinit_pool", NULL); + c->pkinit_kdc_identity = + krb5_config_get_string(context, NULL, + "kdc", "pkinit_identity", NULL); + c->pkinit_kdc_anchors = + krb5_config_get_string(context, NULL, + "kdc", "pkinit_anchors", NULL); + c->pkinit_kdc_cert_pool = + krb5_config_get_strings(context, NULL, + "kdc", "pkinit_pool", NULL); + c->pkinit_kdc_revoke = + krb5_config_get_strings(context, NULL, + "kdc", "pkinit_revoke", NULL); + c->pkinit_kdc_ocsp_file = + krb5_config_get_string(context, NULL, + "kdc", "pkinit_kdc_ocsp", NULL); + c->pkinit_kdc_friendly_name = + krb5_config_get_string(context, NULL, + "kdc", "pkinit_kdc_friendly_name", NULL); + c->pkinit_princ_in_cert = + krb5_config_get_bool_default(context, NULL, + c->pkinit_princ_in_cert, + "kdc", + "pkinit_principal_in_certificate", + NULL); + c->pkinit_require_binding = + krb5_config_get_bool_default(context, NULL, + c->pkinit_require_binding, + "kdc", + "pkinit_win2k_require_binding", + NULL); + c->pkinit_dh_min_bits = + krb5_config_get_int_default(context, NULL, + 0, + "kdc", "pkinit_dh_min_bits", NULL); - revoke_list = - krb5_config_get_strings(context, NULL, - "kdc", "pkinit_revoke", NULL); - file = krb5_config_get_string(context, NULL, - "kdc", "pkinit_kdc_ocsp", NULL); - if (file) { - c->pkinit_kdc_ocsp_file = strdup(file); - if (c->pkinit_kdc_ocsp_file == NULL) - krb5_errx(context, 1, "out of memory"); - } - - file = krb5_config_get_string(context, NULL, - "kdc", "pkinit_kdc_friendly_name", NULL); - if (file) { - c->pkinit_kdc_friendly_name = strdup(file); - if (c->pkinit_kdc_friendly_name == NULL) - krb5_errx(context, 1, "out of memory"); - } +#ifdef __APPLE__ + c->enable_pkinit = 1; + if (c->pkinit_kdc_identity == NULL) { + if (c->pkinit_kdc_friendly_name == NULL) + c->pkinit_kdc_friendly_name = + strdup("O=System Identity,CN=com.apple.kerberos.kdc"); + c->pkinit_kdc_identity = strdup("KEYCHAIN:"); + } + if (c->pkinit_kdc_anchors == NULL) + c->pkinit_kdc_anchors = strdup("KEYCHAIN:"); - _kdc_pk_initialize(context, c, user_id, anchors, - pool_list, revoke_list); +#endif - krb5_config_free_strings(pool_list); - krb5_config_free_strings(revoke_list); + if (c->enable_pkinit) { + if (c->pkinit_kdc_identity == NULL) + krb5_errx(context, 1, "pkinit enabled but no identity"); + + if (c->pkinit_kdc_anchors == NULL) + krb5_errx(context, 1, "pkinit enabled but no X509 anchors"); - c->pkinit_princ_in_cert = - krb5_config_get_bool_default(context, NULL, - c->pkinit_princ_in_cert, - "kdc", - "pkinit_principal_in_certificate", - NULL); + krb5_kdc_pk_initialize(context, c, + c->pkinit_kdc_identity, + c->pkinit_kdc_anchors, + c->pkinit_kdc_cert_pool, + c->pkinit_kdc_revoke); - c->pkinit_require_binding = - krb5_config_get_bool_default(context, NULL, - c->pkinit_require_binding, - "kdc", - "pkinit_win2k_require_binding", - NULL); } - - c->pkinit_dh_min_bits = - krb5_config_get_int_default(context, NULL, - 0, - "kdc", "pkinit_dh_min_bits", NULL); - -#endif - + *config = c; return 0; diff --git a/source4/heimdal/kdc/headers.h b/source4/heimdal/kdc/headers.h index b9a828852a..1eb3ddedcd 100644 --- a/source4/heimdal/kdc/headers.h +++ b/source4/heimdal/kdc/headers.h @@ -38,9 +38,8 @@ #ifndef __HEADERS_H__ #define __HEADERS_H__ -#ifdef HAVE_CONFIG_H #include -#endif + #include #include #include diff --git a/source4/heimdal/kdc/kdc.h b/source4/heimdal/kdc/kdc.h index 285a33af14..c353ca1c5f 100644 --- a/source4/heimdal/kdc/kdc.h +++ b/source4/heimdal/kdc/kdc.h @@ -74,8 +74,12 @@ typedef struct krb5_kdc_configuration { krb5_boolean enable_pkinit; krb5_boolean pkinit_princ_in_cert; - char *pkinit_kdc_ocsp_file; - char *pkinit_kdc_friendly_name; + const char *pkinit_kdc_identity; + const char *pkinit_kdc_anchors; + const char *pkinit_kdc_friendly_name; + const char *pkinit_kdc_ocsp_file; + char **pkinit_kdc_cert_pool; + char **pkinit_kdc_revoke; int pkinit_dh_min_bits; int pkinit_require_binding; int pkinit_allow_proxy_certs; diff --git a/source4/heimdal/kdc/kdc_locl.h b/source4/heimdal/kdc/kdc_locl.h index f2da03b5e6..36d694dae5 100644 --- a/source4/heimdal/kdc/kdc_locl.h +++ b/source4/heimdal/kdc/kdc_locl.h @@ -77,4 +77,8 @@ loop(krb5_context context, krb5_kdc_configuration *config); krb5_kdc_configuration * configure(krb5_context context, int argc, char **argv); +#ifdef __APPLE__ +void bonjour_announce(krb5_context, krb5_kdc_configuration *); +#endif + #endif /* __KDC_LOCL_H__ */ diff --git a/source4/heimdal/kdc/kerberos5.c b/source4/heimdal/kdc/kerberos5.c index fb88aa9f8f..87162d5f98 100644 --- a/source4/heimdal/kdc/kerberos5.c +++ b/source4/heimdal/kdc/kerberos5.c @@ -60,13 +60,13 @@ realloc_method_data(METHOD_DATA *md) } static void -set_salt_padata (METHOD_DATA *md, Salt *salt) +set_salt_padata(METHOD_DATA *md, Salt *salt) { if (salt) { - realloc_method_data(md); - md->val[md->len - 1].padata_type = salt->type; - der_copy_octet_string(&salt->salt, - &md->val[md->len - 1].padata_value); + realloc_method_data(md); + md->val[md->len - 1].padata_type = salt->type; + der_copy_octet_string(&salt->salt, + &md->val[md->len - 1].padata_value); } } @@ -127,7 +127,7 @@ is_default_salt_p(const krb5_salt *default_salt, const Key *key) krb5_error_code _kdc_find_etype(krb5_context context, const hdb_entry_ex *princ, krb5_enctype *etypes, unsigned len, - Key **ret_key, krb5_enctype *ret_etype) + Key **ret_key) { int i; krb5_error_code ret = KRB5KDC_ERR_ETYPE_NOSUPP; @@ -148,7 +148,6 @@ _kdc_find_etype(krb5_context context, const hdb_entry_ex *princ, continue; } *ret_key = key; - *ret_etype = etypes[i]; ret = 0; if (is_default_salt_p(&def_salt, key)) { krb5_free_salt (context, def_salt); @@ -287,8 +286,9 @@ _kdc_encode_reply(krb5_context context, ret = krb5_crypto_init(context, skey, etype, &crypto); if (ret) { + const char *msg; free(buf); - const char *msg = krb5_get_error_message(context, ret); + 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; @@ -902,7 +902,7 @@ _kdc_as_rep(krb5_context context, KDCOptions f = b->kdc_options; hdb_entry_ex *client = NULL, *server = NULL; HDB *clientdb; - krb5_enctype cetype, setype, sessionetype; + krb5_enctype setype, sessionetype; krb5_data e_data; EncTicketPart et; EncKDCRepPart ek; @@ -912,15 +912,20 @@ _kdc_as_rep(krb5_context context, const char *e_text = NULL; krb5_crypto crypto; Key *ckey, *skey; - EncryptionKey *reply_key; + EncryptionKey *reply_key, session_key; int flags = 0; #ifdef PKINIT pk_client_params *pkp = NULL; #endif memset(&rep, 0, sizeof(rep)); + memset(&session_key, 0, sizeof(session_key)); krb5_data_zero(&e_data); + ALLOC(rep.padata); + rep.padata->len = 0; + rep.padata->val = NULL; + if (f.canonicalize) flags |= HDB_F_CANON; @@ -1009,18 +1014,58 @@ _kdc_as_rep(krb5_context context, memset(&ek, 0, sizeof(ek)); /* - * Find the client key for reply encryption and pa-type salt, Pick - * the client key upfront before the other keys because that is - * going to affect what enctypes we are going to use in - * ETYPE-INFO{,2}. + * Select a session enctype from the list of the crypto systems + * supported enctype, is supported by the client and is one of the + * enctype of the enctype of the krbtgt. + * + * The later is used as a hint what enctype all KDC are supporting + * to make sure a newer version of KDC wont generate a session + * enctype that and older version of a KDC in the same realm can't + * decrypt. + * + * But if the KDC admin is paranoid and doesn't want to have "no + * 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. */ + { + const krb5_enctype *p; + krb5_enctype clientbest = ETYPE_NULL; + int i, j; - ret = _kdc_find_etype(context, client, b->etype.val, b->etype.len, - &ckey, &cetype); - if (ret) { - kdc_log(context, config, 0, - "Client (%s) has no support for etypes", client_name); - goto out; + p = krb5_kerberos_enctypes(context); + + sessionetype = ETYPE_NULL; + + for (i = 0; p[i] != ETYPE_NULL && sessionetype == ETYPE_NULL; i++) { + if (krb5_enctype_valid(context, p[i]) != 0) + continue; + + for (j = 0; j < b->etype.len && sessionetype == ETYPE_NULL; j++) { + Key *dummy; + /* check with client */ + if (p[i] != b->etype.val[j]) + continue; + /* save best of union of { client, crypto system } */ + if (clientbest == ETYPE_NULL) + clientbest = p[i]; + /* check with krbtgt */ + ret = hdb_enctype2key(context, &server->entry, p[i], &dummy); + if (ret) + continue; + sessionetype = p[i]; + } + } + /* if krbtgt had no shared keys with client, pick clients best */ + if (clientbest != ETYPE_NULL && sessionetype == ETYPE_NULL) { + sessionetype = clientbest; + } else if (sessionetype == ETYPE_NULL) { + kdc_log(context, config, 0, + "Client (%s) from %s has no common enctypes with KDC" + "to use for the session key", + client_name, from); + goto out; + } } /* @@ -1230,7 +1275,11 @@ _kdc_as_rep(krb5_context context, } et.flags.pre_authent = 1; - ret = krb5_enctype_to_string(context,pa_key->key.keytype, &str); + 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; @@ -1300,7 +1349,9 @@ _kdc_as_rep(krb5_context context, /* * If there is a client key, send ETYPE_INFO{,2} */ - if (ckey) { + ret = _kdc_find_etype(context, client, b->etype.val, b->etype.len, + &ckey); + if (ret == 0) { /* * RFC4120 requires: @@ -1371,63 +1422,6 @@ _kdc_as_rep(krb5_context context, if(ret) goto out; - /* - * Select a session enctype from the list of the crypto systems - * supported enctype, is supported by the client and is one of the - * enctype of the enctype of the krbtgt. - * - * The later is used as a hint what enctype all KDC are supporting - * to make sure a newer version of KDC wont generate a session - * enctype that and older version of a KDC in the same realm can't - * decrypt. - * - * But if the KDC admin is paranoid and doesn't want to have "no - * 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. - */ - { - const krb5_enctype *p; - krb5_enctype clientbest = ETYPE_NULL; - int i, j; - - p = krb5_kerberos_enctypes(context); - - sessionetype = ETYPE_NULL; - - for (i = 0; p[i] != ETYPE_NULL && sessionetype == ETYPE_NULL; i++) { - if (krb5_enctype_valid(context, p[i]) != 0) - continue; - - for (j = 0; j < b->etype.len && sessionetype == ETYPE_NULL; j++) { - Key *dummy; - /* check with client */ - if (p[i] != b->etype.val[j]) - continue; - /* save best of union of { client, crypto system } */ - if (clientbest == ETYPE_NULL) - clientbest = p[i]; - /* check with krbtgt */ - ret = hdb_enctype2key(context, &server->entry, p[i], &dummy); - if (ret) - continue; - sessionetype = p[i]; - } - } - /* if krbtgt had no shared keys with client, pick clients best */ - if (clientbest != ETYPE_NULL && sessionetype == ETYPE_NULL) { - sessionetype = clientbest; - } else if (sessionetype == ETYPE_NULL) { - kdc_log(context, config, 0, - "Client (%s) from %s has no common enctypes with KDC" - "to use for the session key", - client_name, from); - goto out; - } - } - - log_as_req(context, config, cetype, setype, b); - if(f.renew || f.validate || f.proxy || f.forwarded || f.enc_tkt_in_skey || (f.request_anonymous && !config->allow_anonymous)) { ret = KRB5KDC_ERR_BADOPTION; @@ -1622,10 +1616,6 @@ _kdc_as_rep(krb5_context context, copy_HostAddresses(et.caddr, ek.caddr); } - ALLOC(rep.padata); - rep.padata->len = 0; - rep.padata->val = NULL; - #if PKINIT if (pkp) { e_text = "Failed to build PK-INIT reply"; @@ -1642,12 +1632,13 @@ _kdc_as_rep(krb5_context context, goto out; } else #endif - if (ckey) { - reply_key = &ckey->key; + { ret = krb5_generate_random_keyblock(context, sessionetype, &et.key); if (ret) goto out; - } else { + } + + if (reply_key == NULL) { e_text = "Client have no reply key"; ret = KRB5KDC_ERR_CLIENT_NOTYET; goto out; @@ -1657,9 +1648,6 @@ _kdc_as_rep(krb5_context context, if (ret) goto out; - if (ckey) - set_salt_padata (rep.padata, ckey->salt); - /* Add signing of alias referral */ if (f.canonicalize) { PA_ClientCanonicalized canon; @@ -1765,6 +1753,8 @@ _kdc_as_rep(krb5_context context, if (ret) goto out; + log_as_req(context, config, reply_key->keytype, setype, b); + ret = _kdc_encode_reply(context, config, &rep, &et, &ek, setype, server->entry.kvno, &skey->key, client->entry.kvno, diff --git a/source4/heimdal/kdc/krb5tgs.c b/source4/heimdal/kdc/krb5tgs.c index 312be6e016..b6f9c865bb 100644 --- a/source4/heimdal/kdc/krb5tgs.c +++ b/source4/heimdal/kdc/krb5tgs.c @@ -1633,14 +1633,15 @@ server_lookup: } else { Key *skey; - ret = _kdc_find_etype(context, server, b->etype.val, b->etype.len, - &skey, &etype); + ret = _kdc_find_etype(context, server, + b->etype.val, b->etype.len, &skey); if(ret) { kdc_log(context, config, 0, "Server (%s) has no support for etypes", spn); goto out; } ekey = &skey->key; + etype = skey->key.keytype; kvno = server->entry.kvno; } diff --git a/source4/heimdal/kdc/kx509.c b/source4/heimdal/kdc/kx509.c index eb757bb578..f6f8f8a3bd 100644 --- a/source4/heimdal/kdc/kx509.c +++ b/source4/heimdal/kdc/kx509.c @@ -345,10 +345,24 @@ _kdc_do_kx509(krb5_context context, ret = krb5_principal_compare(context, sprincipal, principal); krb5_free_principal(context, principal); if (ret != TRUE) { + char *expected, *used; + + ret = krb5_unparse_name(context, sprincipal, &expected); + if (ret) + goto out; + ret = krb5_unparse_name(context, principal, &used); + if (ret) { + krb5_xfree(expected); + goto out; + } + ret = KRB5KDC_ERR_SERVER_NOMATCH; krb5_set_error_message(context, ret, - "User %s used wrong Kx509 service principal", - cname); + "User %s used wrong Kx509 service " + "principal, expected: %s, used %s", + cname, expected, used); + krb5_xfree(expected); + krb5_xfree(used); goto out; } } diff --git a/source4/heimdal/kdc/log.c b/source4/heimdal/kdc/log.c index b4161da45d..06e64df840 100644 --- a/source4/heimdal/kdc/log.c +++ b/source4/heimdal/kdc/log.c @@ -3,6 +3,8 @@ * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * + * Portions Copyright (c) 2009 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: @@ -36,13 +38,14 @@ RCSID("$Id$"); void kdc_openlog(krb5_context context, + const char *service, krb5_kdc_configuration *config) { char **s = NULL, **p; krb5_initlog(context, "kdc", &config->logf); - s = krb5_config_get_strings(context, NULL, "kdc", "logging", NULL); + s = krb5_config_get_strings(context, NULL, service, "logging", NULL); if(s == NULL) - s = krb5_config_get_strings(context, NULL, "logging", "kdc", NULL); + s = krb5_config_get_strings(context, NULL, "logging", service, NULL); if(s){ for(p = s; *p; p++) krb5_addlog_dest(context, config->logf, *p); diff --git a/source4/heimdal/kdc/pkinit.c b/source4/heimdal/kdc/pkinit.c index 7bb32eb577..099d3ebe7d 100644 --- a/source4/heimdal/kdc/pkinit.c +++ b/source4/heimdal/kdc/pkinit.c @@ -3,6 +3,8 @@ * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * + * Portions Copyright (c) 2009 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: @@ -1379,7 +1381,22 @@ _kdc_pk_mk_pa_reply(krb5_context context, } - ASN1_MALLOC_ENCODE(PA_PK_AS_REP, buf, len, &rep, &size, ret); +#define use_btmm_with_enckey 0 + if (use_btmm_with_enckey && rep.element == choice_PA_PK_AS_REP_encKeyPack) { + PA_PK_AS_REP_BTMM btmm; + heim_any any; + + any.data = rep.u.encKeyPack.data; + any.length = rep.u.encKeyPack.length; + + btmm.dhSignedData = NULL; + btmm.encKeyPack = &any; + + ASN1_MALLOC_ENCODE(PA_PK_AS_REP_BTMM, buf, len, &btmm, &size, ret); + } else { + ASN1_MALLOC_ENCODE(PA_PK_AS_REP, buf, len, &rep, &size, ret); + } + free_PA_PK_AS_REP(&rep); if (ret) { krb5_set_error_message(context, ret, @@ -1928,12 +1945,12 @@ load_mappings(krb5_context context, const char *fn) */ krb5_error_code -_kdc_pk_initialize(krb5_context context, - krb5_kdc_configuration *config, - const char *user_id, - const char *anchors, - char **pool, - char **revoke_list) +krb5_kdc_pk_initialize(krb5_context context, + krb5_kdc_configuration *config, + const char *user_id, + const char *anchors, + char **pool, + char **revoke_list) { const char *file; char *fn = NULL; -- cgit