From 14a4ddb131993fec72316f7e8e371638749e6f1f Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Tue, 3 Jul 2007 08:00:08 +0000 Subject: [PATCH] r23678: Update to current lorikeet-heimdal (-r 767), which should fix the panics on hosts without /dev/random. Andrew Bartlett --- source/heimdal/kdc/default_config.c | 19 +- source/heimdal/kdc/digest.c | 140 +++--- source/heimdal/kdc/kdc-protos.h | 7 +- source/heimdal/kdc/kdc.h | 8 +- source/heimdal/kdc/krb5tgs.c | 32 +- source/heimdal/kdc/misc.c | 11 +- source/heimdal/kdc/pkinit.c | 16 +- source/heimdal/lib/asn1/k5.asn1 | 3 +- source/heimdal/lib/asn1/lex.c | 33 +- source/heimdal/lib/asn1/pkinit.asn1 | 4 +- source/heimdal/lib/com_err/lex.c | 33 +- source/heimdal/lib/gssapi/krb5/acquire_cred.c | 4 +- source/heimdal/lib/gssapi/krb5/display_name.c | 5 +- source/heimdal/lib/gssapi/krb5/prf.c | 3 +- source/heimdal/lib/gssapi/krb5/release_name.c | 5 +- source/heimdal/lib/gssapi/mech/context.c | 6 +- .../lib/gssapi/mech/gss_accept_sec_context.c | 10 +- .../lib/gssapi/mech/gss_display_name.c | 7 +- .../lib/gssapi/mech/gss_display_status.c | 8 +- .../lib/gssapi/mech/gss_duplicate_name.c | 39 +- .../lib/gssapi/mech/gss_inquire_context.c | 11 +- .../gssapi/mech/gss_inquire_cred_by_mech.c | 14 +- source/heimdal/lib/gssapi/mech/gss_krb5.c | 4 +- .../lib/gssapi/mech/gss_set_cred_option.c | 6 +- .../lib/gssapi/spnego/accept_sec_context.c | 139 +++--- source/heimdal/lib/hcrypto/pkcs12.c | 7 +- source/heimdal/lib/hcrypto/rand-egd.c | 4 +- source/heimdal/lib/hcrypto/rand-fortuna.c | 38 +- source/heimdal/lib/hcrypto/rand-timer.c | 206 +++++++++ source/heimdal/lib/hcrypto/rand.c | 8 +- source/heimdal/lib/hcrypto/randi.h | 5 +- source/heimdal/lib/hcrypto/rsa-imath.c | 3 +- source/heimdal/lib/hdb/ext.c | 12 +- source/heimdal/lib/hx509/cert.c | 186 ++++++-- source/heimdal/lib/hx509/cms.c | 79 ++-- source/heimdal/lib/hx509/crypto.c | 66 ++- source/heimdal/lib/hx509/file.c | 240 ++++++++++ source/heimdal/lib/hx509/hx509-private.h | 42 +- source/heimdal/lib/hx509/hx509-protos.h | 57 ++- source/heimdal/lib/hx509/hx509.h | 19 +- source/heimdal/lib/hx509/hx_locl.h | 6 +- source/heimdal/lib/hx509/keyset.c | 23 +- source/heimdal/lib/hx509/ks_file.c | 424 ++++++------------ source/heimdal/lib/hx509/ks_keychain.c | 127 ++++-- source/heimdal/lib/hx509/ks_p11.c | 15 +- source/heimdal/lib/hx509/ks_p12.c | 16 +- source/heimdal/lib/hx509/req.c | 110 ++++- source/heimdal/lib/hx509/revoke.c | 19 +- source/heimdal/lib/krb5/crypto.c | 7 +- source/heimdal/lib/krb5/get_cred.c | 89 +++- source/heimdal/lib/krb5/init_creds_pw.c | 28 +- source/heimdal/lib/krb5/krb5-private.h | 8 + source/heimdal/lib/krb5/krb5-protos.h | 53 ++- source/heimdal/lib/krb5/krb5.h | 14 +- source/heimdal/lib/krb5/krb5_err.et | 8 +- source/heimdal/lib/krb5/krbhst.c | 6 +- source/heimdal/lib/krb5/misc.c | 3 +- source/heimdal/lib/krb5/pac.c | 4 +- source/heimdal/lib/krb5/pkinit.c | 207 ++++----- source/heimdal/lib/krb5/plugin.c | 3 +- source/heimdal/lib/krb5/principal.c | 49 +- source/heimdal/lib/krb5/rd_error.c | 4 +- source/heimdal/lib/krb5/send_to_kdc.c | 177 +++++++- source/heimdal/lib/ntlm/heimntlm-protos.h | 8 + source/heimdal/lib/ntlm/ntlm.c | 111 ++++- source/heimdal/lib/roken/roken_gethostby.c | 4 +- source/heimdal_build/config.mk | 1 + 67 files changed, 2173 insertions(+), 890 deletions(-) create mode 100644 source/heimdal/lib/hcrypto/rand-timer.c diff --git a/source/heimdal/kdc/default_config.c b/source/heimdal/kdc/default_config.c index c28bd424ead..e06366f214b 100644 --- a/source/heimdal/kdc/default_config.c +++ b/source/heimdal/kdc/default_config.c @@ -36,10 +36,9 @@ #include #include -RCSID("$Id: default_config.c 20532 2007-04-23 07:46:57Z lha $"); +RCSID("$Id: default_config.c 21296 2007-06-25 14:49:11Z lha $"); - -int +krb5_error_code krb5_kdc_get_config(krb5_context context, krb5_kdc_configuration **config) { krb5_kdc_configuration *c; @@ -62,7 +61,8 @@ krb5_kdc_get_config(krb5_context context, krb5_kdc_configuration **config) c->enable_524 = FALSE; c->enable_v4_cross_realm = FALSE; c->enable_pkinit = FALSE; - c->enable_pkinit_princ_in_cert = TRUE; + c->pkinit_princ_in_cert = TRUE; + c->pkinit_require_binding = TRUE; c->db = NULL; c->num_db = 0; c->logf = NULL; @@ -257,12 +257,19 @@ krb5_kdc_get_config(krb5_context context, krb5_kdc_configuration **config) krb5_config_free_strings(pool_list); krb5_config_free_strings(revoke_list); - c->enable_pkinit_princ_in_cert = + c->pkinit_princ_in_cert = krb5_config_get_bool_default(context, NULL, - c->enable_pkinit_princ_in_cert, + 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 = diff --git a/source/heimdal/kdc/digest.c b/source/heimdal/kdc/digest.c index 811ab639f1c..801449fe5e5 100644 --- a/source/heimdal/kdc/digest.c +++ b/source/heimdal/kdc/digest.c @@ -34,7 +34,7 @@ #include "kdc_locl.h" #include -RCSID("$Id: digest.c 20877 2007-06-04 04:07:26Z lha $"); +RCSID("$Id: digest.c 21241 2007-06-20 11:30:19Z lha $"); #define MS_CHAP_V2 0x20 #define CHAP_MD5 0x10 @@ -156,6 +156,44 @@ static const unsigned char ms_rfc3079_magic1[27] = { 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 }; +/* + * + */ + +static krb5_error_code +get_password_entry(krb5_context context, + krb5_kdc_configuration *config, + const char *username, + char **password) +{ + krb5_principal clientprincipal; + krb5_error_code ret; + hdb_entry_ex *user; + HDB *db; + + /* get username */ + ret = krb5_parse_name(context, username, &clientprincipal); + if (ret) + return ret; + + ret = _kdc_db_fetch(context, config, clientprincipal, + HDB_F_GET_CLIENT, &db, &user); + krb5_free_principal(context, clientprincipal); + if (ret) + return ret; + + ret = hdb_entry_get_password(context, db, &user->entry, password); + if (ret || password == NULL) { + if (ret == 0) { + ret = EINVAL; + krb5_set_error_string(context, "password missing"); + } + memset(user, 0, sizeof(*user)); + } + _kdc_free_ent (context, user); + return ret; +} + /* * */ @@ -461,9 +499,6 @@ _kdc_do_digest(krb5_context context, break; } case choice_DigestReqInner_digestRequest: { - krb5_principal clientprincipal; - HDB *db; - sp = krb5_storage_emem(); if (sp == NULL) { ret = ENOMEM; @@ -571,29 +606,6 @@ _kdc_do_digest(krb5_context context, } } - /* get username */ - ret = krb5_parse_name(context, - ireq.u.digestRequest.username, - &clientprincipal); - if (ret) - goto out; - - ret = _kdc_db_fetch(context, config, clientprincipal, - HDB_F_GET_CLIENT, &db, &user); - - krb5_free_principal(context, clientprincipal); - if (ret) - goto out; - - ret = hdb_entry_get_password(context, db, &user->entry, &password); - if (ret || password == NULL) { - if (ret == 0) { - ret = EINVAL; - krb5_set_error_string(context, "password missing"); - } - goto out; - } - if (strcasecmp(ireq.u.digestRequest.type, "CHAP") == 0) { MD5_CTX ctx; unsigned char md[MD5_DIGEST_LENGTH]; @@ -618,6 +630,12 @@ _kdc_do_digest(krb5_context context, goto out; } + ret = get_password_entry(context, config, + ireq.u.digestRequest.username, + &password); + if (ret) + goto out; + MD5_Init(&ctx); MD5_Update(&ctx, &id, 1); MD5_Update(&ctx, password, strlen(password)); @@ -664,6 +682,12 @@ _kdc_do_digest(krb5_context context, if (ireq.u.digestRequest.realm == NULL) goto out; + ret = get_password_entry(context, config, + ireq.u.digestRequest.username, + &password); + if (ret) + goto failed; + MD5_Init(&ctx); MD5_Update(&ctx, ireq.u.digestRequest.username, strlen(ireq.u.digestRequest.username)); @@ -692,7 +716,7 @@ _kdc_do_digest(krb5_context context, if (A1 == NULL) { krb5_set_error_string(context, "out of memory"); ret = ENOMEM; - goto out; + goto failed; } MD5_Init(&ctx); @@ -712,7 +736,7 @@ _kdc_do_digest(krb5_context context, krb5_set_error_string(context, "out of memory"); ret = ENOMEM; free(A1); - goto out; + goto failed; } MD5_Init(&ctx); @@ -758,6 +782,7 @@ _kdc_do_digest(krb5_context context, } else if (strcasecmp(ireq.u.digestRequest.type, "MS-CHAP-V2") == 0) { unsigned char md[SHA_DIGEST_LENGTH], challange[SHA_DIGEST_LENGTH]; + krb5_principal clientprincipal = NULL; char *mdx; const char *username; struct ntlm_buf answer; @@ -766,20 +791,20 @@ _kdc_do_digest(krb5_context context, if ((config->digests_allowed & MS_CHAP_V2) == 0) { kdc_log(context, config, 0, "MS-CHAP-V2 not allowed"); - goto out; + goto failed; } if (ireq.u.digestRequest.clientNonce == NULL) { krb5_set_error_string(context, "MS-CHAP-V2 clientNonce missing"); ret = EINVAL; - goto out; + goto failed; } if (serverNonce.length != 16) { krb5_set_error_string(context, "MS-CHAP-V2 serverNonce wrong length"); ret = EINVAL; - goto out; + goto failed; } /* strip of the domain component */ @@ -821,7 +846,7 @@ _kdc_do_digest(krb5_context context, /* NtPasswordHash */ ret = krb5_parse_name(context, username, &clientprincipal); if (ret) - goto out; + goto failed; ret = _kdc_db_fetch(context, config, clientprincipal, HDB_F_GET_CLIENT, NULL, &user); @@ -830,7 +855,7 @@ _kdc_do_digest(krb5_context context, krb5_set_error_string(context, "MS-CHAP-V2 user %s not in database", username); - goto out; + goto failed; } ret = hdb_enctype2key(context, &user->entry, @@ -839,7 +864,7 @@ _kdc_do_digest(krb5_context context, krb5_set_error_string(context, "MS-CHAP-V2 missing arcfour key %s", username); - goto out; + goto failed; } /* ChallengeResponse */ @@ -848,7 +873,7 @@ _kdc_do_digest(krb5_context context, challange, &answer); if (ret) { krb5_set_error_string(context, "NTLM missing arcfour key"); - goto out; + goto failed; } hex_encode(answer.data, answer.length, &mdx); @@ -861,15 +886,15 @@ _kdc_do_digest(krb5_context context, r.element = choice_DigestRepInner_response; ret = strcasecmp(mdx, ireq.u.digestRequest.responseData); - free(mdx); if (ret == 0) { r.u.response.success = TRUE; } else { kdc_log(context, config, 0, - "MS-CHAP-V2 reply mismatch for %s", + "MS-CHAP-V2 hash mismatch for %s", ireq.u.digestRequest.username); r.u.response.success = FALSE; } + free(mdx); if (r.u.response.success) { unsigned char hashhash[MD4_DIGEST_LENGTH]; @@ -958,7 +983,7 @@ _kdc_do_digest(krb5_context context, if ((config->digests_allowed & (NTLM_V1|NTLM_V1_SESSION|NTLM_V2)) == 0) { kdc_log(context, config, 0, "NTLM not allowed"); - goto out; + goto failed; } r.element = choice_DigestRepInner_ntlmInitReply; @@ -967,14 +992,14 @@ _kdc_do_digest(krb5_context context, if ((ireq.u.ntlmInit.flags & NTLM_NEG_UNICODE) == 0) { kdc_log(context, config, 0, "NTLM client have no unicode"); - goto out; + goto failed; } if (ireq.u.ntlmInit.flags & NTLM_NEG_NTLM) r.u.ntlmInitReply.flags |= NTLM_NEG_NTLM; else { kdc_log(context, config, 0, "NTLM client doesn't support NTLM"); - goto out; + goto failed; } r.u.ntlmInitReply.flags |= @@ -1095,7 +1120,7 @@ _kdc_do_digest(krb5_context context, ireq.u.ntlmRequest.username, &clientprincipal); if (ret) - goto out; + goto failed; ret = _kdc_db_fetch(context, config, clientprincipal, HDB_F_GET_CLIENT, NULL, &user); @@ -1103,20 +1128,23 @@ _kdc_do_digest(krb5_context context, if (ret) { krb5_set_error_string(context, "NTLM user %s not in database", ireq.u.ntlmRequest.username); - goto out; + goto failed; } ret = get_digest_key(context, config, server, &crypto); if (ret) - goto out; + goto failed; ret = krb5_decrypt(context, crypto, KRB5_KU_DIGEST_OPAQUE, ireq.u.ntlmRequest.opaque.data, ireq.u.ntlmRequest.opaque.length, &buf); krb5_crypto_destroy(context, crypto); crypto = NULL; - if (ret) - goto out; + if (ret) { + kdc_log(context, config, 0, + "Failed to decrypt nonce from %s", from); + goto failed; + } sp = krb5_storage_from_data(&buf); if (sp == NULL) { @@ -1185,7 +1213,7 @@ _kdc_do_digest(krb5_context context, free(targetname); if (ret) { krb5_set_error_string(context, "NTLM v2 verify failed"); - goto out; + goto failed; } /* XXX verify infotarget matches client (checksum ?) */ @@ -1205,14 +1233,14 @@ _kdc_do_digest(krb5_context context, if ((config->digests_allowed & NTLM_V1_SESSION) == 0) { kdc_log(context, config, 0, "NTLM v1-session not allowed"); ret = EINVAL; - goto out; + goto failed; } if (ireq.u.ntlmRequest.lm.length != 24) { krb5_set_error_string(context, "LM hash have wrong length " "for NTLM session key"); ret = EINVAL; - goto out; + goto failed; } MD5_Init(&md5ctx); @@ -1223,7 +1251,7 @@ _kdc_do_digest(krb5_context context, } else { if ((config->digests_allowed & NTLM_V1) == 0) { kdc_log(context, config, 0, "NTLM v1 not allowed"); - goto out; + goto failed; } } @@ -1232,7 +1260,7 @@ _kdc_do_digest(krb5_context context, challange, &answer); if (ret) { krb5_set_error_string(context, "NTLM missing arcfour key"); - goto out; + goto failed; } if (ireq.u.ntlmRequest.ntlm.length != answer.length || @@ -1241,7 +1269,7 @@ _kdc_do_digest(krb5_context context, free(answer.data); ret = EINVAL; krb5_set_error_string(context, "NTLM hash mismatch"); - goto out; + goto failed; } free(answer.data); @@ -1265,7 +1293,7 @@ _kdc_do_digest(krb5_context context, "NTLM client failed to neg key " "exchange but still sent key"); ret = EINVAL; - goto out; + goto failed; } len = ireq.u.ntlmRequest.sessionkey->length; @@ -1273,7 +1301,7 @@ _kdc_do_digest(krb5_context context, krb5_set_error_string(context, "NTLM master key wrong length: %lu", (unsigned long)len); - goto out; + goto failed; } RC4_set_key(&rc4, sizeof(sessionkey), sessionkey); @@ -1301,12 +1329,12 @@ _kdc_do_digest(krb5_context context, r.u.ntlmResponse.success = 1; kdc_log(context, config, 0, "NTLM version %d successful for %s", version, ireq.u.ntlmRequest.username); - break; } default: + failed: r.element = choice_DigestRepInner_error; - r.u.error.reason = strdup("unknown operation"); + r.u.error.reason = strdup("unknown/failed operation"); if (r.u.error.reason == NULL) { krb5_set_error_string(context, "out of memory"); ret = ENOMEM; diff --git a/source/heimdal/kdc/kdc-protos.h b/source/heimdal/kdc/kdc-protos.h index f7df365eb2a..15e8c29f4cb 100644 --- a/source/heimdal/kdc/kdc-protos.h +++ b/source/heimdal/kdc/kdc-protos.h @@ -37,7 +37,7 @@ kdc_openlog ( krb5_context /*context*/, krb5_kdc_configuration */*config*/); -int +krb5_error_code krb5_kdc_get_config ( krb5_context /*context*/, krb5_kdc_configuration **/*config*/); @@ -74,6 +74,11 @@ krb5_kdc_save_request ( const krb5_data */*reply*/, const struct sockaddr */*sa*/); +krb5_error_code +krb5_kdc_set_dbinfo ( + krb5_context /*context*/, + struct krb5_kdc_configuration */*c*/); + void krb5_kdc_update_time (struct timeval */*tv*/); diff --git a/source/heimdal/kdc/kdc.h b/source/heimdal/kdc/kdc.h index eb24b4ee970..6c129f38f52 100644 --- a/source/heimdal/kdc/kdc.h +++ b/source/heimdal/kdc/kdc.h @@ -35,7 +35,7 @@ */ /* - * $Id: kdc.h 19907 2007-01-14 23:10:24Z lha $ + * $Id: kdc.h 21287 2007-06-25 14:09:03Z lha $ */ #ifndef __KDC_H__ @@ -73,13 +73,13 @@ typedef struct krb5_kdc_configuration { krb5_boolean enable_524; krb5_boolean enable_pkinit; - krb5_boolean enable_pkinit_princ_in_cert; + krb5_boolean pkinit_princ_in_cert; char *pkinit_kdc_ocsp_file; + int pkinit_dh_min_bits; + int pkinit_require_binding; krb5_log_facility *logf; - int pkinit_dh_min_bits; - int enable_digest; int digests_allowed; diff --git a/source/heimdal/kdc/krb5tgs.c b/source/heimdal/kdc/krb5tgs.c index 02cd92de2e3..4d6be60f68f 100644 --- a/source/heimdal/kdc/krb5tgs.c +++ b/source/heimdal/kdc/krb5tgs.c @@ -33,7 +33,7 @@ #include "kdc_locl.h" -RCSID("$Id: krb5tgs.c 21041 2007-06-10 06:21:12Z lha $"); +RCSID("$Id: krb5tgs.c 21262 2007-06-21 15:18:37Z lha $"); /* * return the realm of a krbtgt-ticket or NULL @@ -475,12 +475,14 @@ check_tgs_flags(krb5_context context, et->endtime = min(*et->renew_till, et->endtime); } +#if 0 /* checks for excess flags */ if(f.request_anonymous && !config->allow_anonymous){ kdc_log(context, config, 0, "Request for anonymous ticket"); return KRB5KDC_ERR_BADOPTION; } +#endif return 0; } @@ -731,10 +733,12 @@ tgs_make_reply(krb5_context context, &rep.ticket.realm); _krb5_principal2principalname(&rep.ticket.sname, server->entry.principal); copy_Realm(&tgt_name->realm, &rep.crealm); +/* if (f.request_anonymous) _kdc_make_anonymous_principalname (&rep.cname); - else - copy_PrincipalName(&tgt_name->name, &rep.cname); + else */ + + copy_PrincipalName(&tgt_name->name, &rep.cname); rep.ticket.tkt_vno = 5; ek.caddr = et.caddr; @@ -1707,24 +1711,20 @@ server_lookup: goto out; } - /* check PAC if there is one */ - { + /* check PAC if not cross realm and if there is one */ + if (!cross_realm) { Key *tkey; - krb5_keyblock *tgtkey = NULL; - if (!cross_realm) { - ret = hdb_enctype2key(context, &krbtgt->entry, - krbtgt_etype, &tkey); - if(ret) { - kdc_log(context, config, 0, - "Failed to find key for krbtgt PAC check"); - goto out; - } - tgtkey = &tkey->key; + ret = hdb_enctype2key(context, &krbtgt->entry, + krbtgt_etype, &tkey); + if(ret) { + kdc_log(context, config, 0, + "Failed to find key for krbtgt PAC check"); + goto out; } ret = check_PAC(context, config, client_principal, - client, server, ekey, tgtkey, + client, server, ekey, &tkey->key, tgt, &rspac, &require_signedpath); if (ret) { kdc_log(context, config, 0, diff --git a/source/heimdal/kdc/misc.c b/source/heimdal/kdc/misc.c index ebf28735996..072df440429 100644 --- a/source/heimdal/kdc/misc.c +++ b/source/heimdal/kdc/misc.c @@ -33,7 +33,7 @@ #include "kdc_locl.h" -RCSID("$Id: misc.c 17951 2006-08-28 14:41:49Z lha $"); +RCSID("$Id: misc.c 21106 2007-06-18 10:18:11Z lha $"); struct timeval _kdc_now; @@ -46,12 +46,14 @@ _kdc_db_fetch(krb5_context context, hdb_entry_ex **h) { hdb_entry_ex *ent; - krb5_error_code ret = HDB_ERR_NOENTRY; + krb5_error_code ret; int i; ent = calloc (1, sizeof (*ent)); - if (ent == NULL) + if (ent == NULL) { + krb5_set_error_string(context, "out of memory"); return ENOMEM; + } for(i = 0; i < config->num_db; i++) { ret = config->db[i]->hdb_open(context, config->db[i], O_RDONLY, 0); @@ -74,7 +76,8 @@ _kdc_db_fetch(krb5_context context, } } free(ent); - return ret; + krb5_set_error_string(context, "no such entry found in hdb"); + return HDB_ERR_NOENTRY; } void diff --git a/source/heimdal/kdc/pkinit.c b/source/heimdal/kdc/pkinit.c index bf62f879db7..ead961022d1 100755 --- a/source/heimdal/kdc/pkinit.c +++ b/source/heimdal/kdc/pkinit.c @@ -33,7 +33,7 @@ #include "kdc_locl.h" -RCSID("$Id: pkinit.c 21039 2007-06-10 06:20:31Z lha $"); +RCSID("$Id: pkinit.c 21290 2007-06-25 14:13:23Z lha $"); #ifdef PKINIT @@ -380,6 +380,7 @@ _kdc_pk_rd_padata(krb5_context context, *ret_params = NULL; if (!config->enable_pkinit) { + kdc_log(context, config, 0, "PK-INIT request but PK-INIT not enabled"); krb5_clear_error_string(context); return 0; } @@ -676,6 +677,7 @@ BN_to_integer(krb5_context context, BIGNUM *bn, heim_integer *integer) static krb5_error_code pk_mk_pa_reply_enckey(krb5_context context, + krb5_kdc_configuration *config, pk_client_params *client_params, const KDC_REQ *req, const krb5_data *req_buffer, @@ -700,8 +702,11 @@ pk_mk_pa_reply_enckey(krb5_context context, switch (client_params->type) { case PKINIT_COMPAT_WIN2K: { int i = 0; - if (_kdc_find_padata(req, &i, KRB5_PADATA_PK_AS_09_BINDING) == NULL) + if (_kdc_find_padata(req, &i, KRB5_PADATA_PK_AS_09_BINDING) == NULL + && config->pkinit_require_binding == 0) + { do_win2k = 1; + } break; } case PKINIT_COMPAT_27: @@ -1015,6 +1020,7 @@ _kdc_pk_mk_pa_reply(krb5_context context, goto out; } ret = pk_mk_pa_reply_enckey(context, + config, client_params, req, req_buffer, @@ -1110,6 +1116,7 @@ _kdc_pk_mk_pa_reply(krb5_context context, goto out; } ret = pk_mk_pa_reply_enckey(context, + config, client_params, req, req_buffer, @@ -1384,7 +1391,7 @@ _kdc_pk_check_client(krb5_context context, "Trying to authorize PK-INIT subject DN %s", *subject_name); - if (config->enable_pkinit_princ_in_cert) { + if (config->pkinit_princ_in_cert) { ret = match_rfc_san(context, config, client_params->cert, client->entry.principal); @@ -1508,7 +1515,8 @@ _kdc_add_inital_verified_cas(krb5_context context, krb5_abortx(context, "internal asn.1 encoder error"); ret = _kdc_tkt_add_if_relevant_ad(context, tkt, - ad_initial_verified_cas, &data); + KRB5_AUTHDATA_INITIAL_VERIFIED_CAS, + &data); krb5_data_free(&data); return ret; } diff --git a/source/heimdal/lib/asn1/k5.asn1 b/source/heimdal/lib/asn1/k5.asn1 index 0c7021f87f4..14e9793fdc0 100644 --- a/source/heimdal/lib/asn1/k5.asn1 +++ b/source/heimdal/lib/asn1/k5.asn1 @@ -1,4 +1,4 @@ --- $Id: k5.asn1 21004 2007-06-08 01:53:10Z lha $ +-- $Id: k5.asn1 21092 2007-06-15 19:47:46Z lha $ KERBEROS5 DEFINITIONS ::= BEGIN @@ -88,6 +88,7 @@ AUTHDATA-TYPE ::= INTEGER { KRB5-AUTHDATA-MANDATORY-TICKET-EXTENSIONS(6), KRB5-AUTHDATA-IN-TICKET-EXTENSIONS(7), KRB5-AUTHDATA-MANDATORY-FOR-KDC(8), + KRB5-AUTHDATA-INITIAL-VERIFIED-CAS(9), KRB5-AUTHDATA-OSF-DCE(64), KRB5-AUTHDATA-SESAME(65), KRB5-AUTHDATA-OSF-DCE-PKI-CERTID(66), diff --git a/source/heimdal/lib/asn1/lex.c b/source/heimdal/lib/asn1/lex.c index fe488eb904e..d628e4696f5 100644 --- a/source/heimdal/lib/asn1/lex.c +++ b/source/heimdal/lib/asn1/lex.c @@ -1,6 +1,5 @@ -#include "config.h" -#line 3 "lex.yy.c" +#line 3 "lex.c" #define YY_INT_ALIGNED short int @@ -343,6 +342,9 @@ FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; typedef int yy_state_type; extern int yylineno; + +int yylineno = 1; + extern char *yytext; #define yytext_ptr yytext @@ -824,7 +826,7 @@ char *yytext; * SUCH DAMAGE. */ -/* $Id: lex.l,v 1.31 2006/10/21 11:57:22 lha Exp $ */ +/* $Id: lex.l 18738 2006-10-21 11:57:22Z lha $ */ #ifdef HAVE_CONFIG_H #include @@ -849,7 +851,7 @@ static unsigned lineno = 1; static void unterminated(const char *, unsigned); /* This is for broken old lexes (solaris 10 and hpux) */ -#line 852 "lex.yy.c" +#line 855 "lex.c" #define INITIAL 0 @@ -1004,7 +1006,7 @@ YY_DECL #line 68 "lex.l" -#line 1007 "lex.yy.c" +#line 1010 "lex.c" if ( !(yy_init) ) { @@ -1673,7 +1675,7 @@ YY_RULE_SETUP #line 274 "lex.l" ECHO; YY_BREAK -#line 1676 "lex.yy.c" +#line 1679 "lex.c" case YY_STATE_EOF(INITIAL): yyterminate(); @@ -2483,6 +2485,15 @@ static void yy_fatal_error (yyconst char* msg ) /* Accessor methods (get/set functions) to struct members. */ +/** Get the current line number. + * + */ +int yyget_lineno (void) +{ + + return yylineno; +} + /** Get the input stream. * */ @@ -2516,6 +2527,16 @@ char *yyget_text (void) return yytext; } +/** Set the current line number. + * @param line_number + * + */ +void yyset_lineno (int line_number ) +{ + + yylineno = line_number; +} + /** Set the input stream. This does not discard the current * input buffer. * @param in_str A readable stream. diff --git a/source/heimdal/lib/asn1/pkinit.asn1 b/source/heimdal/lib/asn1/pkinit.asn1 index e89a7217af5..1bfc11ad740 100644 --- a/source/heimdal/lib/asn1/pkinit.asn1 +++ b/source/heimdal/lib/asn1/pkinit.asn1 @@ -34,8 +34,6 @@ MS-UPN-SAN ::= UTF8String pa-pk-as-req INTEGER ::= 16 pa-pk-as-rep INTEGER ::= 17 -ad-initial-verified-cas INTEGER ::= 9 - td-trusted-certifiers INTEGER ::= 104 td-invalid-certificates INTEGER ::= 105 td-dh-parameters INTEGER ::= 109 @@ -160,7 +158,7 @@ KDCDHKeyInfo-Win2k ::= SEQUENCE { ReplyKeyPack-Win2k ::= SEQUENCE { replyKey [0] EncryptionKey, - nonce [1] INTEGER (0..4294967295), + nonce [1] INTEGER (-2147483648..2147483647), ... } diff --git a/source/heimdal/lib/com_err/lex.c b/source/heimdal/lib/com_err/lex.c index 83f1f309a42..c5af2ead5c4 100644 --- a/source/heimdal/lib/com_err/lex.c +++ b/source/heimdal/lib/com_err/lex.c @@ -1,6 +1,5 @@ -#include "config.h" -#line 3 "lex.yy.c" +#line 3 "lex.c" #define YY_INT_ALIGNED short int @@ -343,6 +342,9 @@ FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; typedef int yy_state_type; extern int yylineno; + +int yylineno = 1; + extern char *yytext; #define yytext_ptr yytext @@ -521,7 +523,7 @@ char *yytext; #include "parse.h" #include "lex.h" -RCSID("$Id: lex.l,v 1.8 2005/05/16 08:52:54 lha Exp $"); +RCSID("$Id: lex.l 15143 2005-05-16 08:52:54Z lha $"); static unsigned lineno = 1; static int getstring(void); @@ -530,7 +532,7 @@ static int getstring(void); #undef ECHO -#line 533 "lex.yy.c" +#line 536 "lex.c" #define INITIAL 0 @@ -685,7 +687,7 @@ YY_DECL #line 59 "lex.l" -#line 688 "lex.yy.c" +#line 691 "lex.c" if ( !(yy_init) ) { @@ -849,7 +851,7 @@ YY_RULE_SETUP #line 75 "lex.l" ECHO; YY_BREAK -#line 852 "lex.yy.c" +#line 855 "lex.c" case YY_STATE_EOF(INITIAL): yyterminate(); @@ -1659,6 +1661,15 @@ static void yy_fatal_error (yyconst char* msg ) /* Accessor methods (get/set functions) to struct members. */ +/** Get the current line number. + * + */ +int yyget_lineno (void) +{ + + return yylineno; +} + /** Get the input stream. * */ @@ -1692,6 +1703,16 @@ char *yyget_text (void) return yytext; } +/** Set the current line number. + * @param line_number + * + */ +void yyset_lineno (int line_number ) +{ + + yylineno = line_number; +} + /** Set the input stream. This does not discard the current * input buffer. * @param in_str A readable stream. diff --git a/source/heimdal/lib/gssapi/krb5/acquire_cred.c b/source/heimdal/lib/gssapi/krb5/acquire_cred.c index 42b57cdaddd..d5c70636bc5 100644 --- a/source/heimdal/lib/gssapi/krb5/acquire_cred.c +++ b/source/heimdal/lib/gssapi/krb5/acquire_cred.c @@ -33,7 +33,7 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: acquire_cred.c 20688 2007-05-17 18:44:31Z lha $"); +RCSID("$Id: acquire_cred.c 21221 2007-06-20 08:42:10Z lha $"); OM_uint32 __gsskrb5_ccache_lifetime(OM_uint32 *minor_status, @@ -256,8 +256,8 @@ static OM_uint32 acquire_acceptor_cred if (kret) goto end; krb5_kt_free_entry(context, &entry); + ret = GSS_S_COMPLETE; } - ret = GSS_S_COMPLETE; end: if (ret != GSS_S_COMPLETE) { diff --git a/source/heimdal/lib/gssapi/krb5/display_name.c b/source/heimdal/lib/gssapi/krb5/display_name.c index 93fac8d67b5..727c447d2a0 100644 --- a/source/heimdal/lib/gssapi/krb5/display_name.c +++ b/source/heimdal/lib/gssapi/krb5/display_name.c @@ -33,7 +33,7 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: display_name.c 19031 2006-11-13 18:02:57Z lha $"); +RCSID("$Id: display_name.c 21077 2007-06-12 22:42:56Z lha $"); OM_uint32 _gsskrb5_display_name (OM_uint32 * minor_status, @@ -50,7 +50,8 @@ OM_uint32 _gsskrb5_display_name GSSAPI_KRB5_INIT (&context); - kret = krb5_unparse_name (context, name, &buf); + kret = krb5_unparse_name_flags (context, name, + KRB5_PRINCIPAL_UNPARSE_DISPLAY, &buf); if (kret) { *minor_status = kret; return GSS_S_FAILURE; diff --git a/source/heimdal/lib/gssapi/krb5/prf.c b/source/heimdal/lib/gssapi/krb5/prf.c index 3eb90d279f3..f79c9374a9c 100644 --- a/source/heimdal/lib/gssapi/krb5/prf.c +++ b/source/heimdal/lib/gssapi/krb5/prf.c @@ -33,7 +33,7 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: prf.c 20679 2007-05-14 03:12:05Z lha $"); +RCSID("$Id: prf.c 21129 2007-06-18 20:28:44Z lha $"); OM_uint32 _gsskrb5_pseudo_random(OM_uint32 *minor_status, @@ -67,6 +67,7 @@ _gsskrb5_pseudo_random(OM_uint32 *minor_status, switch(prf_key) { case GSS_C_PRF_KEY_FULL: _gsskrb5i_get_acceptor_subkey(ctx, context, &key); + break; case GSS_C_PRF_KEY_PARTIAL: _gsskrb5i_get_initiator_subkey(ctx, context, &key); break; diff --git a/source/heimdal/lib/gssapi/krb5/release_name.c b/source/heimdal/lib/gssapi/krb5/release_name.c index a01a9a2a62b..80b91930fd3 100644 --- a/source/heimdal/lib/gssapi/krb5/release_name.c +++ b/source/heimdal/lib/gssapi/krb5/release_name.c @@ -33,7 +33,7 @@ #include "krb5/gsskrb5_locl.h" -RCSID("$Id: release_name.c 19031 2006-11-13 18:02:57Z lha $"); +RCSID("$Id: release_name.c 21128 2007-06-18 20:26:50Z lha $"); OM_uint32 _gsskrb5_release_name (OM_uint32 * minor_status, @@ -43,8 +43,7 @@ OM_uint32 _gsskrb5_release_name krb5_context context; krb5_principal name = (krb5_principal)*input_name; - if (minor_status) - *minor_status = 0; + *minor_status = 0; GSSAPI_KRB5_INIT (&context); diff --git a/source/heimdal/lib/gssapi/mech/context.c b/source/heimdal/lib/gssapi/mech/context.c index 1691fd94017..e4517bee449 100644 --- a/source/heimdal/lib/gssapi/mech/context.c +++ b/source/heimdal/lib/gssapi/mech/context.c @@ -1,7 +1,7 @@ #include "mech/mech_locl.h" #include "heim_threads.h" -RCSID("$Id: context.c 19924 2007-01-16 10:17:01Z lha $"); +RCSID("$Id: context.c 21248 2007-06-21 00:45:13Z lha $"); struct mg_thread_ctx { gss_OID mech; @@ -79,7 +79,7 @@ _gss_mg_get_error(const gss_OID mech, OM_uint32 type, switch (type) { case GSS_C_GSS_CODE: { - if (value != mg->maj_stat) + if (value != mg->maj_stat || mg->maj_error.length == 0) break; string->value = malloc(mg->maj_error.length); string->length = mg->maj_error.length; @@ -87,7 +87,7 @@ _gss_mg_get_error(const gss_OID mech, OM_uint32 type, return GSS_S_COMPLETE; } case GSS_C_MECH_CODE: { - if (value != mg->min_stat) + if (value != mg->min_stat || mg->min_error.length == 0) break; string->value = malloc(mg->min_error.length); string->length = mg->min_error.length; diff --git a/source/heimdal/lib/gssapi/mech/gss_accept_sec_context.c b/source/heimdal/lib/gssapi/mech/gss_accept_sec_context.c index 8c5f4d0b08e..d1e243d8b85 100644 --- a/source/heimdal/lib/gssapi/mech/gss_accept_sec_context.c +++ b/source/heimdal/lib/gssapi/mech/gss_accept_sec_context.c @@ -27,7 +27,7 @@ */ #include "mech_locl.h" -RCSID("$Id: gss_accept_sec_context.c 20626 2007-05-08 13:56:49Z lha $"); +RCSID("$Id: gss_accept_sec_context.c 21237 2007-06-20 11:21:09Z lha $"); static OM_uint32 parse_header(const gss_buffer_t input_token, gss_OID mech_oid) @@ -237,9 +237,7 @@ OM_uint32 gss_accept_sec_context(OM_uint32 *minor_status, return (major_status); } - if (!src_name) { - m->gm_release_name(minor_status, &src_mn); - } else { + if (src_name && src_mn) { /* * Make a new name and mark it as an MN. */ @@ -250,13 +248,15 @@ OM_uint32 gss_accept_sec_context(OM_uint32 *minor_status, return (GSS_S_FAILURE); } *src_name = (gss_name_t) name; + } else if (src_mn) { + m->gm_release_name(minor_status, &src_mn); } if (mech_ret_flags & GSS_C_DELEG_FLAG) { if (!delegated_cred_handle) { m->gm_release_cred(minor_status, &delegated_mc); *ret_flags &= ~GSS_C_DELEG_FLAG; - } else { + } else if (delegated_mc) { struct _gss_cred *dcred; struct _gss_mechanism_cred *dmc; diff --git a/source/heimdal/lib/gssapi/mech/gss_display_name.c b/source/heimdal/lib/gssapi/mech/gss_display_name.c index e57e5dd795d..fc10933692c 100644 --- a/source/heimdal/lib/gssapi/mech/gss_display_name.c +++ b/source/heimdal/lib/gssapi/mech/gss_display_name.c @@ -27,7 +27,7 @@ */ #include "mech_locl.h" -RCSID("$Id: gss_display_name.c 19952 2007-01-17 10:16:15Z lha $"); +RCSID("$Id: gss_display_name.c 21246 2007-06-20 15:25:19Z lha $"); OM_uint32 gss_display_name(OM_uint32 *minor_status, @@ -43,6 +43,11 @@ gss_display_name(OM_uint32 *minor_status, if (output_name_type) *output_name_type = GSS_C_NO_OID; + if (name == NULL) { + *minor_status = 0; + return (GSS_S_BAD_NAME); + } + /* * If we know it, copy the buffer used to import the name in * the first place. Otherwise, ask all the MNs in turn if diff --git a/source/heimdal/lib/gssapi/mech/gss_display_status.c b/source/heimdal/lib/gssapi/mech/gss_display_status.c index c316c26fd76..37ded26db69 100644 --- a/source/heimdal/lib/gssapi/mech/gss_display_status.c +++ b/source/heimdal/lib/gssapi/mech/gss_display_status.c @@ -59,7 +59,7 @@ */ #include "mech_locl.h" -RCSID("$Id: gss_display_status.c 20084 2007-01-31 12:12:08Z lha $"); +RCSID("$Id: gss_display_status.c 21247 2007-06-21 00:37:27Z lha $"); static const char * calling_error(OM_uint32 v) @@ -85,7 +85,7 @@ static const char * routine_error(OM_uint32 v) { static const char *msgs[] = { - NULL, /* 0 */ + "Function completed successfully", /* 0 */ "An unsupported mechanism was requested", "An invalid name was supplied", "A supplied name was of an unsupported type", @@ -109,9 +109,7 @@ routine_error(OM_uint32 v) v >>= GSS_C_ROUTINE_ERROR_OFFSET; - if (v == 0) - return ""; - else if (v >= sizeof(msgs)/sizeof(*msgs)) + if (v >= sizeof(msgs)/sizeof(*msgs)) return "unknown routine error"; else return msgs[v]; diff --git a/source/heimdal/lib/gssapi/mech/gss_duplicate_name.c b/source/heimdal/lib/gssapi/mech/gss_duplicate_name.c index 3aab0b9bbcd..4ff81fdf2df 100644 --- a/source/heimdal/lib/gssapi/mech/gss_duplicate_name.c +++ b/source/heimdal/lib/gssapi/mech/gss_duplicate_name.c @@ -27,7 +27,7 @@ */ #include "mech_locl.h" -RCSID("$Id: gss_duplicate_name.c 19953 2007-01-17 11:16:35Z lha $"); +RCSID("$Id: gss_duplicate_name.c 21219 2007-06-20 08:27:11Z lha $"); OM_uint32 gss_duplicate_name(OM_uint32 *minor_status, const gss_name_t src_name, @@ -44,7 +44,7 @@ OM_uint32 gss_duplicate_name(OM_uint32 *minor_status, /* * If this name has a value (i.e. it didn't come from * gss_canonicalize_name(), we re-import the thing. Otherwise, - * we make an empty name to hold the MN copy. + * we make copy of each mech names. */ if (name->gn_value.value) { major_status = gss_import_name(minor_status, @@ -52,6 +52,10 @@ OM_uint32 gss_duplicate_name(OM_uint32 *minor_status, if (major_status != GSS_S_COMPLETE) return (major_status); new_name = (struct _gss_name *) *dest_name; + + SLIST_FOREACH(mn, &name->gn_mn, gmn_link) { + _gss_find_mn(new_name, mn->gmn_mech_oid); + } } else { new_name = malloc(sizeof(struct _gss_name)); if (!new_name) { @@ -59,17 +63,30 @@ OM_uint32 gss_duplicate_name(OM_uint32 *minor_status, return (GSS_S_FAILURE); } memset(new_name, 0, sizeof(struct _gss_name)); - SLIST_INIT(&name->gn_mn); + SLIST_INIT(&new_name->gn_mn); *dest_name = (gss_name_t) new_name; - } + + SLIST_FOREACH(mn, &name->gn_mn, gmn_link) { + struct _gss_mechanism_name *new_mn; + + new_mn = malloc(sizeof(*new_mn)); + if (!new_mn) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + new_mn->gmn_mech = mn->gmn_mech; + new_mn->gmn_mech_oid = mn->gmn_mech_oid; + + major_status = + mn->gmn_mech->gm_duplicate_name(minor_status, + mn->gmn_name, &new_mn->gmn_name); + if (major_status != GSS_S_COMPLETE) { + free(new_mn); + continue; + } + SLIST_INSERT_HEAD(&new_name->gn_mn, new_mn, gmn_link); + } - /* - * Import the new name into any mechanisms listed in the - * original name. We could probably get away with only doing - * this if the original was canonical. - */ - SLIST_FOREACH(mn, &name->gn_mn, gmn_link) { - _gss_find_mn(new_name, mn->gmn_mech_oid); } return (GSS_S_COMPLETE); diff --git a/source/heimdal/lib/gssapi/mech/gss_inquire_context.c b/source/heimdal/lib/gssapi/mech/gss_inquire_context.c index 5cce30c6bd8..d45baac6027 100644 --- a/source/heimdal/lib/gssapi/mech/gss_inquire_context.c +++ b/source/heimdal/lib/gssapi/mech/gss_inquire_context.c @@ -27,7 +27,7 @@ */ #include "mech_locl.h" -RCSID("$Id: gss_inquire_context.c 19958 2007-01-17 13:56:18Z lha $"); +RCSID("$Id: gss_inquire_context.c 21125 2007-06-18 20:11:07Z lha $"); OM_uint32 gss_inquire_context(OM_uint32 *minor_status, @@ -79,7 +79,8 @@ gss_inquire_context(OM_uint32 *minor_status, if (src_name) { name = _gss_make_name(m, src_mn); if (!name) { - *mech_type = GSS_C_NO_OID; + if (mech_type) + *mech_type = GSS_C_NO_OID; m->gm_release_name(minor_status, &src_mn); *minor_status = 0; return (GSS_S_FAILURE); @@ -90,8 +91,10 @@ gss_inquire_context(OM_uint32 *minor_status, if (targ_name) { name = _gss_make_name(m, targ_mn); if (!name) { - *mech_type = GSS_C_NO_OID; - gss_release_name(minor_status, src_name); + if (mech_type) + *mech_type = GSS_C_NO_OID; + if (src_name) + gss_release_name(minor_status, src_name); m->gm_release_name(minor_status, &targ_mn); *minor_status = 0; return (GSS_S_FAILURE); diff --git a/source/heimdal/lib/gssapi/mech/gss_inquire_cred_by_mech.c b/source/heimdal/lib/gssapi/mech/gss_inquire_cred_by_mech.c index a4ace9e9e93..aa83efb0c28 100644 --- a/source/heimdal/lib/gssapi/mech/gss_inquire_cred_by_mech.c +++ b/source/heimdal/lib/gssapi/mech/gss_inquire_cred_by_mech.c @@ -27,7 +27,7 @@ */ #include "mech_locl.h" -RCSID("$Id: gss_inquire_cred_by_mech.c 19960 2007-01-17 15:09:24Z lha $"); +RCSID("$Id: gss_inquire_cred_by_mech.c 21124 2007-06-18 20:08:24Z lha $"); OM_uint32 gss_inquire_cred_by_mech(OM_uint32 *minor_status, @@ -78,12 +78,16 @@ gss_inquire_cred_by_mech(OM_uint32 *minor_status, return (major_status); } - name = _gss_make_name(m, mn); - if (!name) { + if (cred_name) { + name = _gss_make_name(m, mn); + if (!name) { m->gm_release_name(minor_status, &mn); return (GSS_S_NO_CRED); - } + } + *cred_name = (gss_name_t) name; + } else + m->gm_release_name(minor_status, &mn); + - *cred_name = (gss_name_t) name; return (GSS_S_COMPLETE); } diff --git a/source/heimdal/lib/gssapi/mech/gss_krb5.c b/source/heimdal/lib/gssapi/mech/gss_krb5.c index 2500928baf3..9e77f429828 100644 --- a/source/heimdal/lib/gssapi/mech/gss_krb5.c +++ b/source/heimdal/lib/gssapi/mech/gss_krb5.c @@ -27,7 +27,7 @@ */ #include "mech_locl.h" -RCSID("$Id: gss_krb5.c 20383 2007-04-18 08:49:53Z lha $"); +RCSID("$Id: gss_krb5.c 21123 2007-06-18 20:05:26Z lha $"); #include #include @@ -650,7 +650,7 @@ gsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status, if (der_put_oid((unsigned char *)oid_flat.elements + oid_flat.length - 1, oid_flat.length, &oid, &size) != 0) { free(oid.components); - + free(oid_flat.elements); *minor_status = EINVAL; return GSS_S_FAILURE; } diff --git a/source/heimdal/lib/gssapi/mech/gss_set_cred_option.c b/source/heimdal/lib/gssapi/mech/gss_set_cred_option.c index 78c8cc79c10..c32291396f1 100644 --- a/source/heimdal/lib/gssapi/mech/gss_set_cred_option.c +++ b/source/heimdal/lib/gssapi/mech/gss_set_cred_option.c @@ -31,7 +31,7 @@ */ #include "mech_locl.h" -RCSID("$Id: gss_set_cred_option.c 20626 2007-05-08 13:56:49Z lha $"); +RCSID("$Id: gss_set_cred_option.c 21126 2007-06-18 20:19:59Z lha $"); OM_uint32 gss_set_cred_option (OM_uint32 *minor_status, @@ -64,7 +64,9 @@ gss_set_cred_option (OM_uint32 *minor_status, mc = malloc(sizeof(*mc)); if (mc == NULL) { - /* XXX free the other mc's */ + *cred_handle = (gss_cred_id_t)cred; + gss_release_cred(minor_status, cred_handle); + *minor_status = ENOMEM; return GSS_S_FAILURE; } diff --git a/source/heimdal/lib/gssapi/spnego/accept_sec_context.c b/source/heimdal/lib/gssapi/spnego/accept_sec_context.c index 106897b9b09..d20c913bf01 100644 --- a/source/heimdal/lib/gssapi/spnego/accept_sec_context.c +++ b/source/heimdal/lib/gssapi/spnego/accept_sec_context.c @@ -33,7 +33,7 @@ #include "spnego/spnego_locl.h" -RCSID("$Id: accept_sec_context.c 20929 2007-06-05 21:19:22Z lha $"); +RCSID("$Id: accept_sec_context.c 21243 2007-06-20 15:16:22Z lha $"); static OM_uint32 send_reject (OM_uint32 *minor_status, @@ -540,12 +540,12 @@ acceptor_start gss_cred_id_t *delegated_cred_handle ) { - OM_uint32 ret, ret2, minor; - NegTokenInit ni; - size_t ni_len; + OM_uint32 ret, junk, minor; + NegotiationToken nt; + size_t nt_len; + NegTokenInit *ni; int i; gss_buffer_desc data; - size_t len, taglen; gss_buffer_t mech_input_token = GSS_C_NO_BUFFER; gss_buffer_desc mech_output_token; gss_buffer_desc mech_buf; @@ -555,6 +555,9 @@ acceptor_start int get_mic = 0; int first_ok = 0; + if (src_name) + *src_name = GSS_C_NO_NAME; + mech_output_token.value = NULL; mech_output_token.length = 0; mech_buf.value = NULL; @@ -582,39 +585,30 @@ acceptor_start if (ret) return ret; - ret = der_match_tag_and_length(data.value, data.length, - ASN1_C_CONTEXT, CONS, - 0, - &len, &taglen); - if (ret) { - *minor_status = ret; - return GSS_S_FAILURE; - } - - if (len > data.length - taglen) { - *minor_status = ASN1_OVERRUN; - return GSS_S_FAILURE; - } - - ret = decode_NegTokenInit((const unsigned char *)data.value + taglen, - len, &ni, &ni_len); + ret = decode_NegotiationToken(data.value, data.length, &nt, &nt_len); + gss_release_buffer(minor_status, &data); if (ret) { *minor_status = ret; return GSS_S_DEFECTIVE_TOKEN; } + if (nt.element != choice_NegotiationToken_negTokenInit) { + *minor_status = 0; + return GSS_S_DEFECTIVE_TOKEN; + } + ni = &nt.u.negTokenInit; - if (ni.mechTypes.len < 1) { - free_NegTokenInit(&ni); + if (ni->mechTypes.len < 1) { + free_NegotiationToken(&nt); *minor_status = 0; return GSS_S_DEFECTIVE_TOKEN; } HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); - ret = copy_MechTypeList(&ni.mechTypes, &ctx->initiator_mech_types); + ret = copy_MechTypeList(&ni->mechTypes, &ctx->initiator_mech_types); if (ret) { HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); - free_NegTokenInit(&ni); + free_NegotiationToken(&nt); *minor_status = ret; return GSS_S_FAILURE; } @@ -627,17 +621,17 @@ acceptor_start */ ret = select_mech(minor_status, - &ni.mechTypes.val[0], + &ni->mechTypes.val[0], 0, &preferred_mech_type); - if (ret == 0 && ni.mechToken != NULL) { + if (ret == 0 && ni->mechToken != NULL) { gss_cred_id_t mech_delegated_cred = GSS_C_NO_CREDENTIAL; gss_cred_id_t mech_cred; gss_buffer_desc ibuf; - ibuf.length = ni.mechToken->length; - ibuf.value = ni.mechToken->data; + ibuf.length = ni->mechToken->length; + ibuf.value = ni->mechToken->data; mech_input_token = &ibuf; if (acceptor_cred != NULL) @@ -668,12 +662,12 @@ acceptor_start if (ret == GSS_S_COMPLETE) ctx->open = 1; - if (delegated_cred_handle) + if (mech_delegated_cred && delegated_cred_handle) ret = _gss_spnego_alloc_cred(minor_status, mech_delegated_cred, delegated_cred_handle); else - gss_release_cred(&ret2, &mech_delegated_cred); + gss_release_cred(&junk, &mech_delegated_cred); ret = acceptor_complete(minor_status, ctx, @@ -681,7 +675,7 @@ acceptor_start &mech_buf, mech_input_token, &mech_output_token, - ni.mechListMIC, + ni->mechListMIC, output_token); if (ret != GSS_S_COMPLETE) goto out; @@ -697,9 +691,9 @@ acceptor_start if (!first_ok) { /* Call glue layer to find first mech we support */ - for (i = 1; i < ni.mechTypes.len; ++i) { + for (i = 1; i < ni->mechTypes.len; ++i) { ret = select_mech(minor_status, - &ni.mechTypes.val[i], + &ni->mechTypes.val[i], 1, &preferred_mech_type); if (ret == 0) @@ -707,7 +701,7 @@ acceptor_start } if (preferred_mech_type == GSS_C_NO_OID) { HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); - free_NegTokenInit(&ni); + free_NegotiationToken(&nt); return GSS_S_BAD_MECH; } @@ -735,7 +729,8 @@ out: free(mech_buf.value); mech_buf.value = NULL; } - free_NegTokenInit(&ni); + free_NegotiationToken(&nt); + if (ret == GSS_S_COMPLETE) { if (src_name != NULL && ctx->mech_src_name != NULL) { @@ -746,8 +741,7 @@ out: name->mech = ctx->mech_src_name; ctx->mech_src_name = NULL; *src_name = (gss_name_t)name; - } else - *src_name = GSS_C_NO_NAME; + } } if (delegated_cred_handle != NULL) { *delegated_cred_handle = ctx->delegated_cred_id; @@ -790,10 +784,9 @@ acceptor_continue ) { OM_uint32 ret, ret2, minor; - NegTokenResp na; - size_t na_len; - gss_buffer_desc data; - size_t len, taglen; + NegotiationToken nt; + size_t nt_len; + NegTokenResp *na; unsigned int negResult = accept_incomplete; gss_buffer_t mech_input_token = GSS_C_NO_BUFFER; gss_buffer_t mech_output_token = GSS_C_NO_BUFFER; @@ -810,45 +803,34 @@ acceptor_continue * context token (negTokenInit). */ - data.value = input_token_buffer->value; - data.length = input_token_buffer->length; - - ret = der_match_tag_and_length(data.value, data.length, - ASN1_C_CONTEXT, CONS, - 1, - &len, &taglen); - if (ret) { - *minor_status = ret; - return GSS_S_FAILURE; - } - - if (len > data.length - taglen) { - *minor_status = ASN1_OVERRUN; - return GSS_S_FAILURE; - } - - ret = decode_NegTokenResp((const unsigned char *)data.value + taglen, - len, &na, &na_len); + ret = decode_NegotiationToken(input_token_buffer->value, + input_token_buffer->length, + &nt, &nt_len); if (ret) { *minor_status = ret; return GSS_S_DEFECTIVE_TOKEN; } + if (nt.element != choice_NegotiationToken_negTokenResp) { + *minor_status = 0; + return GSS_S_DEFECTIVE_TOKEN; + } + na = &nt.u.negTokenResp; - if (na.negResult != NULL) { - negResult = *(na.negResult); + if (na->negResult != NULL) { + negResult = *(na->negResult); } HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex); { gss_buffer_desc ibuf, obuf; - int require_mic, get_mic; + int require_mic, get_mic = 0; int require_response; heim_octet_string *mic; - if (na.responseToken != NULL) { - ibuf.length = na.responseToken->length; - ibuf.value = na.responseToken->data; + if (na->responseToken != NULL) { + ibuf.length = na->responseToken->length; + ibuf.value = na->responseToken->data; mech_input_token = &ibuf; } else { ibuf.value = NULL; @@ -901,7 +883,7 @@ acceptor_continue mech_output_token = &obuf; } if (ret != GSS_S_COMPLETE && ret != GSS_S_CONTINUE_NEEDED) { - free_NegTokenResp(&na); + free_NegotiationToken(&nt); send_reject (minor_status, output_token); HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex); return ret; @@ -919,7 +901,7 @@ acceptor_continue ctx->require_mic = require_mic; - mic = na.mechListMIC; + mic = na->mechListMIC; if (mic != NULL) require_mic = 1; @@ -930,7 +912,7 @@ acceptor_continue &mech_buf, mech_input_token, mech_output_token, - na.mechListMIC, + na->mechListMIC, output_token); if (ctx->mech_flags & GSS_C_DCE_STYLE) @@ -964,16 +946,19 @@ acceptor_continue gss_release_buffer(&minor, mech_output_token); if (mech_buf.value != NULL) free(mech_buf.value); - free_NegTokenResp(&na); + free_NegotiationToken(&nt); } if (ret == GSS_S_COMPLETE) { - if (src_name != NULL) { - ret2 = gss_duplicate_name(minor_status, - ctx->mech_src_name, - src_name); - if (ret2 != GSS_S_COMPLETE) - ret = ret2; + if (src_name != NULL && ctx->mech_src_name != NULL) { + spnego_name name; + + name = calloc(1, sizeof(*name)); + if (name) { + name->mech = ctx->mech_src_name; + ctx->mech_src_name = NULL; + *src_name = (gss_name_t)name; + } } if (delegated_cred_handle != NULL) { *delegated_cred_handle = ctx->delegated_cred_id; diff --git a/source/heimdal/lib/hcrypto/pkcs12.c b/source/heimdal/lib/hcrypto/pkcs12.c index dcfbdfad424..b43fe571d6c 100644 --- a/source/heimdal/lib/hcrypto/pkcs12.c +++ b/source/heimdal/lib/hcrypto/pkcs12.c @@ -35,7 +35,7 @@ #include #endif -RCSID("$Id: pkcs12.c 20661 2007-05-10 21:57:58Z lha $"); +RCSID("$Id: pkcs12.c 21155 2007-06-18 21:59:44Z lha $"); #include #include @@ -93,8 +93,11 @@ PKCS12_key_gen(const void *key, size_t keylen, while (1) { BIGNUM *bnB, *bnOne; - if (!EVP_DigestInit_ex(&ctx, md, NULL)) + if (!EVP_DigestInit_ex(&ctx, md, NULL)) { + free(I); + free(v); return 0; + } for (i = 0; i < vlen; i++) EVP_DigestUpdate(&ctx, &idc, 1); EVP_DigestUpdate(&ctx, I, size_I); diff --git a/source/heimdal/lib/hcrypto/rand-egd.c b/source/heimdal/lib/hcrypto/rand-egd.c index d1b024b535d..497a3ab5f80 100644 --- a/source/heimdal/lib/hcrypto/rand-egd.c +++ b/source/heimdal/lib/hcrypto/rand-egd.c @@ -35,7 +35,7 @@ #include #endif -RCSID("$Id: rand-egd.c 20093 2007-01-31 12:44:28Z lha $"); +RCSID("$Id: rand-egd.c 21156 2007-06-18 22:00:59Z lha $"); #include #ifdef HAVE_SYS_UN_H @@ -255,7 +255,7 @@ RAND_egd_bytes(const char *filename, int size) RAND_seed(data, size); - memset(data, 0, sizeof(data)); + memset(data, 0, size); free(data); return 1; diff --git a/source/heimdal/lib/hcrypto/rand-fortuna.c b/source/heimdal/lib/hcrypto/rand-fortuna.c index 6cc4267c134..1d47ed49cc3 100644 --- a/source/heimdal/lib/hcrypto/rand-fortuna.c +++ b/source/heimdal/lib/hcrypto/rand-fortuna.c @@ -33,7 +33,7 @@ #include #endif -RCSID("$Id: rand-fortuna.c 20029 2007-01-21 09:55:42Z lha $"); +RCSID("$Id: rand-fortuna.c 21196 2007-06-20 05:08:58Z lha $"); #include #include @@ -427,6 +427,8 @@ extract_data(FState * st, unsigned count, unsigned char *dst) static FState main_state; static int init_done; static int have_entropy; +#define FORTUNA_RESEED_BYTE 10000 +static unsigned resend_bytes; /* * Try our best to do an inital seed @@ -472,6 +474,35 @@ fortuna_reseed(void) memset(buf, 0, sizeof(buf)); } } + /* + * Fall back to gattering data from timer and secret files, this + * is really the last resort. + */ + if (!entropy_p) { + /* to save stackspace */ + union { + unsigned char buf[INIT_BYTES]; + unsigned char shad[1001]; + } u; + int fd; + + /* add timer info */ + if ((*hc_rand_timer_method.bytes)(u.buf, sizeof(u.buf)) == 1) + add_entropy(&main_state, u.buf, sizeof(u.buf)); + /* add /etc/shadow */ + fd = open("/etc/shadow", O_RDONLY, 0); + if (fd >= 0) { + ssize_t n; + /* add_entropy will hash the buf */ + while ((n = read(fd, (char *)u.shad, sizeof(u.shad))) > 0) + add_entropy(&main_state, u.shad, sizeof(u.shad)); + close(fd); + } + + memset(&u, 0, sizeof(u)); + + entropy_p = 1; /* sure about this ? */ + } { pid_t pid = getpid(); add_entropy(&main_state, (void *)&pid, sizeof(pid)); @@ -517,6 +548,11 @@ fortuna_bytes(unsigned char *outdata, int size) { if (!fortuna_init()) return 0; + resend_bytes += size; + if (resend_bytes > FORTUNA_RESEED_BYTE || resend_bytes < size) { + resend_bytes = 0; + fortuna_reseed(); + } extract_data(&main_state, size, outdata); return 1; } diff --git a/source/heimdal/lib/hcrypto/rand-timer.c b/source/heimdal/lib/hcrypto/rand-timer.c new file mode 100644 index 00000000000..67a77b01fc1 --- /dev/null +++ b/source/heimdal/lib/hcrypto/rand-timer.c @@ -0,0 +1,206 @@ +/* + * Copyright (c) 1995, 1996, 1997, 1999, 2007 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. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +RCSID("$Id$"); + +#include +#include +#include + +#include + +#include "randi.h" + +#ifndef WIN32 /* don't bother with this on windows */ + +static volatile int counter; +static volatile unsigned char *gdata; /* Global data */ +static volatile int igdata; /* Index into global data */ +static int gsize; + +static +RETSIGTYPE +sigALRM(int sig) +{ + if (igdata < gsize) + gdata[igdata++] ^= counter & 0xff; + +#ifndef HAVE_SIGACTION + signal(SIGALRM, sigALRM); /* Reinstall SysV signal handler */ +#endif + SIGRETURN(0); +} + +#ifndef HAVE_SETITIMER +static void +pacemaker(struct timeval *tv) +{ + fd_set fds; + pid_t pid; + pid = getppid(); + while(1){ + FD_ZERO(&fds); + FD_SET(0, &fds); + select(1, &fds, NULL, NULL, tv); + kill(pid, SIGALRM); + } +} +#endif + +#ifdef HAVE_SIGACTION +/* XXX ugly hack, should perhaps use function from roken */ +static RETSIGTYPE +(*fake_signal(int sig, RETSIGTYPE (*f)(int)))(int) +{ + struct sigaction sa, osa; + sa.sa_handler = f; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sigaction(sig, &sa, &osa); + return osa.sa_handler; +} +#define signal(S, F) fake_signal((S), (F)) +#endif + +#endif /* WIN32*/ + +/* + * + */ + +static void +timer_seed(const void *indata, int size) +{ +} + +static int +timer_bytes(unsigned char *outdata, int size) +{ +#ifdef WIN32 + return 0; +#else /* WIN32 */ + struct itimerval tv, otv; + RETSIGTYPE (*osa)(int); + int i, j; +#ifndef HAVE_SETITIMER + RETSIGTYPE (*ochld)(int); + pid_t pid; +#endif + + gdata = outdata; + gsize = size; + igdata = 0; + + osa = signal(SIGALRM, sigALRM); + + /* Start timer */ + tv.it_value.tv_sec = 0; + tv.it_value.tv_usec = 10 * 1000; /* 10 ms */ + tv.it_interval = tv.it_value; +#ifdef HAVE_SETITIMER + setitimer(ITIMER_REAL, &tv, &otv); +#else + ochld = signal(SIGCHLD, SIG_IGN); + pid = fork(); + if(pid == -1){ + signal(SIGCHLD, ochld != SIG_ERR ? ochld : SIG_DFL); + des_not_rand_data(data, size); + return; + } + if(pid == 0) + pacemaker(&tv.it_interval); +#endif + + for(i = 0; i < 4; i++) { + for (igdata = 0; igdata < size;) /* igdata++ in sigALRM */ + counter++; + for (j = 0; j < size; j++) /* Only use 2 bits each lap */ + gdata[j] = (gdata[j]>>2) | (gdata[j]<<6); + } +#ifdef HAVE_SETITIMER + setitimer(ITIMER_REAL, &otv, 0); +#else + kill(pid, SIGKILL); + while(waitpid(pid, NULL, 0) != pid); + signal(SIGCHLD, ochld != SIG_ERR ? ochld : SIG_DFL); +#endif + signal(SIGALRM, osa != SIG_ERR ? osa : SIG_DFL); + + return 1; +#endif +} + +static void +timer_cleanup(void) +{ +} + +static void +timer_add(const void *indata, int size, double entropi) +{ +} + +static int +timer_pseudorand(unsigned char *outdata, int size) +{ + return timer_bytes(outdata, size); +} + +static int +timer_status(void) +{ +#ifdef WIN32 + return 0; +#else + return 1; +#endif +} + +const RAND_METHOD hc_rand_timer_method = { + timer_seed, + timer_bytes, + timer_cleanup, + timer_add, + timer_pseudorand, + timer_status +}; + +const RAND_METHOD * +RAND_timer_method(void) +{ + return &hc_rand_timer_method; +} diff --git a/source/heimdal/lib/hcrypto/rand.c b/source/heimdal/lib/hcrypto/rand.c index 29f2d46dba9..248fdde6208 100644 --- a/source/heimdal/lib/hcrypto/rand.c +++ b/source/heimdal/lib/hcrypto/rand.c @@ -35,7 +35,7 @@ #include #endif -RCSID("$Id: rand.c 20126 2007-02-01 22:08:41Z lha $"); +RCSID("$Id: rand.c 21198 2007-06-20 05:10:41Z lha $"); #include #include @@ -56,11 +56,7 @@ init_method(void) { if (selected_meth != NULL) return; - - if ((*hc_rand_unix_method.status)() == 1) - selected_meth = &hc_rand_unix_method; - else - selected_meth = &hc_rand_fortuna_method; + selected_meth = &hc_rand_fortuna_method; } void diff --git a/source/heimdal/lib/hcrypto/randi.h b/source/heimdal/lib/hcrypto/randi.h index b9b9b5309c0..6ae75f262b3 100644 --- a/source/heimdal/lib/hcrypto/randi.h +++ b/source/heimdal/lib/hcrypto/randi.h @@ -32,7 +32,7 @@ */ /* - * $Id: randi.h 20027 2007-01-21 09:54:00Z lha $ + * $Id: randi.h 21101 2007-06-18 03:53:46Z lha $ */ #ifndef _HEIM_RANDI_H @@ -41,5 +41,8 @@ extern const RAND_METHOD hc_rand_fortuna_method; extern const RAND_METHOD hc_rand_unix_method; extern const RAND_METHOD hc_rand_egd_method; +extern const RAND_METHOD hc_rand_timer_method; + +const RAND_METHOD * RAND_timer_method(void); #endif /* _HEIM_RANDI_H */ diff --git a/source/heimdal/lib/hcrypto/rsa-imath.c b/source/heimdal/lib/hcrypto/rsa-imath.c index e05ead1e666..74093ff7ba0 100644 --- a/source/heimdal/lib/hcrypto/rsa-imath.c +++ b/source/heimdal/lib/hcrypto/rsa-imath.c @@ -35,7 +35,7 @@ #include #endif -RCSID("$Id: rsa-imath.c 19750 2007-01-06 13:45:25Z lha $"); +RCSID("$Id: rsa-imath.c 21154 2007-06-18 21:58:12Z lha $"); #include #include @@ -180,7 +180,6 @@ imath_rsa_public_encrypt(int flen, const unsigned char* from, } padlen = size - flen - 3; - assert(padlen >= 8); *p++ = 2; if (RAND_bytes(p, padlen) != 1) { diff --git a/source/heimdal/lib/hdb/ext.c b/source/heimdal/lib/hdb/ext.c index aac0ff53670..5f60999946b 100644 --- a/source/heimdal/lib/hdb/ext.c +++ b/source/heimdal/lib/hdb/ext.c @@ -34,7 +34,7 @@ #include "hdb_locl.h" #include -RCSID("$Id: ext.c 20236 2007-02-16 23:52:29Z lha $"); +RCSID("$Id: ext.c 21113 2007-06-18 12:59:32Z lha $"); krb5_error_code hdb_entry_check_mandatory(krb5_context context, const hdb_entry *ent) @@ -268,6 +268,7 @@ hdb_entry_get_password(krb5_context context, HDB *db, const hdb_entry *entry, char **p) { HDB_extension *ext; + char *str; int ret; ext = hdb_find_extension(entry, choice_HDB_extension_data_password); @@ -314,7 +315,14 @@ hdb_entry_get_password(krb5_context context, HDB *db, } return 0; } - krb5_set_error_string(context, "password attribute not found"); + + ret = krb5_unparse_name(context, entry->principal, &str); + if (ret == 0) { + krb5_set_error_string(context, "no password attributefor %s", str); + free(str); + } else + krb5_clear_error_string(context); + return ENOENT; } diff --git a/source/heimdal/lib/hx509/cert.c b/source/heimdal/lib/hx509/cert.c index 27b17a02049..caf163f8e4b 100644 --- a/source/heimdal/lib/hx509/cert.c +++ b/source/heimdal/lib/hx509/cert.c @@ -32,7 +32,7 @@ */ #include "hx_locl.h" -RCSID("$Id: cert.c 20915 2007-06-05 03:58:56Z lha $"); +RCSID("$Id: cert.c 21294 2007-06-25 14:37:15Z lha $"); #include "crypto-headers.h" #include @@ -43,6 +43,7 @@ struct hx509_verify_ctx_data { #define HX509_VERIFY_CTX_F_ALLOW_PROXY_CERTIFICATE 2 #define HX509_VERIFY_CTX_F_REQUIRE_RFC3280 4 #define HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS 8 +#define HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS 16 time_t time_now; unsigned int max_depth; #define HX509_VERIFY_MAX_DEPTH 30 @@ -51,6 +52,7 @@ struct hx509_verify_ctx_data { #define REQUIRE_RFC3280(ctx) ((ctx)->flags & HX509_VERIFY_CTX_F_REQUIRE_RFC3280) #define CHECK_TA(ctx) ((ctx)->flags & HX509_VERIFY_CTX_F_CHECK_TRUST_ANCHORS) +#define ALLOW_DEF_TA(ctx) (((ctx)->flags & HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS) == 0) struct _hx509_cert_attrs { size_t len; @@ -76,22 +78,6 @@ typedef struct hx509_name_constraints { #define GeneralSubtrees_SET(g,var) \ (g)->len = (var)->len, (g)->val = (var)->val; -/* - * - */ - -void -_hx509_abort(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); - printf("\n"); - fflush(stdout); - abort(); -} - /* * */ @@ -227,10 +213,37 @@ hx509_cert_init(hx509_context context, const Certificate *c, hx509_cert *cert) if (ret) { free((*cert)->data); free(*cert); + *cert = NULL; } return ret; } +int +hx509_cert_init_data(hx509_context context, + const void *ptr, + size_t len, + hx509_cert *cert) +{ + Certificate t; + size_t size; + int ret; + + ret = decode_Certificate(ptr, len, &t, &size); + if (ret) { + hx509_set_error_string(context, 0, ret, "Failed to decode certificate"); + return ret; + } + if (size != len) { + hx509_set_error_string(context, 0, HX509_EXTRA_DATA_AFTER_STRUCTURE, + "Extra data after certificate"); + return HX509_EXTRA_DATA_AFTER_STRUCTURE; + } + + ret = hx509_cert_init(context, &t, cert); + free_Certificate(&t); + return ret; +} + void _hx509_cert_set_release(hx509_cert cert, _hx509_cert_release_func release, @@ -291,10 +304,10 @@ hx509_cert hx509_cert_ref(hx509_cert cert) { if (cert->ref <= 0) - _hx509_abort("refcount <= 0"); + _hx509_abort("cert refcount <= 0"); cert->ref++; if (cert->ref == 0) - _hx509_abort("refcount == 0"); + _hx509_abort("cert refcount == 0"); return cert; } @@ -341,6 +354,12 @@ hx509_verify_set_time(hx509_verify_ctx ctx, time_t t) ctx->time_now = t; } +void +hx509_verify_set_max_depth(hx509_verify_ctx ctx, unsigned int max_depth) +{ + ctx->max_depth = max_depth; +} + void hx509_verify_set_proxy_certificate(hx509_verify_ctx ctx, int boolean) { @@ -359,6 +378,15 @@ hx509_verify_set_strict_rfc3280_verification(hx509_verify_ctx ctx, int boolean) ctx->flags &= ~HX509_VERIFY_CTX_F_REQUIRE_RFC3280; } +void +hx509_verify_ctx_f_allow_default_trustanchors(hx509_verify_ctx ctx, int boolean) +{ + if (boolean) + ctx->flags &= ~HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS; + else + ctx->flags |= HX509_VERIFY_CTX_F_NO_DEFAULT_ANCHORS; +} + static const Extension * find_extension(const Certificate *cert, const heim_oid *oid, int *idx) { @@ -1295,13 +1323,15 @@ match_general_name(const GeneralName *c, const GeneralName *n, int *match) return 0; } case choice_GeneralName_dNSName: { - size_t len1, len2; + size_t lenc, lenn; - len1 = strlen(c->u.dNSName); - len2 = strlen(n->u.dNSName); - if (len1 > len2) + lenc = strlen(c->u.dNSName); + lenn = strlen(n->u.dNSName); + if (lenc > lenn) return HX509_NAME_CONSTRAINT_ERROR; - if (strcasecmp(&n->u.dNSName[len2 - len1], c->u.dNSName) != 0) + if (strcasecmp(&n->u.dNSName[lenn - lenc], c->u.dNSName) != 0) + return HX509_NAME_CONSTRAINT_ERROR; + if (lenc != lenn && n->u.dNSName[lenn - lenc - 1] != '.') return HX509_NAME_CONSTRAINT_ERROR; *match = 1; return 0; @@ -1488,15 +1518,15 @@ hx509_verify_path(hx509_context context, /* * */ - ret = hx509_certs_init(context, "MEMORY:trust-anchors", 0, NULL, &anchors); - if (ret) - goto out; - ret = hx509_certs_merge(context, anchors, ctx->trust_anchors); - if (ret) - goto out; - ret = hx509_certs_merge(context, anchors, context->default_trust_anchors); - if (ret) - goto out; + if (ctx->trust_anchors) + anchors = _hx509_certs_ref(ctx->trust_anchors); + else if (context->default_trust_anchors && ALLOW_DEF_TA(ctx)) + anchors = _hx509_certs_ref(context->default_trust_anchors); + else { + ret = hx509_certs_init(context, "MEMORY:no-TA", 0, NULL, &anchors); + if (ret) + goto out; + } /* * Calculate the path from the certificate user presented to the @@ -1843,17 +1873,82 @@ hx509_verify_signature(hx509_context context, return _hx509_verify_signature(context, signer->data, alg, data, sig); } +#define HX509_VHN_F_ALLOW_NO_MATCH 1 + int hx509_verify_hostname(hx509_context context, const hx509_cert cert, - int require_match, + int flags, + hx509_hostname_type type, const char *hostname, const struct sockaddr *sa, /* XXX krb5_socklen_t */ int sa_size) { + GeneralNames san; + int ret, i, j; + if (sa && sa_size <= 0) return EINVAL; - return 0; + + memset(&san, 0, sizeof(san)); + + i = 0; + do { + ret = find_extension_subject_alt_name(cert->data, &i, &san); + if (ret == HX509_EXTENSION_NOT_FOUND) { + ret = 0; + break; + } else if (ret != 0) + break; + + for (j = 0; j < san.len; j++) { + switch (san.val[j].element) { + case choice_GeneralName_dNSName: + if (strcasecmp(san.val[j].u.dNSName, hostname) == 0) { + free_GeneralNames(&san); + return 0; + } + break; + default: + break; + } + } + free_GeneralNames(&san); + } while (1); + + { + Name *name = &cert->data->tbsCertificate.subject; + + /* match if first component is a CN= */ + if (name->u.rdnSequence.len > 0 + && name->u.rdnSequence.val[0].len == 1 + && der_heim_oid_cmp(&name->u.rdnSequence.val[0].val[0].type, + oid_id_at_commonName()) == 0) + { + DirectoryString *ds = &name->u.rdnSequence.val[0].val[0].value; + + switch (ds->element) { + case choice_DirectoryString_printableString: + if (strcasecmp(ds->u.printableString, hostname) == 0) + return 0; + break; + case choice_DirectoryString_ia5String: + if (strcasecmp(ds->u.ia5String, hostname) == 0) + return 0; + break; + case choice_DirectoryString_utf8String: + if (strcasecmp(ds->u.utf8String, hostname) == 0) + return 0; + default: + break; + } + } + } + + if ((flags & HX509_VHN_F_ALLOW_NO_MATCH) == 0) + ret = HX509_NAME_CONSTRAINT_ERROR; + + return ret; } int @@ -2434,3 +2529,24 @@ hx509_cert_binary(hx509_context context, hx509_cert c, heim_octet_string *os) return ret; } + +/* + * Last to avoid lost __attribute__s due to #undef. + */ + +#undef __attribute__ +#define __attribute__(X) + +void +_hx509_abort(const char *fmt, ...) + __attribute__ ((noreturn, format (printf, 1, 2))) +{ + va_list ap; + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + printf("\n"); + fflush(stdout); + abort(); +} + diff --git a/source/heimdal/lib/hx509/cms.c b/source/heimdal/lib/hx509/cms.c index 29ca80e1941..30f364060d0 100644 --- a/source/heimdal/lib/hx509/cms.c +++ b/source/heimdal/lib/hx509/cms.c @@ -32,7 +32,7 @@ */ #include "hx_locl.h" -RCSID("$Id: cms.c 20937 2007-06-06 20:50:55Z lha $"); +RCSID("$Id: cms.c 21319 2007-06-25 19:46:52Z lha $"); #define ALLOC(X, N) (X) = calloc((N), sizeof(*(X))) #define ALLOC_SEQ(X, N) do { (X)->len = (N); ALLOC((X)->val, (N)); } while(0) @@ -115,24 +115,42 @@ hx509_cms_unwrap_ContentInfo(const heim_octet_string *in, return 0; } +#define CMS_ID_SKI 0 +#define CMS_ID_NAME 1 + static int -fill_CMSIdentifier(const hx509_cert cert, CMSIdentifier *id) +fill_CMSIdentifier(const hx509_cert cert, + int type, + CMSIdentifier *id) { - hx509_name name; int ret; - id->element = choice_CMSIdentifier_issuerAndSerialNumber; - ret = hx509_cert_get_issuer(cert, &name); - if (ret) - return ret; - ret = copy_Name(&name->der_name, - &id->u.issuerAndSerialNumber.issuer); - hx509_name_free(&name); - if (ret) - return ret; + switch (type) { + case CMS_ID_SKI: + id->element = choice_CMSIdentifier_subjectKeyIdentifier; + ret = _hx509_find_extension_subject_key_id(_hx509_get_cert(cert), + &id->u.subjectKeyIdentifier); + if (ret == 0) + break; + /* FALL THOUGH */ + case CMS_ID_NAME: { + hx509_name name; - ret = hx509_cert_get_serialnumber(cert, - &id->u.issuerAndSerialNumber.serialNumber); + id->element = choice_CMSIdentifier_issuerAndSerialNumber; + ret = hx509_cert_get_issuer(cert, &name); + if (ret) + return ret; + ret = hx509_name_to_Name(name, &id->u.issuerAndSerialNumber.issuer); + hx509_name_free(&name); + if (ret) + return ret; + + ret = hx509_cert_get_serialnumber(cert, &id->u.issuerAndSerialNumber.serialNumber); + break; + } + default: + _hx509_abort("CMS fill identifier with unknown type"); + } return ret; } @@ -467,6 +485,13 @@ hx509_cms_envelope_1(hx509_context context, goto out; } + ret = hx509_crypto_random_iv(crypto, &ivec); + if (ret) { + hx509_set_error_string(context, 0, ret, + "Failed to create a random iv"); + goto out; + } + ret = hx509_crypto_encrypt(crypto, data, length, @@ -518,7 +543,7 @@ hx509_cms_envelope_1(hx509_context context, ri = &ed.recipientInfos.val[0]; ri->version = 0; - ret = fill_CMSIdentifier(cert, &ri->rid); + ret = fill_CMSIdentifier(cert, CMS_ID_SKI, &ri->rid); if (ret) { hx509_set_error_string(context, 0, ret, "Failed to set CMS identifier info " @@ -585,22 +610,12 @@ any_to_certs(hx509_context context, const SignedData *sd, hx509_certs certs) return 0; for (i = 0; i < sd->certificates->len; i++) { - Certificate cert; hx509_cert c; - const void *p = sd->certificates->val[i].data; - size_t size, length = sd->certificates->val[i].length; - - ret = decode_Certificate(p, length, &cert, &size); - if (ret) { - hx509_set_error_string(context, 0, ret, - "Failed to decode certificate %d " - "in SignedData.certificates", i); - return ret; - } - - ret = hx509_cert_init(context, &cert, &c); - free_Certificate(&cert); + ret = hx509_cert_init_data(context, + sd->certificates->val[i].data, + sd->certificates->val[i].length, + &c); if (ret) return ret; ret = hx509_certs_add(context, certs, c); @@ -951,6 +966,7 @@ hx509_cms_create_signed_1(hx509_context context, int ret; size_t size; hx509_path path; + int cmsidflag = CMS_ID_SKI; memset(&sd, 0, sizeof(sd)); memset(&name, 0, sizeof(name)); @@ -960,6 +976,9 @@ hx509_cms_create_signed_1(hx509_context context, content.data = rk_UNCONST(data); content.length = length; + if (flags & HX509_CMS_SIGATURE_ID_NAME) + cmsidflag = CMS_ID_NAME; + if (_hx509_cert_private_key(cert) == NULL) { hx509_set_error_string(context, 0, HX509_PRIVATE_KEY_MISSING, "Private key missing for signing"); @@ -1014,7 +1033,7 @@ hx509_cms_create_signed_1(hx509_context context, signer_info->version = 1; - ret = fill_CMSIdentifier(cert, &signer_info->sid); + ret = fill_CMSIdentifier(cert, cmsidflag, &signer_info->sid); if (ret) { hx509_clear_error_string(context); goto out; diff --git a/source/heimdal/lib/hx509/crypto.c b/source/heimdal/lib/hx509/crypto.c index 96d9693cc25..d86300bd586 100644 --- a/source/heimdal/lib/hx509/crypto.c +++ b/source/heimdal/lib/hx509/crypto.c @@ -32,7 +32,7 @@ */ #include "hx_locl.h" -RCSID("$Id: crypto.c 20939 2007-06-06 20:53:02Z lha $"); +RCSID("$Id: crypto.c 21318 2007-06-25 19:46:32Z lha $"); struct hx509_crypto; @@ -362,6 +362,7 @@ rsa_create_signature(hx509_context context, sig->length = RSA_size(signer->private_key.rsa); sig->data = malloc(sig->length); if (sig->data == NULL) { + der_free_octet_string(&indata); hx509_set_error_string(context, 0, ENOMEM, "out of memory"); return ENOMEM; } @@ -1761,15 +1762,17 @@ CMSRC2CBCParam_set(hx509_context context, const heim_octet_string *param, p->maximum_effective_key = 128; break; default: + free(p); free_CMSRC2CBCParameter(&rc2param); return HX509_CRYPTO_SIG_INVALID_FORMAT; } if (ivec) ret = der_copy_octet_string(&rc2param.iv, ivec); free_CMSRC2CBCParameter(&rc2param); - if (ret) + if (ret) { + free(p); hx509_clear_error_string(context); - else + } else crypto->param = p; return ret; @@ -2008,11 +2011,30 @@ hx509_crypto_get_params(hx509_context context, return (*crypto->cipher->get_params)(context, crypto, ivec, param); } +int +hx509_crypto_random_iv(hx509_crypto crypto, heim_octet_string *ivec) +{ + ivec->length = EVP_CIPHER_iv_length(crypto->c); + ivec->data = malloc(ivec->length); + if (ivec->data == NULL) { + ivec->length = 0; + return ENOMEM; + } + + if (RAND_bytes(ivec->data, ivec->length) <= 0) { + free(ivec->data); + ivec->data = NULL; + ivec->length = 0; + return HX509_CRYPTO_INTERNAL_ERROR; + } + return 0; +} + int hx509_crypto_encrypt(hx509_crypto crypto, const void *data, const size_t length, - heim_octet_string *ivec, + const heim_octet_string *ivec, heim_octet_string **ciphertext) { EVP_CIPHER_CTX evp; @@ -2021,20 +2043,10 @@ hx509_crypto_encrypt(hx509_crypto crypto, *ciphertext = NULL; + assert(EVP_CIPHER_iv_length(crypto->c) == ivec->length); + EVP_CIPHER_CTX_init(&evp); - ivec->length = EVP_CIPHER_iv_length(crypto->c); - ivec->data = malloc(ivec->length); - if (ivec->data == NULL) { - ret = ENOMEM; - goto out; - } - - if (RAND_bytes(ivec->data, ivec->length) <= 0) { - ret = HX509_CRYPTO_INTERNAL_ERROR; - goto out; - } - ret = EVP_CipherInit_ex(&evp, crypto->c, NULL, crypto->key.data, ivec->data, 1); if (ret != 1) { @@ -2082,10 +2094,6 @@ hx509_crypto_encrypt(hx509_crypto crypto, out: if (ret) { - if (ivec->data) { - free(ivec->data); - memset(ivec, 0, sizeof(*ivec)); - } if (*ciphertext) { if ((*ciphertext)->data) { free((*ciphertext)->data); @@ -2286,6 +2294,24 @@ find_string2key(const heim_oid *oid, return NULL; } +/* + * + */ + +int +_hx509_pbe_encrypt(hx509_context context, + hx509_lock lock, + const AlgorithmIdentifier *ai, + const heim_octet_string *content, + heim_octet_string *econtent) +{ + hx509_clear_error_string(context); + return EINVAL; +} + +/* + * + */ int _hx509_pbe_decrypt(hx509_context context, diff --git a/source/heimdal/lib/hx509/file.c b/source/heimdal/lib/hx509/file.c index 1152af2423c..b076b74f44d 100644 --- a/source/heimdal/lib/hx509/file.c +++ b/source/heimdal/lib/hx509/file.c @@ -134,3 +134,243 @@ _hx509_write_file(const char *fn, const void *data, size_t length) return 0; } + +/* + * + */ + +static void +header(FILE *f, const char *type, const char *str) +{ + fprintf(f, "-----%s %s-----\n", type, str); +} + +int +hx509_pem_write(hx509_context context, const char *type, + hx509_pem_header *headers, FILE *f, + const void *data, size_t size) +{ + const char *p = data; + size_t length; + char *line; + +#define ENCODE_LINE_LENGTH 54 + + header(f, "BEGIN", type); + + while (headers) { + fprintf(f, "%s: %s\n%s", + headers->header, headers->value, + headers->next ? "" : "\n"); + headers = headers->next; + } + + while (size > 0) { + ssize_t l; + + length = size; + if (length > ENCODE_LINE_LENGTH) + length = ENCODE_LINE_LENGTH; + + l = base64_encode(p, length, &line); + if (l < 0) { + hx509_set_error_string(context, 0, ENOMEM, + "malloc - out of memory"); + return ENOMEM; + } + size -= length; + fprintf(f, "%s\n", line); + p += length; + free(line); + } + + header(f, "END", type); + + return 0; +} + +/* + * + */ + +int +hx509_pem_add_header(hx509_pem_header **headers, + const char *header, const char *value) +{ + hx509_pem_header *h; + + h = calloc(1, sizeof(*h)); + if (h == NULL) + return ENOMEM; + h->header = strdup(header); + if (h->header == NULL) { + free(h); + return ENOMEM; + } + h->value = strdup(value); + if (h->value == NULL) { + free(h->header); + free(h); + return ENOMEM; + } + + h->next = *headers; + *headers = h; + + return 0; +} + +void +hx509_pem_free_header(hx509_pem_header *headers) +{ + hx509_pem_header *h; + while (headers) { + h = headers; + headers = headers->next; + free(h->header); + free(h->value); + free(h); + } +} + +/* + * + */ + +const char * +hx509_pem_find_header(const hx509_pem_header *h, const char *header) +{ + while(h) { + if (strcmp(header, h->header) == 0) + return h->value; + h = h->next; + } + return NULL; +} + + +/* + * + */ + +int +hx509_pem_read(hx509_context context, + FILE *f, + hx509_pem_read_func func, + void *ctx) +{ + hx509_pem_header *headers = NULL; + char *type = NULL; + void *data = NULL; + size_t len = 0; + char buf[1024]; + int ret = HX509_PARSING_KEY_FAILED; + + enum { BEFORE, SEARCHHEADER, INHEADER, INDATA, DONE } where; + + where = BEFORE; + + while (fgets(buf, sizeof(buf), f) != NULL) { + char *p; + int i; + + i = strcspn(buf, "\n"); + if (buf[i] == '\n') { + buf[i] = '\0'; + if (i > 0) + i--; + } + if (buf[i] == '\r') { + buf[i] = '\0'; + if (i > 0) + i--; + } + + switch (where) { + case BEFORE: + if (strncmp("-----BEGIN ", buf, 11) == 0) { + type = strdup(buf + 11); + if (type == NULL) + break; + p = strchr(type, '-'); + if (p) + *p = '\0'; + where = SEARCHHEADER; + } + break; + case SEARCHHEADER: + p = strchr(buf, ':'); + if (p == NULL) { + where = INDATA; + goto indata; + } + /* FALLTHOUGH */ + case INHEADER: + if (buf[0] == '\0') { + where = INDATA; + break; + } + p = strchr(buf, ':'); + if (p) { + *p++ = '\0'; + while (isspace((int)*p)) + p++; + ret = hx509_pem_add_header(&headers, buf, p); + if (ret) + abort(); + } + break; + case INDATA: + indata: + + if (strncmp("-----END ", buf, 9) == 0) { + where = DONE; + break; + } + + p = emalloc(i); + i = base64_decode(buf, p); + if (i < 0) { + free(p); + goto out; + } + + data = erealloc(data, len + i); + memcpy(((char *)data) + len, p, i); + free(p); + len += i; + break; + case DONE: + abort(); + } + + if (where == DONE) { + ret = (*func)(context, type, headers, data, len, ctx); + out: + free(data); + data = NULL; + len = 0; + free(type); + type = NULL; + where = BEFORE; + hx509_pem_free_header(headers); + headers = NULL; + if (ret) + break; + } + } + + if (where != BEFORE) { + hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, + "File ends before end of PEM end tag"); + ret = HX509_PARSING_KEY_FAILED; + } + if (data) + free(data); + if (type) + free(type); + if (headers) + hx509_pem_free_header(headers); + + return ret; +} diff --git a/source/heimdal/lib/hx509/hx509-private.h b/source/heimdal/lib/hx509/hx509-private.h index 2763df957f6..451c3c89f2b 100644 --- a/source/heimdal/lib/hx509/hx509-private.h +++ b/source/heimdal/lib/hx509/hx509-private.h @@ -4,6 +4,10 @@ #include +#if !defined(__GNUC__) && !defined(__attribute__) +#define __attribute__(x) +#endif + int _hx509_Certificate_cmp ( const Certificate */*p*/, @@ -20,7 +24,8 @@ _hx509_Time2time_t (const Time */*t*/); void _hx509_abort ( const char */*fmt*/, - ...); + ...) + __attribute__ ((noreturn, format (printf, 1, 2))); int _hx509_calculate_path ( @@ -104,6 +109,9 @@ _hx509_certs_keys_get ( hx509_certs /*certs*/, hx509_private_key **/*keys*/); +hx509_certs +_hx509_certs_ref (hx509_certs /*certs*/); + int _hx509_check_key_usage ( hx509_context /*context*/, @@ -306,6 +314,14 @@ _hx509_pbe_decrypt ( const heim_octet_string */*econtent*/, heim_octet_string */*content*/); +int +_hx509_pbe_encrypt ( + hx509_context /*context*/, + hx509_lock /*lock*/, + const AlgorithmIdentifier */*ai*/, + const heim_octet_string */*content*/, + heim_octet_string */*econtent*/); + void _hx509_pi_printf ( int (*/*func*/)(void *, const char *), @@ -406,11 +422,35 @@ _hx509_request_add_email ( void _hx509_request_free (hx509_request */*req*/); +int +_hx509_request_get_SubjectPublicKeyInfo ( + hx509_context /*context*/, + hx509_request /*req*/, + SubjectPublicKeyInfo */*key*/); + +int +_hx509_request_get_name ( + hx509_context /*context*/, + hx509_request /*req*/, + hx509_name */*name*/); + int _hx509_request_init ( hx509_context /*context*/, hx509_request */*req*/); +int +_hx509_request_parse ( + hx509_context /*context*/, + const char */*path*/, + hx509_request */*req*/); + +int +_hx509_request_print ( + hx509_context /*context*/, + hx509_request /*req*/, + FILE */*f*/); + int _hx509_request_set_SubjectPublicKeyInfo ( hx509_context /*context*/, diff --git a/source/heimdal/lib/hx509/hx509-protos.h b/source/heimdal/lib/hx509/hx509-protos.h index ab312cdbdfd..71fb29d59dd 100644 --- a/source/heimdal/lib/hx509/hx509-protos.h +++ b/source/heimdal/lib/hx509/hx509-protos.h @@ -236,6 +236,13 @@ hx509_cert_init ( const Certificate */*c*/, hx509_cert */*cert*/); +int +hx509_cert_init_data ( + hx509_context /*context*/, + const void */*ptr*/, + size_t /*len*/, + hx509_cert */*cert*/); + int hx509_cert_keyusage_print ( hx509_context /*context*/, @@ -479,7 +486,7 @@ hx509_crypto_encrypt ( hx509_crypto /*crypto*/, const void */*data*/, const size_t /*length*/, - heim_octet_string */*ivec*/, + const heim_octet_string */*ivec*/, heim_octet_string **/*ciphertext*/); const heim_oid * @@ -507,6 +514,11 @@ hx509_crypto_init ( const char * hx509_crypto_provider (hx509_crypto /*crypto*/); +int +hx509_crypto_random_iv ( + hx509_crypto /*crypto*/, + heim_octet_string */*ivec*/); + int hx509_crypto_select ( const hx509_context /*context*/, @@ -740,6 +752,36 @@ hx509_peer_info_set_cms_algs ( const AlgorithmIdentifier */*val*/, size_t /*len*/); +int +hx509_pem_add_header ( + hx509_pem_header **/*headers*/, + const char */*header*/, + const char */*value*/); + +const char * +hx509_pem_find_header ( + const hx509_pem_header */*h*/, + const char */*header*/); + +void +hx509_pem_free_header (hx509_pem_header */*headers*/); + +int +hx509_pem_read ( + hx509_context /*context*/, + FILE */*f*/, + hx509_pem_read_func /*func*/, + void */*ctx*/); + +int +hx509_pem_write ( + hx509_context /*context*/, + const char */*type*/, + hx509_pem_header */*headers*/, + FILE */*f*/, + const void */*data*/, + size_t /*size*/); + void hx509_print_func ( hx509_vprint_func /*func*/, @@ -930,6 +972,11 @@ hx509_verify_attach_revoke ( hx509_verify_ctx /*ctx*/, hx509_revoke_ctx /*revoke_ctx*/); +void +hx509_verify_ctx_f_allow_default_trustanchors ( + hx509_verify_ctx /*ctx*/, + int /*boolean*/); + void hx509_verify_destroy_ctx (hx509_verify_ctx /*ctx*/); @@ -937,7 +984,8 @@ int hx509_verify_hostname ( hx509_context /*context*/, const hx509_cert /*cert*/, - int /*require_match*/, + int /*flags*/, + hx509_hostname_type /*type*/, const char */*hostname*/, const struct sockaddr */*sa*/, int /*sa_size*/); @@ -954,6 +1002,11 @@ hx509_verify_path ( hx509_cert /*cert*/, hx509_certs /*pool*/); +void +hx509_verify_set_max_depth ( + hx509_verify_ctx /*ctx*/, + unsigned int /*max_depth*/); + void hx509_verify_set_proxy_certificate ( hx509_verify_ctx /*ctx*/, diff --git a/source/heimdal/lib/hx509/hx509.h b/source/heimdal/lib/hx509/hx509.h index 664c12e045a..2f22cedfbc8 100644 --- a/source/heimdal/lib/hx509/hx509.h +++ b/source/heimdal/lib/hx509/hx509.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -/* $Id: hx509.h 20798 2007-06-02 03:28:55Z lha $ */ +/* $Id: hx509.h 21310 2007-06-25 18:26:06Z lha $ */ typedef struct hx509_cert_attribute_data *hx509_cert_attribute; typedef struct hx509_cert_data *hx509_cert; @@ -84,6 +84,16 @@ typedef struct hx509_octet_string_list { heim_octet_string *val; } hx509_octet_string_list; +typedef struct hx509_pem_header { + struct hx509_pem_header *next; + char *header; + char *value; +} hx509_pem_header; + +typedef int +(*hx509_pem_read_func)(hx509_context, const char *, const hx509_pem_header *, + const void *, size_t, void *ctx); + /* * Options passed to hx509_query_match_option. */ @@ -122,5 +132,12 @@ typedef enum { /* flags hx509_cms_create_signed* */ #define HX509_CMS_SIGATURE_DETACHED 1 +#define HX509_CMS_SIGATURE_ID_NAME 2 + +/* hx509_verify_hostname nametype */ +typedef enum { + HX509_HN_HOSTNAME = 0, + HX509_HN_DNSSRV +} hx509_hostname_type; #include diff --git a/source/heimdal/lib/hx509/hx_locl.h b/source/heimdal/lib/hx509/hx_locl.h index bfbee0943eb..145bfcc006d 100644 --- a/source/heimdal/lib/hx509/hx_locl.h +++ b/source/heimdal/lib/hx509/hx_locl.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -/* $Id: hx_locl.h 20930 2007-06-06 00:23:42Z lha $ */ +/* $Id: hx_locl.h 21083 2007-06-13 02:11:19Z lha $ */ #ifdef HAVE_CONFIG_H #include @@ -194,6 +194,6 @@ extern const AlgorithmIdentifier * _hx509_crypto_default_secret_alg; * Configurable options */ -#if 0 /* fdef __APPLE__*/ -#define HX509_DEFAULT_ANCHORS "KEYCHAIN:system" +#ifdef __APPLE__ +#define HX509_DEFAULT_ANCHORS "KEYCHAIN:system-anchors" #endif diff --git a/source/heimdal/lib/hx509/keyset.c b/source/heimdal/lib/hx509/keyset.c index 475835b9b09..7da5705a802 100644 --- a/source/heimdal/lib/hx509/keyset.c +++ b/source/heimdal/lib/hx509/keyset.c @@ -32,9 +32,10 @@ */ #include "hx_locl.h" -RCSID("$Id: keyset.c 20911 2007-06-05 03:41:17Z lha $"); +RCSID("$Id: keyset.c 21140 2007-06-18 21:24:19Z lha $"); struct hx509_certs_data { + int ref; struct hx509_keyset_ops *ops; void *ops_data; }; @@ -99,18 +100,20 @@ hx509_certs_init(hx509_context context, } ops = _hx509_ks_type(context, type); - free(type); if (ops == NULL) { hx509_set_error_string(context, 0, ENOENT, "Keyset type %s is not supported", type); + free(type); return ENOENT; } + free(type); c = calloc(1, sizeof(*c)); if (c == NULL) { hx509_clear_error_string(context); return ENOMEM; } c->ops = ops; + c->ref = 1; ret = (*ops->init)(context, c, &c->ops_data, flags, residue, lock); if (ret) { @@ -140,10 +143,26 @@ hx509_certs_store(hx509_context context, } +hx509_certs +_hx509_certs_ref(hx509_certs certs) +{ + if (certs->ref <= 0) + _hx509_abort("certs refcount <= 0"); + certs->ref++; + if (certs->ref == 0) + _hx509_abort("certs refcount == 0"); + return certs; +} + void hx509_certs_free(hx509_certs *certs) { if (*certs) { + if ((*certs)->ref <= 0) + _hx509_abort("refcount <= 0"); + if (--(*certs)->ref > 0) + return; + (*(*certs)->ops->free)(*certs, (*certs)->ops_data); free(*certs); *certs = NULL; diff --git a/source/heimdal/lib/hx509/ks_file.c b/source/heimdal/lib/hx509/ks_file.c index f9a35808805..269afd03b10 100644 --- a/source/heimdal/lib/hx509/ks_file.c +++ b/source/heimdal/lib/hx509/ks_file.c @@ -32,68 +32,16 @@ */ #include "hx_locl.h" -RCSID("$Id: ks_file.c 20776 2007-06-01 22:02:01Z lha $"); +RCSID("$Id: ks_file.c 21314 2007-06-25 18:45:07Z lha $"); + +typedef enum { USE_PEM, USE_DER } outformat; struct ks_file { hx509_certs certs; char *fn; + outformat format; }; -struct header { - char *header; - char *value; - struct header *next; -}; - -static int -add_headers(struct header **headers, const char *header, const char *value) -{ - struct header *h; - h = calloc(1, sizeof(*h)); - if (h == NULL) - return ENOMEM; - h->header = strdup(header); - if (h->header == NULL) { - free(h); - return ENOMEM; - } - h->value = strdup(value); - if (h->value == NULL) { - free(h->header); - free(h); - return ENOMEM; - } - - h->next = *headers; - *headers = h; - - return 0; -} - -static void -free_headers(struct header *headers) -{ - struct header *h; - while (headers) { - h = headers; - headers = headers->next; - free(h->header); - free(h->value); - free(h); - } -} - -static const char * -find_header(const struct header *headers, const char *header) -{ - while(headers) { - if (strcmp(header, headers->header) == 0) - return headers->value; - headers = headers->next; - } - return NULL; -} - /* * */ @@ -101,24 +49,13 @@ find_header(const struct header *headers, const char *header) static int parse_certificate(hx509_context context, const char *fn, struct hx509_collector *c, - const struct header *headers, + const hx509_pem_header *headers, const void *data, size_t len) { hx509_cert cert; - Certificate t; - size_t size; int ret; - ret = decode_Certificate(data, len, &t, &size); - if (ret) { - hx509_set_error_string(context, 0, ret, - "Failed to parse certificate in %s", - fn); - return ret; - } - - ret = hx509_cert_init(context, &t, &cert); - free_Certificate(&t); + ret = hx509_cert_init_data(context, data, len, &cert); if (ret) return ret; @@ -195,13 +132,13 @@ out: static int parse_rsa_private_key(hx509_context context, const char *fn, struct hx509_collector *c, - const struct header *headers, + const hx509_pem_header *headers, const void *data, size_t len) { int ret = 0; const char *enc; - enc = find_header(headers, "Proc-Type"); + enc = hx509_pem_find_header(headers, "Proc-Type"); if (enc) { const char *dek; char *type, *iv; @@ -229,7 +166,7 @@ parse_rsa_private_key(hx509_context context, const char *fn, return HX509_PARSING_KEY_FAILED; } - dek = find_header(headers, "DEK-Info"); + dek = hx509_pem_find_header(headers, "DEK-Info"); if (dek == NULL) { hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, "Encrypted RSA missing DEK-Info"); @@ -243,8 +180,14 @@ parse_rsa_private_key(hx509_context context, const char *fn, } iv = strchr(type, ','); - if (iv) - *iv++ = '\0'; + if (iv == NULL) { + free(type); + hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, + "IV missing"); + return HX509_PARSING_KEY_FAILED; + } + + *iv++ = '\0'; size = strlen(iv); ivdata = malloc(size); @@ -339,7 +282,7 @@ parse_rsa_private_key(hx509_context context, const char *fn, struct pem_formats { const char *name; int (*func)(hx509_context, const char *, struct hx509_collector *, - const struct header *, const void *, size_t); + const hx509_pem_header *, const void *, size_t); } formats[] = { { "CERTIFICATE", parse_certificate }, { "RSA PRIVATE KEY", parse_rsa_private_key } @@ -347,152 +290,27 @@ struct pem_formats { static int -parse_pem_file(hx509_context context, - const char *fn, - struct hx509_collector *c, - int *found_data) +pem_func(hx509_context context, const char *type, + const hx509_pem_header *header, + const void *data, size_t len, void *ctx) { - struct header *headers = NULL; - char *type = NULL; - void *data = NULL; - size_t len = 0; - char buf[1024]; - int ret; - FILE *f; + struct hx509_collector *c = ctx; + int ret, j; - - enum { BEFORE, SEARCHHEADER, INHEADER, INDATA, DONE } where; - - where = BEFORE; - *found_data = 0; - - if ((f = fopen(fn, "r")) == NULL) { - hx509_set_error_string(context, 0, ENOENT, - "Failed to open PEM file \"%s\": %s", - fn, strerror(errno)); - return ENOENT; - } - ret = 0; - - while (fgets(buf, sizeof(buf), f) != NULL) { - char *p; - int i; - - i = strcspn(buf, "\n"); - if (buf[i] == '\n') { - buf[i] = '\0'; - if (i > 0) - i--; - } - if (buf[i] == '\r') { - buf[i] = '\0'; - if (i > 0) - i--; - } - - switch (where) { - case BEFORE: - if (strncmp("-----BEGIN ", buf, 11) == 0) { - type = strdup(buf + 11); - if (type == NULL) - break; - p = strchr(type, '-'); - if (p) - *p = '\0'; - *found_data = 1; - where = SEARCHHEADER; - } + for (j = 0; j < sizeof(formats)/sizeof(formats[0]); j++) { + const char *q = formats[j].name; + if (strcasecmp(type, q) == 0) { + ret = (*formats[j].func)(context, NULL, c, header, data, len); break; - case SEARCHHEADER: - p = strchr(buf, ':'); - if (p == NULL) { - where = INDATA; - goto indata; - } - /* FALLTHOUGH */ - case INHEADER: - if (buf[0] == '\0') { - where = INDATA; - break; - } - p = strchr(buf, ':'); - if (p) { - *p++ = '\0'; - while (isspace((int)*p)) - p++; - add_headers(&headers, buf, p); - } - break; - case INDATA: - indata: - - if (strncmp("-----END ", buf, 9) == 0) { - where = DONE; - break; - } - - p = emalloc(i); - i = base64_decode(buf, p); - if (i < 0) { - free(p); - goto out; - } - - data = erealloc(data, len + i); - memcpy(((char *)data) + len, p, i); - free(p); - len += i; - break; - case DONE: - abort(); - } - - if (where == DONE) { - int j; - - for (j = 0; j < sizeof(formats)/sizeof(formats[0]); j++) { - const char *q = formats[j].name; - if (strcasecmp(type, q) == 0) { - ret = (*formats[j].func)(context, fn, c, - headers, data, len); - break; - } - } - if (j == sizeof(formats)/sizeof(formats[0])) { - ret = HX509_UNSUPPORTED_OPERATION; - hx509_set_error_string(context, 0, ret, - "Found no matching PEM format for %s", - type); - } - out: - free(data); - data = NULL; - len = 0; - free(type); - type = NULL; - where = BEFORE; - free_headers(headers); - headers = NULL; - if (ret) - break; } } - - fclose(f); - - if (where != BEFORE) { - hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, - "File ends before end of PEM end tag"); - ret = HX509_PARSING_KEY_FAILED; + if (j == sizeof(formats)/sizeof(formats[0])) { + ret = HX509_UNSUPPORTED_OPERATION; + hx509_set_error_string(context, 0, ret, + "Found no matching PEM format for %s", type); + return ret; } - if (data) - free(data); - if (type) - free(type); - if (headers) - free_headers(headers); - - return ret; + return 0; } /* @@ -500,9 +318,9 @@ parse_pem_file(hx509_context context, */ static int -file_init(hx509_context context, - hx509_certs certs, void **data, int flags, - const char *residue, hx509_lock lock) +file_init_common(hx509_context context, + hx509_certs certs, void **data, int flags, + const char *residue, hx509_lock lock, outformat format) { char *p, *pnext; struct ks_file *f = NULL; @@ -520,6 +338,7 @@ file_init(hx509_context context, hx509_clear_error_string(context); return ENOMEM; } + f->format = format; f->fn = strdup(residue); if (f->fn == NULL) { @@ -547,17 +366,26 @@ file_init(hx509_context context, goto out; for (p = f->fn; p != NULL; p = pnext) { - int found_data; + FILE *f; pnext = strchr(p, ','); if (pnext) *pnext++ = '\0'; - ret = parse_pem_file(context, p, c, &found_data); - if (ret) - goto out; - if (!found_data) { + if ((f = fopen(p, "r")) == NULL) { + ret = ENOENT; + hx509_set_error_string(context, 0, ret, + "Failed to open PEM file \"%s\": %s", + p, strerror(errno)); + goto out; + } + + ret = hx509_pem_read(context, f, pem_func, c); + fclose(f); + if (ret != 0 && ret != HX509_PARSING_KEY_FAILED) + goto out; + else if (ret == HX509_PARSING_KEY_FAILED) { size_t length; void *ptr; int i; @@ -605,6 +433,22 @@ out: return ret; } +static int +file_init_pem(hx509_context context, + hx509_certs certs, void **data, int flags, + const char *residue, hx509_lock lock) +{ + return file_init_common(context, certs, data, flags, residue, lock, USE_PEM); +} + +static int +file_init_der(hx509_context context, + hx509_certs certs, void **data, int flags, + const char *residue, hx509_lock lock) +{ + return file_init_common(context, certs, data, flags, residue, lock, USE_DER); +} + static int file_free(hx509_certs certs, void *data) { @@ -615,66 +459,15 @@ file_free(hx509_certs certs, void *data) return 0; } -static void -pem_header(FILE *f, const char *type, const char *str) -{ - fprintf(f, "-----%s %s-----\n", type, str); -} - -static int -dump_pem_file(hx509_context context, const char *header, - FILE *f, const void *data, size_t size) -{ - const char *p = data; - size_t length; - char *line; - -#define ENCODE_LINE_LENGTH 54 - - pem_header(f, "BEGIN", header); - - while (size > 0) { - ssize_t l; - - length = size; - if (length > ENCODE_LINE_LENGTH) - length = ENCODE_LINE_LENGTH; - - l = base64_encode(p, length, &line); - if (l < 0) { - hx509_set_error_string(context, 0, ENOMEM, - "malloc - out of memory"); - return ENOMEM; - } - size -= length; - fprintf(f, "%s\n", line); - p += length; - free(line); - } - - pem_header(f, "END", header); - - return 0; -} - -static int -store_private_key(hx509_context context, FILE *f, hx509_private_key key) -{ - heim_octet_string data; - int ret; - - ret = _hx509_private_key_export(context, key, &data); - if (ret == 0) - dump_pem_file(context, _hx509_private_pem_name(key), f, - data.data, data.length); - free(data.data); - return ret; -} +struct store_ctx { + FILE *f; + outformat format; +}; static int store_func(hx509_context context, void *ctx, hx509_cert c) { - FILE *f = (FILE *)ctx; + struct store_ctx *sc = ctx; heim_octet_string data; int ret; @@ -682,11 +475,26 @@ store_func(hx509_context context, void *ctx, hx509_cert c) if (ret) return ret; - dump_pem_file(context, "CERTIFICATE", f, data.data, data.length); - free(data.data); - - if (_hx509_cert_private_key_exportable(c)) - store_private_key(context, f, _hx509_cert_private_key(c)); + switch (sc->format) { + case USE_DER: + fwrite(data.data, data.length, 1, sc->f); + free(data.data); + break; + case USE_PEM: + hx509_pem_write(context, "CERTIFICATE", NULL, sc->f, + data.data, data.length); + free(data.data); + if (_hx509_cert_private_key_exportable(c)) { + hx509_private_key key = _hx509_cert_private_key(c); + ret = _hx509_private_key_export(context, key, &data); + if (ret) + break; + hx509_pem_write(context, _hx509_private_pem_name(key), NULL, sc->f, + data.data, data.length); + free(data.data); + } + break; + } return 0; } @@ -696,18 +504,19 @@ file_store(hx509_context context, hx509_certs certs, void *data, int flags, hx509_lock lock) { struct ks_file *f = data; - FILE *fh; + struct store_ctx sc; int ret; - fh = fopen(f->fn, "w"); - if (fh == NULL) { + sc.f = fopen(f->fn, "w"); + if (sc.f == NULL) { hx509_set_error_string(context, 0, ENOENT, "Failed to open file %s for writing"); return ENOENT; } + sc.format = f->format; - ret = hx509_certs_iter(context, f->certs, store_func, fh); - fclose(fh); + ret = hx509_certs_iter(context, f->certs, store_func, &sc); + fclose(sc.f); return ret; } @@ -767,7 +576,7 @@ file_addkey(hx509_context context, static struct hx509_keyset_ops keyset_file = { "FILE", 0, - file_init, + file_init_pem, file_store, file_free, file_add, @@ -780,8 +589,43 @@ static struct hx509_keyset_ops keyset_file = { file_addkey }; +static struct hx509_keyset_ops keyset_pemfile = { + "PEM-FILE", + 0, + file_init_pem, + file_store, + file_free, + file_add, + NULL, + file_iter_start, + file_iter, + file_iter_end, + NULL, + file_getkeys, + file_addkey +}; + +static struct hx509_keyset_ops keyset_derfile = { + "DER-FILE", + 0, + file_init_der, + file_store, + file_free, + file_add, + NULL, + file_iter_start, + file_iter, + file_iter_end, + NULL, + file_getkeys, + file_addkey +}; + + void _hx509_ks_file_register(hx509_context context) { _hx509_ks_register(context, &keyset_file); + _hx509_ks_register(context, &keyset_pemfile); + _hx509_ks_register(context, &keyset_derfile); } diff --git a/source/heimdal/lib/hx509/ks_keychain.c b/source/heimdal/lib/hx509/ks_keychain.c index 2f0f72cd147..33c4d6774b3 100644 --- a/source/heimdal/lib/hx509/ks_keychain.c +++ b/source/heimdal/lib/hx509/ks_keychain.c @@ -32,7 +32,7 @@ */ #include "hx_locl.h" -RCSID("$Id: ks_keychain.c 20945 2007-06-06 22:17:17Z lha $"); +RCSID("$Id: ks_keychain.c 21097 2007-06-16 07:00:49Z lha $"); #ifdef HAVE_FRAMEWORK_SECURITY @@ -254,6 +254,7 @@ set_private_key(hx509_context context, */ struct ks_keychain { + int anchors; SecKeychainRef keychain; }; @@ -263,7 +264,6 @@ keychain_init(hx509_context context, const char *residue, hx509_lock lock) { struct ks_keychain *ctx; - OSStatus ret; ctx = calloc(1, sizeof(*ctx)); if (ctx == NULL) { @@ -272,13 +272,20 @@ keychain_init(hx509_context context, } if (residue) { - if (strcasecmp(residue, "system") == 0) - residue = "/System/Library/Keychains/X509Anchors"; + if (strcasecmp(residue, "system-anchors") == 0) { + ctx->anchors = 1; + } else if (strncasecmp(residue, "FILE:", 5) == 0) { + OSStatus ret; - ret = SecKeychainOpen(residue, &ctx->keychain); - if (ret != noErr) { + ret = SecKeychainOpen(residue + 5, &ctx->keychain); + if (ret != noErr) { + hx509_set_error_string(context, 0, ENOENT, + "Failed to open %s", residue); + return ENOENT; + } + } else { hx509_set_error_string(context, 0, ENOENT, - "Failed to open %s", residue); + "Unknown subtype %s", residue); return ENOENT; } } @@ -307,6 +314,8 @@ keychain_free(hx509_certs certs, void *data) */ struct iter { + hx509_certs certs; + void *cursor; SecKeychainSearchRef searchRef; }; @@ -316,7 +325,6 @@ keychain_iter_start(hx509_context context, { struct ks_keychain *ctx = data; struct iter *iter; - OSStatus ret; iter = calloc(1, sizeof(*iter)); if (iter == NULL) { @@ -324,15 +332,66 @@ keychain_iter_start(hx509_context context, return ENOMEM; } - ret = SecKeychainSearchCreateFromAttributes(ctx->keychain, - kSecCertificateItemClass, - NULL, - &iter->searchRef); - if (ret) { - free(iter); - hx509_set_error_string(context, 0, ret, - "Failed to start search for attributes"); - return ENOMEM; + if (ctx->anchors) { + CFArrayRef anchors; + int ret; + int i; + + ret = hx509_certs_init(context, "MEMORY:ks-file-create", + 0, NULL, &iter->certs); + if (ret) { + free(iter); + return ret; + } + + ret = SecTrustCopyAnchorCertificates(&anchors); + if (ret != 0) { + hx509_certs_free(&iter->certs); + free(iter); + hx509_set_error_string(context, 0, ENOMEM, + "Can't get trust anchors from Keychain"); + return ENOMEM; + } + for (i = 0; i < CFArrayGetCount(anchors); i++) { + SecCertificateRef cr; + hx509_cert cert; + CSSM_DATA cssm; + + cr = (SecCertificateRef)CFArrayGetValueAtIndex(anchors, i); + + SecCertificateGetData(cr, &cssm); + + ret = hx509_cert_init_data(context, cssm.Data, cssm.Length, &cert); + if (ret) + continue; + + ret = hx509_certs_add(context, iter->certs, cert); + hx509_cert_free(cert); + } + CFRelease(anchors); + } + + if (iter->certs) { + int ret; + ret = hx509_certs_start_seq(context, iter->certs, &iter->cursor); + if (ret) { + hx509_certs_free(&iter->certs); + free(iter); + return ret; + } + } else { + OSStatus ret; + + ret = SecKeychainSearchCreateFromAttributes(ctx->keychain, + kSecCertificateItemClass, + NULL, + &iter->searchRef); + if (ret) { + free(iter); + hx509_set_error_string(context, 0, ret, + "Failed to start search for attributes"); + return ENOMEM; + } } *cursor = iter; @@ -349,15 +408,16 @@ keychain_iter(hx509_context context, { SecKeychainAttributeList *attrs = NULL; SecKeychainAttributeInfo attrInfo; - uint32 attrFormat = 0; + uint32 attrFormat[1] = { 0 }; SecKeychainItemRef itemRef; - SecItemAttr item; + SecItemAttr item[1]; struct iter *iter = cursor; - Certificate t; OSStatus ret; UInt32 len; void *ptr = NULL; - size_t size; + + if (iter->certs) + return hx509_certs_next_cert(context, iter->certs, iter->cursor, cert); *cert = NULL; @@ -371,26 +431,18 @@ keychain_iter(hx509_context context, * Pick out certificate and matching "keyid" */ - item = kSecPublicKeyHashItemAttr; + item[0] = kSecPublicKeyHashItemAttr; attrInfo.count = 1; - attrInfo.tag = &item; - attrInfo.format = &attrFormat; + attrInfo.tag = item; + attrInfo.format = attrFormat; ret = SecKeychainItemCopyAttributesAndData(itemRef, &attrInfo, NULL, &attrs, &len, &ptr); if (ret) return EINVAL; - - ret = decode_Certificate(ptr, len, &t, &size); - CFRelease(itemRef); - if (ret) { - hx509_set_error_string(context, 0, ret, "Failed to parse certificate"); - goto out; - } - ret = hx509_cert_init(context, &t, cert); - free_Certificate(&t); + ret = hx509_cert_init_data(context, ptr, len, cert); if (ret) goto out; @@ -449,7 +501,14 @@ keychain_iter_end(hx509_context context, { struct iter *iter = cursor; - CFRelease(iter->searchRef); + if (iter->certs) { + int ret; + ret = hx509_certs_end_seq(context, iter->certs, iter->cursor); + hx509_certs_free(&iter->certs); + } else { + CFRelease(iter->searchRef); + } + memset(iter, 0, sizeof(*iter)); free(iter); return 0; diff --git a/source/heimdal/lib/hx509/ks_p11.c b/source/heimdal/lib/hx509/ks_p11.c index 90c716213fd..b899005b333 100644 --- a/source/heimdal/lib/hx509/ks_p11.c +++ b/source/heimdal/lib/hx509/ks_p11.c @@ -32,7 +32,7 @@ */ #include "hx_locl.h" -RCSID("$Id: ks_p11.c 20920 2007-06-05 05:47:06Z lha $"); +RCSID("$Id: ks_p11.c 21085 2007-06-13 06:39:53Z lha $"); #ifdef HAVE_DLFCN_H #include #endif @@ -682,7 +682,6 @@ collect_cert(hx509_context context, { struct hx509_collector *collector = ptr; hx509_cert cert; - Certificate t; int ret; if ((CK_LONG)query[0].ulValueLen == -1 || @@ -691,16 +690,8 @@ collect_cert(hx509_context context, return 0; } - - ret = decode_Certificate(query[1].pValue, query[1].ulValueLen, - &t, NULL); - if (ret) { - hx509_clear_error_string(context); - return 0; - } - - ret = hx509_cert_init(context, &t, &cert); - free_Certificate(&t); + ret = hx509_cert_init_data(context, query[1].pValue, + query[1].ulValueLen, &cert); if (ret) return ret; diff --git a/source/heimdal/lib/hx509/ks_p12.c b/source/heimdal/lib/hx509/ks_p12.c index 5fddbd07def..12756e6c071 100644 --- a/source/heimdal/lib/hx509/ks_p12.c +++ b/source/heimdal/lib/hx509/ks_p12.c @@ -32,7 +32,7 @@ */ #include "hx_locl.h" -RCSID("$Id: ks_p12.c 20909 2007-06-05 03:09:13Z lha $"); +RCSID("$Id: ks_p12.c 21146 2007-06-18 21:37:25Z lha $"); struct ks_pkcs12 { hx509_certs certs; @@ -90,7 +90,7 @@ keyBag_parser(hx509_context context, &ki.privateKeyAlgorithm, NULL, &ki.privateKey, - &attr->attrValues); + os); free_PKCS8PrivateKeyInfo(&ki); return 0; } @@ -132,7 +132,6 @@ certBag_parser(hx509_context context, const PKCS12_Attributes *attrs) { heim_octet_string os; - Certificate t; hx509_cert cert; PKCS12_CertBag cb; int ret; @@ -154,16 +153,11 @@ certBag_parser(hx509_context context, if (ret) return ret; - ret = decode_Certificate(os.data, os.length, &t, NULL); + ret = hx509_cert_init_data(context, os.data, os.length, &cert); der_free_octet_string(&os); if (ret) return ret; - ret = hx509_cert_init(context, &t, &cert); - free_Certificate(&t); - if (ret) - return ret; - ret = _hx509_collector_certs_add(context, c, cert); if (ret) { hx509_cert_free(cert); @@ -437,7 +431,9 @@ p12_init(hx509_context context, out: _hx509_collector_free(c); - if (ret) { + if (ret && p12) { + if (p12->fn) + free(p12->fn); if (p12->certs) hx509_certs_free(&p12->certs); free(p12); diff --git a/source/heimdal/lib/hx509/req.c b/source/heimdal/lib/hx509/req.c index 34e3a4ea27c..d7a85e1cecd 100644 --- a/source/heimdal/lib/hx509/req.c +++ b/source/heimdal/lib/hx509/req.c @@ -33,7 +33,7 @@ #include "hx_locl.h" #include -RCSID("$Id: req.c 20934 2007-06-06 15:30:02Z lha $"); +RCSID("$Id: req.c 21344 2007-06-26 14:22:34Z lha $"); struct hx509_request_data { hx509_name name; @@ -84,6 +84,18 @@ _hx509_request_set_name(hx509_context context, return 0; } +int +_hx509_request_get_name(hx509_context context, + hx509_request req, + hx509_name *name) +{ + if (req->name == NULL) { + hx509_set_error_string(context, 0, EINVAL, "Request have no name"); + return EINVAL; + } + return hx509_name_copy(context, req->name, name); +} + int _hx509_request_set_SubjectPublicKeyInfo(hx509_context context, hx509_request req, @@ -93,6 +105,14 @@ _hx509_request_set_SubjectPublicKeyInfo(hx509_context context, return copy_SubjectPublicKeyInfo(key, &req->key); } +int +_hx509_request_get_SubjectPublicKeyInfo(hx509_context context, + hx509_request req, + SubjectPublicKeyInfo *key) +{ + return copy_SubjectPublicKeyInfo(&req->key, key); +} + int _hx509_request_add_eku(hx509_context context, hx509_request req, @@ -215,3 +235,91 @@ out: return ret; } + +int +_hx509_request_parse(hx509_context context, + const char *path, + hx509_request *req) +{ + CertificationRequest r; + CertificationRequestInfo *rinfo; + hx509_name subject; + size_t len, size; + void *p; + int ret; + + if (strncmp(path, "PKCS10:", 7) != 0) { + hx509_set_error_string(context, 0, HX509_UNSUPPORTED_OPERATION, + "unsupport type in %s", path); + return HX509_UNSUPPORTED_OPERATION; + } + path += 7; + + /* XXX PEM request */ + + ret = _hx509_map_file(path, &p, &len, NULL); + if (ret) { + hx509_set_error_string(context, 0, ret, "Failed to map file %s", path); + return ret; + } + + ret = decode_CertificationRequest(p, len, &r, &size); + _hx509_unmap_file(p, len); + if (ret) { + hx509_set_error_string(context, 0, ret, "Failed to decode %s", path); + return ret; + } + + ret = _hx509_request_init(context, req); + if (ret) { + free_CertificationRequest(&r); + return ret; + } + + rinfo = &r.certificationRequestInfo; + + ret = _hx509_request_set_SubjectPublicKeyInfo(context, *req, + &rinfo->subjectPKInfo); + if (ret) { + free_CertificationRequest(&r); + _hx509_request_free(req); + return ret; + } + + ret = _hx509_name_from_Name(&rinfo->subject, &subject); + if (ret) { + free_CertificationRequest(&r); + _hx509_request_free(req); + return ret; + } + ret = _hx509_request_set_name(context, *req, subject); + hx509_name_free(&subject); + free_CertificationRequest(&r); + if (ret) { + _hx509_request_free(req); + return ret; + } + + return 0; +} + + +int +_hx509_request_print(hx509_context context, hx509_request req, FILE *f) +{ + int ret; + + if (req->name) { + char *subject; + ret = hx509_name_to_string(req->name, &subject); + if (ret) { + hx509_set_error_string(context, 0, ret, "Failed to print name"); + return ret; + } + fprintf(f, "name: %s\n", subject); + free(subject); + } + + return 0; +} + diff --git a/source/heimdal/lib/hx509/revoke.c b/source/heimdal/lib/hx509/revoke.c index 0d477945c88..ddcb17ee38d 100644 --- a/source/heimdal/lib/hx509/revoke.c +++ b/source/heimdal/lib/hx509/revoke.c @@ -32,7 +32,7 @@ */ #include "hx_locl.h" -RCSID("$Id: revoke.c 20871 2007-06-03 21:22:51Z lha $"); +RCSID("$Id: revoke.c 21153 2007-06-18 21:55:46Z lha $"); struct revoke_crl { char *path; @@ -572,10 +572,10 @@ hx509_revoke_verify(hx509_context context, continue; } - for (i = 0; i < ocsp->ocsp.tbsResponseData.responses.len; i++) { + for (j = 0; j < ocsp->ocsp.tbsResponseData.responses.len; j++) { heim_octet_string os; - ret = der_heim_integer_cmp(&ocsp->ocsp.tbsResponseData.responses.val[i].certID.serialNumber, + ret = der_heim_integer_cmp(&ocsp->ocsp.tbsResponseData.responses.val[j].certID.serialNumber, &c->tbsCertificate.serialNumber); if (ret != 0) continue; @@ -594,13 +594,13 @@ hx509_revoke_verify(hx509_context context, ret = _hx509_verify_signature(context, NULL, - &ocsp->ocsp.tbsResponseData.responses.val[i].certID.hashAlgorithm, + &ocsp->ocsp.tbsResponseData.responses.val[j].certID.hashAlgorithm, &os, - &ocsp->ocsp.tbsResponseData.responses.val[i].certID.issuerKeyHash); + &ocsp->ocsp.tbsResponseData.responses.val[j].certID.issuerKeyHash); if (ret != 0) continue; - switch (ocsp->ocsp.tbsResponseData.responses.val[i].certStatus.element) { + switch (ocsp->ocsp.tbsResponseData.responses.val[j].certStatus.element) { case choice_OCSPCertStatus_good: break; case choice_OCSPCertStatus_revoked: @@ -609,13 +609,13 @@ hx509_revoke_verify(hx509_context context, } /* don't allow the update to be in the future */ - if (ocsp->ocsp.tbsResponseData.responses.val[i].thisUpdate > + if (ocsp->ocsp.tbsResponseData.responses.val[j].thisUpdate > now + context->ocsp_time_diff) continue; /* don't allow the next updte to be in the past */ - if (ocsp->ocsp.tbsResponseData.responses.val[i].nextUpdate) { - if (*ocsp->ocsp.tbsResponseData.responses.val[i].nextUpdate < now) + if (ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate) { + if (*ocsp->ocsp.tbsResponseData.responses.val[j].nextUpdate < now) continue; } else /* Should force a refetch, but can we ? */; @@ -1077,6 +1077,7 @@ hx509_crl_alloc(hx509_context context, hx509_crl *crl) if (ret) { free(*crl); *crl = NULL; + return ret; } (*crl)->expire = 0; return ret; diff --git a/source/heimdal/lib/krb5/crypto.c b/source/heimdal/lib/krb5/crypto.c index 93f3e44ba1c..12f75d0bcde 100644 --- a/source/heimdal/lib/krb5/crypto.c +++ b/source/heimdal/lib/krb5/crypto.c @@ -32,7 +32,7 @@ */ #include "krb5_locl.h" -RCSID("$Id: crypto.c 20981 2007-06-07 20:05:50Z lha $"); +RCSID("$Id: crypto.c 21130 2007-06-18 20:45:21Z lha $"); #undef CRYPTO_DEBUG #ifdef CRYPTO_DEBUG @@ -3162,8 +3162,9 @@ decrypt_internal_derived(krb5_context context, unsigned long l; checksum_sz = CHECKSUMSIZE(et->keyed_checksum); - if (len < checksum_sz) { - krb5_set_error_string(context, "Encrypted data shorter then checksum"); + if (len < checksum_sz + et->confoundersize) { + krb5_set_error_string(context, "Encrypted data shorter then " + "checksum + confunder"); return KRB5_BAD_MSIZE; } diff --git a/source/heimdal/lib/krb5/get_cred.c b/source/heimdal/lib/krb5/get_cred.c index 761224b82c8..8a0af23e408 100644 --- a/source/heimdal/lib/krb5/get_cred.c +++ b/source/heimdal/lib/krb5/get_cred.c @@ -33,7 +33,7 @@ #include -RCSID("$Id: get_cred.c 21004 2007-06-08 01:53:10Z lha $"); +RCSID("$Id: get_cred.c 21327 2007-06-26 10:54:15Z lha $"); /* * Take the `body' and encode it into `padata' using the credentials @@ -411,7 +411,6 @@ get_cred_kdc_usage(krb5_context context, krb5_keyblock *subkey = NULL; size_t len; Ticket second_ticket_data; - int send_to_kdc_flags = 0; METHOD_DATA padata; krb5_data_zero(&resp); @@ -511,11 +510,18 @@ get_cred_kdc_usage(krb5_context context, /* * Send and receive */ -again: - ret = krb5_sendto_kdc_flags (context, &enc, - &krbtgt->server->name.name_string.val[1], - &resp, - send_to_kdc_flags); + { + krb5_sendto_ctx stctx; + ret = krb5_sendto_ctx_alloc(context, &stctx); + if (ret) + return ret; + krb5_sendto_ctx_set_func(stctx, _krb5_kdc_retry, NULL); + + ret = krb5_sendto_context (context, stctx, &enc, + krbtgt->server->name.name_string.val[1], + &resp); + krb5_sendto_ctx_free(context, stctx); + } if(ret) goto out; @@ -550,12 +556,6 @@ again: } else if(krb5_rd_error(context, &resp, &error) == 0) { ret = krb5_error_from_rd_error(context, &error, in_creds); krb5_free_error_contents(context, &error); - - if (ret == KRB5KRB_ERR_RESPONSE_TOO_BIG && !(send_to_kdc_flags & KRB5_KRBHST_FLAGS_LARGE_MSG)) { - send_to_kdc_flags |= KRB5_KRBHST_FLAGS_LARGE_MSG; - krb5_data_free(&resp); - goto again; - } } else if(resp.data && ((char*)resp.data)[0] == 4) { ret = KRB5KRB_AP_ERR_V4_REPLY; krb5_clear_error_string(context); @@ -1191,6 +1191,10 @@ krb5_get_creds(krb5_context context, flags.b.forwardable = 1; if (options & KRB5_GC_NO_TRANSIT_CHECK) flags.b.disable_transited_check = 1; + if (options & KRB5_GC_CONSTRAINED_DELEGATION) { + flags.b.request_anonymous = 1; /* XXX ARGH confusion */ + flags.b.constrained_delegation = 1; + } tgts = NULL; ret = get_cred_from_kdc_flags(context, flags, ccache, @@ -1206,3 +1210,62 @@ krb5_get_creds(krb5_context context, krb5_cc_store_cred(context, ccache, *out_creds); return ret; } + +/* + * + */ + +krb5_error_code KRB5_LIB_FUNCTION +krb5_get_renewed_creds(krb5_context context, + krb5_creds *creds, + krb5_const_principal client, + krb5_ccache ccache, + const char *in_tkt_service) +{ + krb5_error_code ret; + krb5_kdc_flags flags; + krb5_creds in, *template; + + memset(&in, 0, sizeof(in)); + + ret = krb5_copy_principal(context, client, &in.client); + if (ret) + return ret; + + if (in_tkt_service) { + ret = krb5_parse_name(context, in_tkt_service, &in.server); + if (ret) { + krb5_free_principal(context, in.client); + return ret; + } + } else { + const char *realm = krb5_principal_get_realm(context, client); + + ret = krb5_make_principal(context, &in.server, realm, KRB5_TGS_NAME, + realm, NULL); + if (ret) { + krb5_free_principal(context, in.client); + return ret; + } + } + + flags.i = 0; + flags.b.renewable = flags.b.renew = 1; + + /* + * Get template from old credential cache for the same entry, if + * this failes, no worries. + */ + ret = krb5_get_credentials(context, KRB5_GC_CACHED, ccache, &in, &template); + if (ret == 0) { + flags.b.forwardable = template->flags.b.forwardable; + flags.b.proxiable = template->flags.b.proxiable; + krb5_free_creds (context, template); + } + + ret = krb5_get_kdc_cred(context, ccache, flags, NULL, NULL, &in, &creds); + krb5_free_principal(context, in.client); + krb5_free_principal(context, in.server); + + return ret; +} diff --git a/source/heimdal/lib/krb5/init_creds_pw.c b/source/heimdal/lib/krb5/init_creds_pw.c index a58435a9eaf..1676da3bd62 100644 --- a/source/heimdal/lib/krb5/init_creds_pw.c +++ b/source/heimdal/lib/krb5/init_creds_pw.c @@ -33,7 +33,7 @@ #include "krb5_locl.h" -RCSID("$Id: init_creds_pw.c 20262 2007-02-18 00:33:01Z lha $"); +RCSID("$Id: init_creds_pw.c 21061 2007-06-12 17:56:30Z lha $"); typedef struct krb5_get_init_creds_ctx { KDCOptions flags; @@ -1221,8 +1221,8 @@ init_cred_loop(krb5_context context, krb5_data resp; size_t len; size_t size; - int send_to_kdc_flags = 0; krb5_krbhst_info *hi = NULL; + krb5_sendto_ctx stctx = NULL; memset(&md, 0, sizeof(md)); @@ -1238,6 +1238,11 @@ init_cred_loop(krb5_context context, if (ret) return ret; + ret = krb5_sendto_ctx_alloc(context, &stctx); + if (ret) + goto out; + krb5_sendto_ctx_set_func(stctx, _krb5_kdc_retry, NULL); + /* Set a new nonce. */ krb5_generate_random_block (&ctx->nonce, sizeof(ctx->nonce)); ctx->nonce &= 0xffffffff; @@ -1281,10 +1286,9 @@ init_cred_loop(krb5_context context, if(len != ctx->req_buffer.length) krb5_abortx(context, "internal error in ASN.1 encoder"); - ret = krb5_sendto_kdc_flags (context, &ctx->req_buffer, - &creds->client->realm, &resp, - send_to_kdc_flags); - if (ret) + ret = krb5_sendto_context (context, stctx, &ctx->req_buffer, + creds->client->realm, &resp); + if (ret) goto out; memset (&rep, 0, sizeof(rep)); @@ -1329,16 +1333,6 @@ init_cred_loop(krb5_context context, krb5_free_error_contents(context, &error); if (ret) goto out; - } else if (ret == KRB5KRB_ERR_RESPONSE_TOO_BIG) { - if (send_to_kdc_flags & KRB5_KRBHST_FLAGS_LARGE_MSG) { - if (ret_as_reply) - rep.error = error; - else - krb5_free_error_contents(context, &error); - goto out; - } - krb5_free_error_contents(context, &error); - send_to_kdc_flags |= KRB5_KRBHST_FLAGS_LARGE_MSG; } else { _krb5_get_init_creds_opt_set_krb5_error(context, init_cred_opts, @@ -1437,6 +1431,8 @@ init_cred_loop(krb5_context context, } } out: + if (stctx) + krb5_sendto_ctx_free(context, stctx); krb5_data_free(&ctx->req_buffer); free_METHOD_DATA(&md); memset(&md, 0, sizeof(md)); diff --git a/source/heimdal/lib/krb5/krb5-private.h b/source/heimdal/lib/krb5/krb5-private.h index be718f67143..a551c42ecd1 100644 --- a/source/heimdal/lib/krb5/krb5-private.h +++ b/source/heimdal/lib/krb5/krb5-private.h @@ -149,6 +149,14 @@ _krb5_kcm_noop ( krb5_context /*context*/, krb5_ccache /*id*/); +krb5_error_code +_krb5_kdc_retry ( + krb5_context /*context*/, + krb5_sendto_ctx /*ctx*/, + void */*data*/, + const krb5_data */*reply*/, + int */*action*/); + krb5_error_code KRB5_LIB_FUNCTION _krb5_krb_cr_err_reply ( krb5_context /*context*/, diff --git a/source/heimdal/lib/krb5/krb5-protos.h b/source/heimdal/lib/krb5/krb5-protos.h index e852bffeb1a..058496434e0 100644 --- a/source/heimdal/lib/krb5/krb5-protos.h +++ b/source/heimdal/lib/krb5/krb5-protos.h @@ -2243,6 +2243,14 @@ krb5_get_pw_salt ( krb5_const_principal /*principal*/, krb5_salt */*salt*/); +krb5_error_code KRB5_LIB_FUNCTION +krb5_get_renewed_creds ( + krb5_context /*context*/, + krb5_creds */*creds*/, + krb5_const_principal /*client*/, + krb5_ccache /*ccache*/, + const char */*in_tkt_service*/); + krb5_error_code KRB5_LIB_FUNCTION krb5_get_server_rcache ( krb5_context /*context*/, @@ -2868,6 +2876,12 @@ krb5_parse_name_flags ( int /*flags*/, krb5_principal */*principal*/); +krb5_error_code +krb5_parse_nametype ( + krb5_context /*context*/, + const char */*str*/, + int32_t */*nametype*/); + const char* KRB5_LIB_FUNCTION krb5_passwd_result_to_string ( krb5_context /*context*/, @@ -3071,7 +3085,7 @@ krb5_rd_cred2 ( krb5_error_code KRB5_LIB_FUNCTION krb5_rd_error ( krb5_context /*context*/, - krb5_data */*msg*/, + const krb5_data */*msg*/, KRB_ERROR */*result*/); krb5_error_code KRB5_LIB_FUNCTION @@ -3346,6 +3360,43 @@ krb5_sendto ( krb5_krbhst_handle /*handle*/, krb5_data */*receive*/); +krb5_error_code KRB5_LIB_FUNCTION +krb5_sendto_context ( + krb5_context /*context*/, + krb5_sendto_ctx /*ctx*/, + const krb5_data */*send_data*/, + const krb5_realm /*realm*/, + krb5_data */*receive*/); + +void KRB5_LIB_FUNCTION +krb5_sendto_ctx_add_flags ( + krb5_sendto_ctx /*ctx*/, + int /*flags*/); + +krb5_error_code KRB5_LIB_FUNCTION +krb5_sendto_ctx_alloc ( + krb5_context /*context*/, + krb5_sendto_ctx */*ctx*/); + +void KRB5_LIB_FUNCTION +krb5_sendto_ctx_free ( + krb5_context /*context*/, + krb5_sendto_ctx /*ctx*/); + +int KRB5_LIB_FUNCTION +krb5_sendto_ctx_get_flags (krb5_sendto_ctx /*ctx*/); + +void KRB5_LIB_FUNCTION +krb5_sendto_ctx_set_func ( + krb5_sendto_ctx /*ctx*/, + krb5_sendto_ctx_func /*func*/, + void */*data*/); + +void KRB5_LIB_FUNCTION +krb5_sendto_ctx_set_type ( + krb5_sendto_ctx /*ctx*/, + int /*type*/); + krb5_error_code KRB5_LIB_FUNCTION krb5_sendto_kdc ( krb5_context /*context*/, diff --git a/source/heimdal/lib/krb5/krb5.h b/source/heimdal/lib/krb5/krb5.h index eefda81ca90..345fe70764f 100644 --- a/source/heimdal/lib/krb5/krb5.h +++ b/source/heimdal/lib/krb5/krb5.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. */ -/* $Id: krb5.h 20245 2007-02-17 00:09:57Z lha $ */ +/* $Id: krb5.h 21252 2007-06-21 04:18:28Z lha $ */ #ifndef __KRB5_H__ #define __KRB5_H__ @@ -361,6 +361,7 @@ typedef union { #define KRB5_GC_NO_STORE (1U << 3) #define KRB5_GC_FORWARDABLE (1U << 4) #define KRB5_GC_NO_TRANSIT_CHECK (1U << 5) +#define KRB5_GC_CONSTRAINED_DELEGATION (1U << 6) /* constants for compare_creds (and cc_retrieve_cred) */ #define KRB5_TC_DONT_MATCH_REALM (1U << 31) @@ -753,9 +754,18 @@ enum { /* flags for krb5_unparse_name_flags */ enum { KRB5_PRINCIPAL_UNPARSE_SHORT = 1, - KRB5_PRINCIPAL_UNPARSE_NO_REALM = 2 + KRB5_PRINCIPAL_UNPARSE_NO_REALM = 2, + KRB5_PRINCIPAL_UNPARSE_DISPLAY = 4 }; +typedef struct krb5_sendto_ctx *krb5_sendto_ctx; + +#define KRB5_SENDTO_DONE 0 +#define KRB5_SENDTO_RESTART 1 +#define KRB5_SENDTO_CONTINUE 2 + +typedef krb5_error_code (*krb5_sendto_ctx_func)(krb5_context, krb5_sendto_ctx, void *, const krb5_data *, int *); + struct credentials; /* this is to keep the compiler happy */ struct getargs; struct sockaddr; diff --git a/source/heimdal/lib/krb5/krb5_err.et b/source/heimdal/lib/krb5/krb5_err.et index 785c258ee0c..6714401e450 100644 --- a/source/heimdal/lib/krb5/krb5_err.et +++ b/source/heimdal/lib/krb5/krb5_err.et @@ -3,7 +3,7 @@ # # This might look like a com_err file, but is not # -id "$Id: krb5_err.et 20760 2007-06-01 03:24:49Z lha $" +id "$Id: krb5_err.et 21050 2007-06-12 02:00:40Z lha $" error_table krb5 @@ -35,8 +35,10 @@ error_code KEY_EXPIRED, "Password has expired" error_code PREAUTH_FAILED, "Preauthentication failed" error_code PREAUTH_REQUIRED, "Additional pre-authentication required" error_code SERVER_NOMATCH, "Requested server and ticket don't match" +error_code KDC_ERR_MUST_USE_USER2USER, "Server principal valid for user2user only" +error_code PATH_NOT_ACCEPTED, "KDC Policy rejects transited path" +error_code SVC_UNAVAILABLE, "A service is not available" -# 27-30 are reserved index 31 prefix KRB5KRB_AP error_code ERR_BAD_INTEGRITY, "Decrypt integrity check failed" @@ -108,7 +110,7 @@ error_code PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED, "Public key encryption not suppo index 128 prefix -error_code KRB5_ERR_RCSID, "$Id: krb5_err.et 20760 2007-06-01 03:24:49Z lha $" +error_code KRB5_ERR_RCSID, "$Id: krb5_err.et 21050 2007-06-12 02:00:40Z lha $" error_code KRB5_LIBOS_BADLOCKFLAG, "Invalid flag for file lock mode" error_code KRB5_LIBOS_CANTREADPWD, "Cannot read password" diff --git a/source/heimdal/lib/krb5/krbhst.c b/source/heimdal/lib/krb5/krbhst.c index 51bf934bfd1..69b52dd808c 100644 --- a/source/heimdal/lib/krb5/krbhst.c +++ b/source/heimdal/lib/krb5/krbhst.c @@ -35,7 +35,7 @@ #include #include "locate_plugin.h" -RCSID("$Id: krbhst.c 19198 2006-11-30 17:23:08Z lha $"); +RCSID("$Id: krbhst.c 21131 2007-06-18 20:48:09Z lha $"); static int string_to_proto(const char *string) @@ -501,10 +501,8 @@ add_locate(void *ctx, int type, struct sockaddr *addr) hostlen = strlen(host); hi = calloc(1, sizeof(*hi) + hostlen); - if(hi == NULL) { - free(host); + if(hi == NULL) return ENOMEM; - } hi->proto = krbhst_get_default_proto(kd); hi->port = hi->def_port = socket_get_port(addr); diff --git a/source/heimdal/lib/krb5/misc.c b/source/heimdal/lib/krb5/misc.c index 0d410b57d21..8050bdb9b46 100644 --- a/source/heimdal/lib/krb5/misc.c +++ b/source/heimdal/lib/krb5/misc.c @@ -33,7 +33,7 @@ #include "krb5_locl.h" -RCSID("$Id: misc.c 17616 2006-06-06 14:57:47Z lha $"); +RCSID("$Id: misc.c 21174 2007-06-19 10:10:58Z lha $"); krb5_error_code KRB5_LIB_FUNCTION _krb5_s4u2self_to_checksumdata(krb5_context context, @@ -51,6 +51,7 @@ _krb5_s4u2self_to_checksumdata(krb5_context context, krb5_clear_error_string(context); return ENOMEM; } + krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); ret = krb5_store_int32(sp, self->name.name_type); if (ret) goto out; diff --git a/source/heimdal/lib/krb5/pac.c b/source/heimdal/lib/krb5/pac.c index 55d4f5ff564..f7a5e83ea34 100644 --- a/source/heimdal/lib/krb5/pac.c +++ b/source/heimdal/lib/krb5/pac.c @@ -33,7 +33,7 @@ #include "krb5_locl.h" -RCSID("$Id: pac.c 20845 2007-06-03 14:31:16Z lha $"); +RCSID("$Id: pac.c 21149 2007-06-18 21:50:22Z lha $"); struct PAC_INFO_BUFFER { uint32_t type; @@ -409,6 +409,8 @@ verify_checksum(krb5_context context, krb5_error_code ret; Checksum cksum; + memset(&cksum, 0, sizeof(cksum)); + sp = krb5_storage_from_mem((char *)data->data + sig->offset_lo, sig->buffersize); if (sp == NULL) { diff --git a/source/heimdal/lib/krb5/pkinit.c b/source/heimdal/lib/krb5/pkinit.c index dd828420847..105cab554d8 100755 --- a/source/heimdal/lib/krb5/pkinit.c +++ b/source/heimdal/lib/krb5/pkinit.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003 - 2006 Kungliga Tekniska Högskolan + * Copyright (c) 2003 - 2007 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -33,7 +33,7 @@ #include "krb5_locl.h" -RCSID("$Id: pkinit.c 21004 2007-06-08 01:53:10Z lha $"); +RCSID("$Id: pkinit.c 21321 2007-06-26 05:21:56Z lha $"); struct krb5_dh_moduli { char *name; @@ -554,18 +554,13 @@ pk_mk_padata(krb5_context context, if (ret) goto out; - ret = _krb5_pk_mk_ContentInfo(context, &sd_buf, oid_id_pkcs7_signedData(), - &content_info); + ret = hx509_cms_wrap_ContentInfo(oid_id_pkcs7_signedData(), &sd_buf, &buf); krb5_data_free(&sd_buf); - if (ret) + if (ret) { + krb5_set_error_string(context, + "ContentInfo wrapping of signedData failed"); goto out; - - ASN1_MALLOC_ENCODE(ContentInfo, buf.data, buf.length, - &content_info, &size, ret); - if (ret) - goto out; - if (buf.length != size) - krb5_abortx(context, "Internal ASN1 encoder error"); + } if (ctx->type == COMPAT_WIN2K) { PA_PK_AS_REQ_Win2k winreq; @@ -794,6 +789,7 @@ get_reply_key_win(krb5_context context, if (ret) { krb5_set_error_string(context, "PKINIT failed copying reply key"); free(*key); + *key = NULL; } return ret; @@ -856,6 +852,7 @@ get_reply_key(krb5_context context, if (ret) { krb5_set_error_string(context, "PKINIT failed copying reply key"); free(*key); + *key = NULL; } return ret; @@ -929,6 +926,7 @@ pk_verify_host(krb5_context context, if (hi) { ret = hx509_verify_hostname(ctx->id->hx509ctx, host->cert, ctx->require_hostname_match, + HX509_HN_HOSTNAME, hi->hostname, hi->ai->ai_addr, hi->ai->ai_addrlen); @@ -942,7 +940,8 @@ pk_verify_host(krb5_context context, static krb5_error_code pk_rd_pa_reply_enckey(krb5_context context, int type, - const ContentInfo *rep, + const heim_octet_string *indata, + const heim_oid *dataType, const char *realm, krb5_pk_init_ctx ctx, krb5_enctype etype, @@ -954,27 +953,19 @@ pk_rd_pa_reply_enckey(krb5_context context, { krb5_error_code ret; struct krb5_pk_cert *host = NULL; - size_t size; - int length; - void *p; krb5_data content; heim_oid contentType = { 0, NULL }; - if (der_heim_oid_cmp(oid_id_pkcs7_envelopedData(), &rep->contentType)) { + if (der_heim_oid_cmp(oid_id_pkcs7_envelopedData(), dataType)) { krb5_set_error_string(context, "PKINIT: Invalid content type"); return EINVAL; } - if (rep->content == NULL) { - krb5_set_error_string(context, "PKINIT: No content in reply"); - return EINVAL; - } - ret = hx509_cms_unenvelope(ctx->id->hx509ctx, ctx->id->certs, HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT, - rep->content->data, - rep->content->length, + indata->data, + indata->length, NULL, &contentType, &content); @@ -983,41 +974,52 @@ pk_rd_pa_reply_enckey(krb5_context context, "Failed to unenvelope CMS data in PK-INIT reply"); return ret; } + der_free_oid(&contentType); - p = content.data; - length = content.length; +#if 0 /* windows LH with interesting CMS packets, leaks memory */ + { + size_t ph = 1 + der_length_len (length); + unsigned char *ptr = malloc(length + ph); + size_t l; + + memcpy(ptr + ph, p, length); + + ret = der_put_length_and_tag (ptr + ph - 1, ph, length, + ASN1_C_UNIV, CONS, UT_Sequence, &l); + if (ret) + return ret; + ptr += ph - l; + length += l; + p = ptr; + } +#endif /* win2k uses ContentInfo */ if (type == COMPAT_WIN2K) { - ContentInfo ci; + heim_oid type; + heim_octet_string out; - ret = decode_ContentInfo(p, length, &ci, &size); - if (ret) { - krb5_set_error_string(context, - "PKINIT: failed decoding ContentInfo: %d", - ret); - goto out; - } - - if (der_heim_oid_cmp(&ci.contentType, oid_id_pkcs7_signedData())) { - ret = EINVAL; /* XXX */ - krb5_set_error_string(context, "PKINIT: Invalid content type"); - goto out; - } - if (ci.content == NULL) { + ret = hx509_cms_unwrap_ContentInfo(&content, &type, &out, NULL); + if (der_heim_oid_cmp(&type, oid_id_pkcs7_signedData())) { ret = EINVAL; /* XXX */ krb5_set_error_string(context, "PKINIT: Invalid content type"); + der_free_oid(&type); + der_free_octet_string(&out); goto out; } + der_free_oid(&type); krb5_data_free(&content); - content = *ci.content; - p = ci.content->data; - length = ci.content->length; + ret = krb5_data_copy(&content, out.data, out.length); + der_free_octet_string(&out); + if (ret) { + krb5_set_error_string(context, "PKINIT: out of memory"); + goto out; + } } ret = _krb5_pk_verify_sign(context, - p, - length, + content.data, + content.length, ctx->id, &contentType, &content, @@ -1073,7 +1075,8 @@ pk_rd_pa_reply_enckey(krb5_context context, static krb5_error_code pk_rd_pa_reply_dh(krb5_context context, - const ContentInfo *rep, + const heim_octet_string *indata, + const heim_oid *dataType, const char *realm, krb5_pk_init_ctx ctx, krb5_enctype etype, @@ -1097,19 +1100,14 @@ pk_rd_pa_reply_dh(krb5_context context, krb5_data_zero(&content); memset(&kdc_dh_info, 0, sizeof(kdc_dh_info)); - if (der_heim_oid_cmp(oid_id_pkcs7_signedData(), &rep->contentType)) { + if (der_heim_oid_cmp(oid_id_pkcs7_signedData(), dataType)) { krb5_set_error_string(context, "PKINIT: Invalid content type"); return EINVAL; } - if (rep->content == NULL) { - krb5_set_error_string(context, "PKINIT: No content in reply"); - return EINVAL; - } - ret = _krb5_pk_verify_sign(context, - rep->content->data, - rep->content->length, + indata->data, + indata->length, ctx->id, &contentType, &content, @@ -1261,20 +1259,19 @@ _krb5_pk_rd_pa_reply(krb5_context context, { krb5_pk_init_ctx ctx = c; krb5_error_code ret; - ContentInfo ci; size_t size; /* Check for IETF PK-INIT first */ if (ctx->type == COMPAT_IETF) { PA_PK_AS_REP rep; + heim_octet_string os, data; + heim_oid oid; if (pa->padata_type != KRB5_PADATA_PK_AS_REP) { krb5_set_error_string(context, "PKINIT: wrong padata recv"); return EINVAL; } - memset(&rep, 0, sizeof(rep)); - ret = decode_PA_PK_AS_REP(pa->padata_value.data, pa->padata_value.length, &rep, @@ -1286,50 +1283,43 @@ _krb5_pk_rd_pa_reply(krb5_context context, switch (rep.element) { case choice_PA_PK_AS_REP_dhInfo: - ret = decode_ContentInfo(rep.u.dhInfo.dhSignedData.data, - rep.u.dhInfo.dhSignedData.length, - &ci, - &size); - if (ret) { - krb5_set_error_string(context, - "PKINIT: decoding failed DH " - "ContentInfo: %d", ret); - - free_PA_PK_AS_REP(&rep); - break; - } - ret = pk_rd_pa_reply_dh(context, &ci, realm, ctx, etype, hi, - ctx->clientDHNonce, - rep.u.dhInfo.serverDHNonce, - nonce, pa, key); - free_ContentInfo(&ci); - free_PA_PK_AS_REP(&rep); - + os = rep.u.dhInfo.dhSignedData; break; case choice_PA_PK_AS_REP_encKeyPack: - ret = decode_ContentInfo(rep.u.encKeyPack.data, - rep.u.encKeyPack.length, - &ci, - &size); - free_PA_PK_AS_REP(&rep); - if (ret) { - krb5_set_error_string(context, - "PKINIT: -25 decoding failed " - "ContentInfo: %d", ret); - break; - } - ret = pk_rd_pa_reply_enckey(context, COMPAT_IETF, &ci, realm, ctx, - etype, hi, nonce, req_buffer, pa, key); - free_ContentInfo(&ci); - return ret; + os = rep.u.encKeyPack; + break; default: free_PA_PK_AS_REP(&rep); krb5_set_error_string(context, "PKINIT: -27 reply " "invalid content type"); - ret = EINVAL; - break; + return EINVAL; } + ret = hx509_cms_unwrap_ContentInfo(&os, &oid, &data, NULL); + if (ret) { + free_PA_PK_AS_REP(&rep); + krb5_set_error_string(context, "PKINIT: failed to unwrap CI"); + return ret; + } + + switch (rep.element) { + case choice_PA_PK_AS_REP_dhInfo: + ret = pk_rd_pa_reply_dh(context, &data, &oid, realm, ctx, etype, hi, + ctx->clientDHNonce, + rep.u.dhInfo.serverDHNonce, + nonce, pa, key); + break; + case choice_PA_PK_AS_REP_encKeyPack: + ret = pk_rd_pa_reply_enckey(context, COMPAT_IETF, &data, &oid, realm, + ctx, etype, hi, nonce, req_buffer, pa, key); + break; + default: + krb5_abortx(context, "pk-init as-rep case not possible to happen"); + } + der_free_octet_string(&data); + der_free_oid(&oid); + free_PA_PK_AS_REP(&rep); + } else if (ctx->type == COMPAT_WIN2K) { PA_PK_AS_REP_Win2k w2krep; @@ -1357,23 +1347,25 @@ _krb5_pk_rd_pa_reply(krb5_context context, krb5_clear_error_string(context); switch (w2krep.element) { - case choice_PA_PK_AS_REP_Win2k_encKeyPack: - ret = decode_ContentInfo(w2krep.u.encKeyPack.data, - w2krep.u.encKeyPack.length, - &ci, - &size); + case choice_PA_PK_AS_REP_Win2k_encKeyPack: { + heim_octet_string data; + heim_oid oid; + + ret = hx509_cms_unwrap_ContentInfo(&w2krep.u.encKeyPack, + &oid, &data, NULL); free_PA_PK_AS_REP_Win2k(&w2krep); if (ret) { - krb5_set_error_string(context, - "PKINIT: decoding failed " - "ContentInfo: %d", - ret); + krb5_set_error_string(context, "PKINIT: failed to unwrap CI"); return ret; } - ret = pk_rd_pa_reply_enckey(context, COMPAT_WIN2K, &ci, realm, ctx, - etype, hi, nonce, req_buffer, pa, key); - free_ContentInfo(&ci); + + ret = pk_rd_pa_reply_enckey(context, COMPAT_WIN2K, &data, &oid, realm, + ctx, etype, hi, nonce, req_buffer, pa, key); + der_free_octet_string(&data); + der_free_oid(&oid); + break; + } default: free_PA_PK_AS_REP_Win2k(&w2krep); krb5_set_error_string(context, "PKINIT: win2k reply invalid " @@ -1473,8 +1465,7 @@ _krb5_pk_load_id(krb5_context context, id = calloc(1, sizeof(*id)); if (id == NULL) { krb5_set_error_string(context, "malloc: out of memory"); - ret = ENOMEM; - goto out; + return ENOMEM; } ret = hx509_context_init(&id->hx509ctx); diff --git a/source/heimdal/lib/krb5/plugin.c b/source/heimdal/lib/krb5/plugin.c index f19464bf3c8..68317a12c0d 100644 --- a/source/heimdal/lib/krb5/plugin.c +++ b/source/heimdal/lib/krb5/plugin.c @@ -32,7 +32,7 @@ */ #include "krb5_locl.h" -RCSID("$Id: plugin.c 19789 2007-01-09 17:46:01Z lha $"); +RCSID("$Id: plugin.c 21134 2007-06-18 21:02:23Z lha $"); #ifdef HAVE_DLFCN_H #include #endif @@ -96,6 +96,7 @@ loadlib(krb5_context context, (*e)->dsohandle = dlopen(lib, RTLD_LAZY); if ((*e)->dsohandle == NULL) { free(*e); + *e = NULL; krb5_set_error_string(context, "Failed to load %s: %s", lib, dlerror()); return ENOMEM; diff --git a/source/heimdal/lib/krb5/principal.c b/source/heimdal/lib/krb5/principal.c index ef3f5412db0..c1a29d266b6 100644 --- a/source/heimdal/lib/krb5/principal.c +++ b/source/heimdal/lib/krb5/principal.c @@ -41,7 +41,7 @@ #include #include "resolve.h" -RCSID("$Id: principal.c 20223 2007-02-15 04:17:04Z lha $"); +RCSID("$Id: principal.c 21285 2007-06-25 12:30:55Z lha $"); #define princ_num_comp(P) ((P)->name.name_string.len) #define princ_type(P) ((P)->name.name_type) @@ -281,15 +281,19 @@ krb5_parse_name(krb5_context context, static const char quotable_chars[] = " \n\t\b\\/@"; static const char replace_chars[] = " ntb\\/@"; +static const char nq_chars[] = " \\/@"; #define add_char(BASE, INDEX, LEN, C) do { if((INDEX) < (LEN)) (BASE)[(INDEX)++] = (C); }while(0); static size_t -quote_string(const char *s, char *out, size_t idx, size_t len) +quote_string(const char *s, char *out, size_t idx, size_t len, int display) { const char *p, *q; for(p = s; *p && idx < len; p++){ - if((q = strchr(quotable_chars, *p))){ + q = strchr(quotable_chars, *p); + if (q && display) { + add_char(out, idx, len, replace_chars[q - quotable_chars]); + } else if (q) { add_char(out, idx, len, '\\'); add_char(out, idx, len, replace_chars[q - quotable_chars]); }else @@ -312,6 +316,7 @@ unparse_name_fixed(krb5_context context, int i; int short_form = (flags & KRB5_PRINCIPAL_UNPARSE_SHORT) != 0; int no_realm = (flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) != 0; + int display = (flags & KRB5_PRINCIPAL_UNPARSE_DISPLAY) != 0; if (!no_realm && princ_realm(principal) == NULL) { krb5_set_error_string(context, "Realm missing from principal, " @@ -322,7 +327,7 @@ unparse_name_fixed(krb5_context context, for(i = 0; i < princ_num_comp(principal); i++){ if(i) add_char(name, idx, len, '/'); - idx = quote_string(princ_ncomp(principal, i), name, idx, len); + idx = quote_string(princ_ncomp(principal, i), name, idx, len, display); if(idx == len) { krb5_set_error_string(context, "Out of space printing principal"); return ERANGE; @@ -341,7 +346,7 @@ unparse_name_fixed(krb5_context context, } if(!short_form && !no_realm) { add_char(name, idx, len, '@'); - idx = quote_string(princ_realm(principal), name, idx, len); + idx = quote_string(princ_realm(principal), name, idx, len, display); if(idx == len) { krb5_set_error_string(context, "Out of space printing realm of principal"); @@ -1213,3 +1218,37 @@ krb5_sname_to_principal (krb5_context context, krb5_free_host_realm(context, realms); return ret; } + +static const struct { + const char *type; + int32_t value; +} nametypes[] = { + { "UNKNOWN", KRB5_NT_UNKNOWN }, + { "PRINCIPAL", KRB5_NT_PRINCIPAL }, + { "SRV_INST", KRB5_NT_SRV_INST }, + { "SRV_HST", KRB5_NT_SRV_HST }, + { "SRV_XHST", KRB5_NT_SRV_XHST }, + { "UID", KRB5_NT_UID }, + { "X500_PRINCIPAL", KRB5_NT_X500_PRINCIPAL }, + { "SMTP_NAME", KRB5_NT_SMTP_NAME }, + { "ENTERPRISE_PRINCIPAL", KRB5_NT_ENTERPRISE_PRINCIPAL }, + { "ENT_PRINCIPAL_AND_ID", KRB5_NT_ENT_PRINCIPAL_AND_ID }, + { "MS_PRINCIPAL", KRB5_NT_MS_PRINCIPAL }, + { "MS_PRINCIPAL_AND_ID", KRB5_NT_MS_PRINCIPAL_AND_ID }, + { NULL } +}; + +krb5_error_code +krb5_parse_nametype(krb5_context context, const char *str, int32_t *nametype) +{ + size_t i; + + for(i = 0; nametypes[i].type; i++) { + if (strcasecmp(nametypes[i].type, str) == 0) { + *nametype = nametypes[i].value; + return 0; + } + } + krb5_set_error_string(context, "Failed to find name type %s", str); + return KRB5_PARSE_MALFORMED; +} diff --git a/source/heimdal/lib/krb5/rd_error.c b/source/heimdal/lib/krb5/rd_error.c index 89615ee8ac7..e7646467afd 100644 --- a/source/heimdal/lib/krb5/rd_error.c +++ b/source/heimdal/lib/krb5/rd_error.c @@ -33,11 +33,11 @@ #include "krb5_locl.h" -RCSID("$Id: rd_error.c 20304 2007-04-11 11:15:05Z lha $"); +RCSID("$Id: rd_error.c 21057 2007-06-12 17:22:31Z lha $"); krb5_error_code KRB5_LIB_FUNCTION krb5_rd_error(krb5_context context, - krb5_data *msg, + const krb5_data *msg, KRB_ERROR *result) { diff --git a/source/heimdal/lib/krb5/send_to_kdc.c b/source/heimdal/lib/krb5/send_to_kdc.c index 6c702443276..c1a4df2b01c 100644 --- a/source/heimdal/lib/krb5/send_to_kdc.c +++ b/source/heimdal/lib/krb5/send_to_kdc.c @@ -33,7 +33,7 @@ #include "krb5_locl.h" -RCSID("$Id: send_to_kdc.c 19973 2007-01-17 17:19:52Z lha $"); +RCSID("$Id: send_to_kdc.c 21062 2007-06-12 17:58:57Z lha $"); struct send_to_kdc { krb5_send_to_kdc_func func; @@ -413,26 +413,16 @@ krb5_sendto_kdc_flags(krb5_context context, int flags) { krb5_error_code ret; - krb5_krbhst_handle handle; - int type; + krb5_sendto_ctx ctx; - if ((flags & KRB5_KRBHST_FLAGS_MASTER) || context->use_admin_kdc) - type = KRB5_KRBHST_ADMIN; - else - type = KRB5_KRBHST_KDC; - - if (send_data->length > context->large_msg_size) - flags |= KRB5_KRBHST_FLAGS_LARGE_MSG; - - ret = krb5_krbhst_init_flags(context, *realm, type, flags, &handle); + ret = krb5_sendto_ctx_alloc(context, &ctx); if (ret) return ret; + krb5_sendto_ctx_add_flags(ctx, flags); + krb5_sendto_ctx_set_func(ctx, _krb5_kdc_retry, NULL); - ret = krb5_sendto(context, send_data, handle, receive); - krb5_krbhst_free(context, handle); - if (ret == KRB5_KDC_UNREACH) - krb5_set_error_string(context, - "unable to reach any KDC in realm %s", *realm); + ret = krb5_sendto_context(context, ctx, send_data, *realm, receive); + krb5_sendto_ctx_free(context, ctx); return ret; } @@ -458,4 +448,157 @@ krb5_set_send_to_kdc_func(krb5_context context, return 0; } +struct krb5_sendto_ctx { + int flags; + int type; + krb5_sendto_ctx_func func; + void *data; +}; +krb5_error_code KRB5_LIB_FUNCTION +krb5_sendto_ctx_alloc(krb5_context context, krb5_sendto_ctx *ctx) +{ + *ctx = calloc(1, sizeof(**ctx)); + if (*ctx == NULL) { + krb5_set_error_string(context, "out of memory"); + return ENOMEM; + } + return 0; +} + +void KRB5_LIB_FUNCTION +krb5_sendto_ctx_add_flags(krb5_sendto_ctx ctx, int flags) +{ + ctx->flags |= flags; +} + +int KRB5_LIB_FUNCTION +krb5_sendto_ctx_get_flags(krb5_sendto_ctx ctx) +{ + return ctx->flags; +} + +void KRB5_LIB_FUNCTION +krb5_sendto_ctx_set_type(krb5_sendto_ctx ctx, int type) +{ + ctx->type = type; +} + + +void KRB5_LIB_FUNCTION +krb5_sendto_ctx_set_func(krb5_sendto_ctx ctx, + krb5_sendto_ctx_func func, + void *data) +{ + ctx->func = func; + ctx->data = data; +} + +void KRB5_LIB_FUNCTION +krb5_sendto_ctx_free(krb5_context context, krb5_sendto_ctx ctx) +{ + memset(ctx, 0, sizeof(*ctx)); + free(ctx); +} + +krb5_error_code KRB5_LIB_FUNCTION +krb5_sendto_context(krb5_context context, + krb5_sendto_ctx ctx, + const krb5_data *send_data, + const krb5_realm realm, + krb5_data *receive) +{ + krb5_error_code ret; + krb5_krbhst_handle handle = NULL; + int type, freectx = 0; + int action; + + krb5_data_zero(receive); + + if (ctx == NULL) { + freectx = 1; + ret = krb5_sendto_ctx_alloc(context, &ctx); + if (ret) + return ret; + } + + type = ctx->type; + if (type == 0) { + if ((ctx->flags & KRB5_KRBHST_FLAGS_MASTER) || context->use_admin_kdc) + type = KRB5_KRBHST_ADMIN; + else + type = KRB5_KRBHST_KDC; + } + + if (send_data->length > context->large_msg_size) + ctx->flags |= KRB5_KRBHST_FLAGS_LARGE_MSG; + + /* loop until we get back a appropriate response */ + + do { + action = KRB5_SENDTO_DONE; + + krb5_data_free(receive); + + if (handle == NULL) { + ret = krb5_krbhst_init_flags(context, realm, type, + ctx->flags, &handle); + if (ret) { + if (freectx) + krb5_sendto_ctx_free(context, ctx); + return ret; + } + } + + ret = krb5_sendto(context, send_data, handle, receive); + if (ret) + break; + if (ctx->func) { + ret = (*ctx->func)(context, ctx, ctx->data, receive, &action); + if (ret) + break; + } + if (action != KRB5_SENDTO_CONTINUE) { + krb5_krbhst_free(context, handle); + handle = NULL; + } + } while (action != KRB5_SENDTO_DONE); + if (handle) + krb5_krbhst_free(context, handle); + if (ret == KRB5_KDC_UNREACH) + krb5_set_error_string(context, + "unable to reach any KDC in realm %s", realm); + if (ret) + krb5_data_free(receive); + if (freectx) + krb5_sendto_ctx_free(context, ctx); + return ret; +} + +krb5_error_code +_krb5_kdc_retry(krb5_context context, krb5_sendto_ctx ctx, void *data, + const krb5_data *reply, int *action) +{ + krb5_error_code ret; + KRB_ERROR error; + + if(krb5_rd_error(context, reply, &error)) + return 0; + + ret = krb5_error_from_rd_error(context, &error, NULL); + krb5_free_error_contents(context, &error); + + switch(ret) { + case KRB5KRB_ERR_RESPONSE_TOO_BIG: { + if (krb5_sendto_ctx_get_flags(ctx) & KRB5_KRBHST_FLAGS_LARGE_MSG) + break; + krb5_sendto_ctx_add_flags(ctx, KRB5_KRBHST_FLAGS_LARGE_MSG); + *action = KRB5_SENDTO_RESTART; + break; + } + case KRB5KDC_ERR_SVC_UNAVAILABLE: + *action = KRB5_SENDTO_CONTINUE; + break; + } + return 0; +} diff --git a/source/heimdal/lib/ntlm/heimntlm-protos.h b/source/heimdal/lib/ntlm/heimntlm-protos.h index 2df32dfa50d..438ba2b94d1 100644 --- a/source/heimdal/lib/ntlm/heimntlm-protos.h +++ b/source/heimdal/lib/ntlm/heimntlm-protos.h @@ -33,6 +33,14 @@ heim_ntlm_calculate_ntlm2 ( unsigned char ntlmv2[16], struct ntlm_buf */*answer*/); +int +heim_ntlm_calculate_ntlm2_sess ( + const unsigned char clnt_nonce[8], + const unsigned char svr_chal[8], + const unsigned char ntlm_hash[16], + struct ntlm_buf */*lm*/, + struct ntlm_buf */*ntlm*/); + int heim_ntlm_decode_targetinfo ( struct ntlm_buf */*data*/, diff --git a/source/heimdal/lib/ntlm/ntlm.c b/source/heimdal/lib/ntlm/ntlm.c index af950cc3b52..1961c7fa22f 100644 --- a/source/heimdal/lib/ntlm/ntlm.c +++ b/source/heimdal/lib/ntlm/ntlm.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 Kungliga Tekniska Högskolan + * Copyright (c) 2006 - 2007 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -33,7 +33,7 @@ #include -RCSID("$Id: ntlm.c 20816 2007-06-03 04:36:31Z lha $"); +RCSID("$Id: ntlm.c 21317 2007-06-25 19:22:02Z lha $"); #include #include @@ -52,6 +52,12 @@ RCSID("$Id: ntlm.c 20816 2007-06-03 04:36:31Z lha $"); #include +/* + * Source of NTLM information: + * http://davenport.sourceforge.net/ntlm.html + */ + + struct sec_buffer { uint16_t length; uint16_t allocated; @@ -760,6 +766,10 @@ splitandenc(unsigned char *hash, memset(key, 0, sizeof(key)); } +/* + * String-to-key function for NTLM + */ + int heim_ntlm_nt_key(const char *password, struct ntlm_buf *key) { @@ -784,6 +794,10 @@ heim_ntlm_nt_key(const char *password, struct ntlm_buf *key) return 0; } +/* + * Calculate NTLMv1 response hash + */ + int heim_ntlm_calculate_ntlm1(void *key, size_t len, unsigned char challange[8], @@ -809,6 +823,10 @@ heim_ntlm_calculate_ntlm1(void *key, size_t len, return 0; } +/* + * Calculate NTLMv1 master key + */ + int heim_ntlm_build_ntlm1_master(void *key, size_t len, struct ntlm_buf *session, @@ -880,8 +898,8 @@ heim_ntlm_ntlmv2_key(const void *key, size_t len, ascii2ucs2le(username, 1, &buf); HMAC_Update(&c, buf.data, buf.length); free(buf.data); - /* turn target into ucs2-le */ - ascii2ucs2le(target, 0, &buf); + /* uppercase target and turn into ucs2-le */ + ascii2ucs2le(target, 1, &buf); HMAC_Update(&c, buf.data, buf.length); free(buf.data); } @@ -914,6 +932,10 @@ nt2unixtime(uint64_t t) } +/* + * Calculate NTLMv2 response + */ + int heim_ntlm_calculate_ntlm2(const void *key, size_t len, const char *username, @@ -948,25 +970,27 @@ heim_ntlm_calculate_ntlm2(const void *key, size_t len, return ENOMEM; krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE); - CHECK(krb5_store_uint32(sp, 0x01010000), 0); + CHECK(krb5_store_uint32(sp, 0x00000101), 0); CHECK(krb5_store_uint32(sp, 0), 0); /* timestamp le 64 bit ts */ CHECK(krb5_store_uint32(sp, t & 0xffffffff), 0); CHECK(krb5_store_uint32(sp, t >> 32), 0); + CHECK(krb5_storage_write(sp, clientchallange, 8), 8); + + CHECK(krb5_store_uint32(sp, 0), 0); /* unknown but zero will work */ CHECK(krb5_storage_write(sp, infotarget->data, infotarget->length), infotarget->length); - /* unknown */ - /* CHECK(krb5_store_uint32(sp, 0), 0); */ + CHECK(krb5_store_uint32(sp, 0), 0); /* unknown but zero will work */ CHECK(krb5_storage_to_data(sp, &data), 0); krb5_storage_free(sp); sp = NULL; HMAC_CTX_init(&c); - HMAC_Init_ex(&c, ntlmv2, sizeof(ntlmv2), EVP_md5(), NULL); - HMAC_Update(&c, data.data, data.length); + HMAC_Init_ex(&c, ntlmv2, 16, EVP_md5(), NULL); HMAC_Update(&c, serverchallange, 8); + HMAC_Update(&c, data.data, data.length); HMAC_Final(&c, ntlmv2answer, &hmaclen); HMAC_CTX_cleanup(&c); @@ -996,6 +1020,10 @@ out: static const int authtimediff = 3600 * 2; /* 2 hours */ +/* + * Verify NTLMv2 response. + */ + int heim_ntlm_verify_ntlm2(const void *key, size_t len, const char *username, @@ -1009,6 +1037,7 @@ heim_ntlm_verify_ntlm2(const void *key, size_t len, krb5_error_code ret; unsigned int hmaclen; unsigned char clientanswer[16]; + unsigned char clientnonce[8]; unsigned char serveranswer[16]; krb5_storage *sp; HMAC_CTX c; @@ -1039,7 +1068,7 @@ heim_ntlm_verify_ntlm2(const void *key, size_t len, CHECK(krb5_storage_read(sp, clientanswer, 16), 16); CHECK(krb5_ret_uint32(sp, &temp), 0); - CHECK(temp, 0x01010000); + CHECK(temp, 0x00000101); CHECK(krb5_ret_uint32(sp, &temp), 0); CHECK(temp, 0); /* timestamp le 64 bit ts */ @@ -1056,9 +1085,12 @@ heim_ntlm_verify_ntlm2(const void *key, size_t len, } /* client challange */ - CHECK(krb5_storage_read(sp, serveranswer, 8), 8); + CHECK(krb5_storage_read(sp, clientnonce, 8), 8); - infotarget->length = answer->length - 40; + CHECK(krb5_ret_uint32(sp, &temp), 0); /* unknown */ + + /* should really unparse the infotarget, but lets pick up everything */ + infotarget->length = answer->length - krb5_storage_seek(sp, 0, SEEK_CUR); infotarget->data = malloc(infotarget->length); if (infotarget->data == NULL) { ret = ENOMEM; @@ -1066,14 +1098,14 @@ heim_ntlm_verify_ntlm2(const void *key, size_t len, } CHECK(krb5_storage_read(sp, infotarget->data, infotarget->length), infotarget->length); - /* XXX remove the unknown uint32_t */ + /* XXX remove the unknown ?? */ krb5_storage_free(sp); sp = NULL; HMAC_CTX_init(&c); - HMAC_Init_ex(&c, ntlmv2, sizeof(ntlmv2), EVP_md5(), NULL); - HMAC_Update(&c, ((char *)answer->data) + 16, answer->length - 16); + HMAC_Init_ex(&c, ntlmv2, 16, EVP_md5(), NULL); HMAC_Update(&c, serverchallange, 8); + HMAC_Update(&c, ((char *)answer->data) + 16, answer->length - 16); HMAC_Final(&c, serveranswer, &hmaclen); HMAC_CTX_cleanup(&c); @@ -1089,3 +1121,52 @@ out: krb5_storage_free(sp); return ret; } + + +/* + * Calculate the NTLM2 Session Response + */ + +int +heim_ntlm_calculate_ntlm2_sess(const unsigned char clnt_nonce[8], + const unsigned char svr_chal[8], + const unsigned char ntlm_hash[16], + struct ntlm_buf *lm, + struct ntlm_buf *ntlm) +{ + unsigned char ntlm2_sess_hash[MD5_DIGEST_LENGTH]; + unsigned char res[21], *resp; + MD5_CTX md5; + + lm->data = malloc(24); + if (lm->data == NULL) + return ENOMEM; + lm->length = 24; + + ntlm->data = malloc(24); + if (ntlm->data == NULL) { + free(lm->data); + lm->data = NULL; + return ENOMEM; + } + ntlm->length = 24; + + /* first setup the lm resp */ + memset(lm->data, 0, 24); + memcpy(lm->data, clnt_nonce, 8); + + MD5_Init(&md5); + MD5_Update(&md5, svr_chal, 8); /* session nonce part 1 */ + MD5_Update(&md5, clnt_nonce, 8); /* session nonce part 2 */ + MD5_Final(ntlm2_sess_hash, &md5); /* will only use first 8 bytes */ + + memset(res, 0, sizeof(res)); + memcpy(res, ntlm_hash, 16); + + resp = ntlm->data; + splitandenc(&res[0], ntlm2_sess_hash, resp + 0); + splitandenc(&res[7], ntlm2_sess_hash, resp + 8); + splitandenc(&res[14], ntlm2_sess_hash, resp + 16); + + return 0; +} diff --git a/source/heimdal/lib/roken/roken_gethostby.c b/source/heimdal/lib/roken/roken_gethostby.c index 08eed5f8ed3..0b25fbdb3da 100644 --- a/source/heimdal/lib/roken/roken_gethostby.c +++ b/source/heimdal/lib/roken/roken_gethostby.c @@ -33,7 +33,7 @@ #ifdef HAVE_CONFIG_H #include -RCSID("$Id: roken_gethostby.c 21005 2007-06-08 01:54:35Z lha $"); +RCSID("$Id: roken_gethostby.c 21157 2007-06-18 22:03:13Z lha $"); #endif #include @@ -111,7 +111,7 @@ int ROKEN_LIB_FUNCTION roken_gethostby_setup(const char *proxy_spec, const char *dns_spec) { char *proxy_host = NULL; - int proxy_port; + int proxy_port = 0; char *dns_host, *dns_path; int dns_port; diff --git a/source/heimdal_build/config.mk b/source/heimdal_build/config.mk index a13a8741013..73187c31dcb 100644 --- a/source/heimdal_build/config.mk +++ b/source/heimdal_build/config.mk @@ -325,6 +325,7 @@ OBJ_FILES = \ ../heimdal/lib/hcrypto/rand-egd.o \ ../heimdal/lib/hcrypto/rand-unix.o \ ../heimdal/lib/hcrypto/rand-fortuna.o \ + ../heimdal/lib/hcrypto/rand-timer.o \ ../heimdal/lib/hcrypto/hmac.o # End SUBSYSTEM HEIMDAL_HCRYPTO #######################