From c33f6b2c370379dfd010600adc59e7439f1318f7 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Mon, 24 Apr 2006 09:36:24 +0000 Subject: r15192: Update Samba4 to use current lorikeet-heimdal. Andrew Bartlett (This used to be commit f0e538126c5cb29ca14ad0d8281eaa0a715ed94f) --- source4/heimdal/kdc/524.c | 30 +- source4/heimdal/kdc/kaserver.c | 10 +- source4/heimdal/kdc/kdc-private.h | 8 +- source4/heimdal/kdc/kerberos4.c | 10 +- source4/heimdal/kdc/kerberos5.c | 97 ++++-- source4/heimdal/kdc/pkinit.c | 683 +++++++++++--------------------------- 6 files changed, 308 insertions(+), 530 deletions(-) (limited to 'source4/heimdal/kdc') diff --git a/source4/heimdal/kdc/524.c b/source4/heimdal/kdc/524.c index 1642975616..9fcf40a4c2 100644 --- a/source4/heimdal/kdc/524.c +++ b/source4/heimdal/kdc/524.c @@ -33,7 +33,7 @@ #include "kdc_locl.h" -RCSID("$Id: 524.c,v 1.35 2005/12/13 19:42:37 lha Exp $"); +RCSID("$Id: 524.c,v 1.36 2006/04/07 22:12:28 lha Exp $"); #include @@ -374,19 +374,21 @@ _kdc_do_524(krb5_context context, /* make reply */ memset(buf, 0, sizeof(buf)); sp = krb5_storage_from_mem(buf, sizeof(buf)); - krb5_store_int32(sp, ret); - if(ret == 0){ - krb5_store_int32(sp, kvno); - krb5_store_data(sp, ticket.cipher); - /* Aargh! This is coded as a KTEXT_ST. */ - krb5_storage_seek(sp, MAX_KTXT_LEN - ticket.cipher.length, SEEK_CUR); - krb5_store_int32(sp, 0); /* mbz */ - free_EncryptedData(&ticket); - } - ret = krb5_storage_to_data(sp, reply); - reply->length = krb5_storage_seek(sp, 0, SEEK_CUR); - krb5_storage_free(sp); - + if (sp) { + krb5_store_int32(sp, ret); + if(ret == 0){ + krb5_store_int32(sp, kvno); + krb5_store_data(sp, ticket.cipher); + /* Aargh! This is coded as a KTEXT_ST. */ + krb5_storage_seek(sp, MAX_KTXT_LEN - ticket.cipher.length, SEEK_CUR); + krb5_store_int32(sp, 0); /* mbz */ + free_EncryptedData(&ticket); + } + ret = krb5_storage_to_data(sp, reply); + reply->length = krb5_storage_seek(sp, 0, SEEK_CUR); + krb5_storage_free(sp); + } else + krb5_data_zero(reply); if(spn) free(spn); if(server) diff --git a/source4/heimdal/kdc/kaserver.c b/source4/heimdal/kdc/kaserver.c index 069af21660..05fedeca29 100644 --- a/source4/heimdal/kdc/kaserver.c +++ b/source4/heimdal/kdc/kaserver.c @@ -33,7 +33,7 @@ #include "kdc_locl.h" -RCSID("$Id: kaserver.c,v 1.31 2005/12/13 19:44:27 lha Exp $"); +RCSID("$Id: kaserver.c,v 1.32 2006/04/02 01:54:37 lha Exp $"); #include #include @@ -453,8 +453,8 @@ do_authenticate (krb5_context context, } ret = _kdc_check_flags (context, config, - &client_entry->entry, client_name, - &server_entry->entry, server_name, + client_entry, client_name, + server_entry, server_name, TRUE); if (ret) { make_error_reply (hdr, KAPWEXPIRED, reply); @@ -752,8 +752,8 @@ do_getticket (krb5_context context, } ret = _kdc_check_flags (context, config, - &client_entry->entry, client_name, - &server_entry->entry, server_name, + client_entry, client_name, + server_entry, server_name, FALSE); if (ret) { make_error_reply (hdr, KAPWEXPIRED, reply); diff --git a/source4/heimdal/kdc/kdc-private.h b/source4/heimdal/kdc/kdc-private.h index 729778a69e..c718b1fd52 100644 --- a/source4/heimdal/kdc/kdc-private.h +++ b/source4/heimdal/kdc/kdc-private.h @@ -18,9 +18,9 @@ krb5_error_code _kdc_check_flags ( krb5_context /*context*/, krb5_kdc_configuration */*config*/, - hdb_entry */*client*/, + hdb_entry_ex */*client_ex*/, const char */*client_name*/, - hdb_entry */*server*/, + hdb_entry_ex */*server_ex*/, const char */*server_name*/, krb5_boolean /*is_as_req*/); @@ -118,7 +118,9 @@ _kdc_pk_initialize ( krb5_context /*context*/, krb5_kdc_configuration */*config*/, const char */*user_id*/, - const char */*x509_anchors*/); + const char */*anchors*/, + char **/*pool*/, + char **/*revoke*/); krb5_error_code _kdc_pk_mk_pa_reply ( diff --git a/source4/heimdal/kdc/kerberos4.c b/source4/heimdal/kdc/kerberos4.c index 72ea41d9e6..030405adc2 100644 --- a/source4/heimdal/kdc/kerberos4.c +++ b/source4/heimdal/kdc/kerberos4.c @@ -35,7 +35,7 @@ #include -RCSID("$Id: kerberos4.c,v 1.56 2005/12/13 19:44:01 lha Exp $"); +RCSID("$Id: kerberos4.c,v 1.57 2006/04/02 01:54:37 lha Exp $"); #ifndef swap32 static u_int32_t @@ -201,8 +201,8 @@ _kdc_do_version4(krb5_context context, } ret = _kdc_check_flags (context, config, - &client->entry, client_name, - &server->entry, server_name, + client, client_name, + server, server_name, TRUE); if (ret) { /* good error code? */ @@ -489,8 +489,8 @@ _kdc_do_version4(krb5_context context, } ret = _kdc_check_flags (context, config, - &client->entry, client_name, - &server->entry, server_name, + client, client_name, + server, server_name, FALSE); if (ret) { /* good error code? */ diff --git a/source4/heimdal/kdc/kerberos5.c b/source4/heimdal/kdc/kerberos5.c index 3f9dcd12f8..68720d692e 100644 --- a/source4/heimdal/kdc/kerberos5.c +++ b/source4/heimdal/kdc/kerberos5.c @@ -33,7 +33,7 @@ #include "kdc_locl.h" -RCSID("$Id: kerberos5.c,v 1.201 2005/12/14 12:17:58 lha Exp $"); +RCSID("$Id: kerberos5.c,v 1.206 2006/04/02 01:54:37 lha Exp $"); #define MAX_TIME ((time_t)((1U << 31) - 1)) @@ -209,6 +209,50 @@ log_timestamp(krb5_context context, type, authtime_str, starttime_str, endtime_str, renewtime_str); } +static void +log_patypes(krb5_context context, + krb5_kdc_configuration *config, + METHOD_DATA *padata) +{ + struct rk_strpool *p = NULL; + char *str; + int i; + + for (i = 0; i < padata->len; i++) { + switch(padata->val[i].padata_type) { + case KRB5_PADATA_PK_AS_REQ: + p = rk_strpoolprintf(p, "PK-INIT(ietf)"); + break; + case KRB5_PADATA_PK_AS_REQ_WIN: + p = rk_strpoolprintf(p, "PK-INIT(win2k)"); + break; + case KRB5_PADATA_PA_PK_OCSP_RESPONSE: + p = rk_strpoolprintf(p, "OCSP"); + break; + case KRB5_PADATA_ENC_TIMESTAMP: + p = rk_strpoolprintf(p, "encrypted-timestamp"); + break; + default: + p = rk_strpoolprintf(p, "%d", padata->val[i].padata_type); + break; + } + if (p && i + 1 < padata->len) + p = rk_strpoolprintf(p, ", "); + if (p == NULL) { + kdc_log(context, config, 0, "out of memory"); + return; + } + } + str = rk_strpoolcollect(p); + kdc_log(context, config, 0, "Client sent patypes: %s", str); + free(str); +} + +/* + * + */ + + static krb5_error_code encode_reply(krb5_context context, krb5_kdc_configuration *config, @@ -642,11 +686,13 @@ get_pa_etype_info2(krb5_context context, krb5_error_code _kdc_check_flags(krb5_context context, krb5_kdc_configuration *config, - hdb_entry *client, const char *client_name, - hdb_entry *server, const char *server_name, + hdb_entry_ex *client_ex, const char *client_name, + hdb_entry_ex *server_ex, const char *server_name, krb5_boolean is_as_req) { - if(client != NULL) { + if(client_ex != NULL) { + hdb_entry *client = &client_ex->entry; + /* check client */ if (client->flags.invalid) { kdc_log(context, config, 0, @@ -680,8 +726,8 @@ _kdc_check_flags(krb5_context context, return KRB5KDC_ERR_NAME_EXP; } - if (client->pw_end && *client->pw_end < kdc_time - && !server->flags.change_pw) { + if (client->pw_end && *client->pw_end < kdc_time + && (server_ex == NULL || !server_ex->entry.flags.change_pw)) { char pwend_str[100]; krb5_format_time(context, *client->pw_end, pwend_str, sizeof(pwend_str), TRUE); @@ -694,7 +740,9 @@ _kdc_check_flags(krb5_context context, /* check server */ - if (server != NULL) { + if (server_ex != NULL) { + hdb_entry *server = &server_ex->entry; + if (server->flags.invalid) { kdc_log(context, config, 0, "Server has invalid flag set -- %s", server_name); @@ -762,27 +810,28 @@ check_addresses(krb5_context context, krb5_boolean result; krb5_boolean only_netbios = TRUE; int i; - + if(config->check_ticket_addresses == 0) return TRUE; - if(addresses == NULL) + if(addresses == NULL) return config->allow_null_ticket_addresses; - + for (i = 0; i < addresses->len; ++i) { - if (addresses->val[i].addr_type != KRB5_ADDRESS_NETBIOS) { - only_netbios = FALSE; - } + if (addresses->val[i].addr_type != KRB5_ADDRESS_NETBIOS) { + only_netbios = FALSE; + } } /* Windows sends it's netbios name, which I can only assume is - * used for the 'allowed workstations' check. This is painful, but - * we still want to check IP addresses if they happen to be - * present. */ + * used for the 'allowed workstations' check. This is painful, + * but we still want to check IP addresses if they happen to be + * present. + */ if(only_netbios) return config->allow_null_ticket_addresses; - + ret = krb5_sockaddr2address (context, from, &addr); if(ret) return FALSE; @@ -867,8 +916,8 @@ _kdc_as_rep(krb5_context context, } ret = _kdc_check_flags(context, config, - &client->entry, client_name, - &server->entry, server_name, + client, client_name, + server, server_name, TRUE); if(ret) goto out; @@ -884,10 +933,12 @@ _kdc_as_rep(krb5_context context, memset(&ek, 0, sizeof(ek)); if(req->padata){ - int i = 0; + int i; PA_DATA *pa; int found_pa = 0; + log_patypes(context, config, req->padata); + #ifdef PKINIT kdc_log(context, config, 5, "Looking for PKINIT pa-data -- %s", client_name); @@ -1171,7 +1222,7 @@ _kdc_as_rep(krb5_context context, if (p && i + 1 < b->etype.len) p = rk_strpoolprintf(p, ", "); if (p == NULL) { - kdc_log(context, config, 0, "out of meory"); + kdc_log(context, config, 0, "out of memory"); goto out; } } @@ -2410,8 +2461,8 @@ tgs_rep2(krb5_context context, } ret = _kdc_check_flags(context, config, - &client->entry, cpn, - &server->entry, spn, + client, cpn, + server, spn, FALSE); if(ret) goto out; diff --git a/source4/heimdal/kdc/pkinit.c b/source4/heimdal/kdc/pkinit.c index 67934c0745..3f064f9d50 100755 --- a/source4/heimdal/kdc/pkinit.c +++ b/source4/heimdal/kdc/pkinit.c @@ -33,7 +33,7 @@ #include "kdc_locl.h" -RCSID("$Id: pkinit.c,v 1.50 2006/02/13 11:48:21 lha Exp $"); +RCSID("$Id: pkinit.c,v 1.59 2006/04/22 12:10:16 lha Exp $"); #ifdef PKINIT @@ -42,25 +42,17 @@ RCSID("$Id: pkinit.c,v 1.50 2006/02/13 11:48:21 lha Exp $"); #include #include -#include -#include -#include -#include -#include -#include +#include +#include "crypto-headers.h" /* XXX copied from lib/krb5/pkinit.c */ struct krb5_pk_identity { - EVP_PKEY *private_key; - STACK_OF(X509) *cert; - STACK_OF(X509) *trusted_certs; - STACK_OF(X509_CRL) *crls; - ENGINE *engine; -}; - -/* XXX copied from lib/krb5/pkinit.c */ -struct krb5_pk_cert { - X509 *cert; + hx509_context hx509ctx; + hx509_verify_ctx verify_ctx; + hx509_certs certs; + hx509_certs anchors; + hx509_certs certpool; + hx509_revoke_ctx revoke; }; enum pkinit_type { @@ -71,7 +63,7 @@ enum pkinit_type { struct pk_client_params { enum pkinit_type type; BIGNUM *dh_public_key; - struct krb5_pk_cert *certificate; + hx509_cert cert; unsigned nonce; DH *dh; EncryptionKey reply_key; @@ -86,29 +78,6 @@ struct pk_principal_mapping { } *val; }; -/* XXX copied from lib/krb5/pkinit.c */ -#define OPENSSL_ASN1_MALLOC_ENCODE(T, B, BL, S, R) \ -{ \ - unsigned char *p; \ - (BL) = i2d_##T((S), NULL); \ - if ((BL) <= 0) { \ - (R) = EINVAL; \ - } else { \ - (B) = malloc((BL)); \ - if ((B) == NULL) { \ - (R) = ENOMEM; \ - } else { \ - p = (B); \ - (R) = 0; \ - (BL) = i2d_##T((S), &p); \ - if ((BL) <= 0) { \ - free((B)); \ - (R) = ASN1_OVERRUN; \ - } \ - } \ - } \ -} - static struct krb5_pk_identity *kdc_identity; static struct pk_principal_mapping principal_mappings; static struct krb5_dh_moduli **moduli; @@ -185,59 +154,19 @@ pk_check_pkauthenticator(krb5_context context, krb5_clear_error_string(context); ret = KRB5KRB_ERR_GENERIC; } + out: free_Checksum(&checksum); return ret; } -static krb5_error_code -pk_encrypt_key(krb5_context context, - krb5_keyblock *key, - EVP_PKEY *public_key, - krb5_data *encrypted_key, - const heim_oid **oid) -{ - krb5_error_code ret; - - encrypted_key->length = EVP_PKEY_size(public_key); - - if (encrypted_key->length < key->keyvalue.length + 11) { /* XXX */ - krb5_set_error_string(context, "pkinit: encrypted key too long"); - return KRB5KRB_ERR_GENERIC; - } - - encrypted_key->data = malloc(encrypted_key->length); - if (encrypted_key->data == NULL) { - krb5_set_error_string(context, "malloc: out of memory"); - return ENOMEM; - } - - ret = EVP_PKEY_encrypt(encrypted_key->data, - key->keyvalue.data, - key->keyvalue.length, - public_key); - if (ret < 0) { - free(encrypted_key->data); - krb5_set_error_string(context, "Can't encrypt key: %s", - ERR_error_string(ERR_get_error(), NULL)); - return KRB5KRB_ERR_GENERIC; - } - if (encrypted_key->length != ret) - krb5_abortx(context, "size of EVP_PKEY_size is not the " - "size of the output"); - - *oid = oid_id_pkcs1_rsaEncryption(); - - return 0; -} - void _kdc_pk_free_client_param(krb5_context context, pk_client_params *client_params) { - if (client_params->certificate) - _krb5_pk_cert_free(client_params->certificate); + if (client_params->cert) + hx509_cert_free(client_params->cert); if (client_params->dh) DH_free(client_params->dh); if (client_params->dh_public_key) @@ -261,9 +190,7 @@ generate_dh_keyblock(krb5_context context, pk_client_params *client_params, memset(&key, 0, sizeof(key)); if (!DH_generate_key(client_params->dh)) { - krb5_set_error_string(context, "Can't generate Diffie-Hellman " - "keys (%s)", - ERR_error_string(ERR_get_error(), NULL)); + krb5_set_error_string(context, "Can't generate Diffie-Hellman keys"); ret = KRB5KRB_ERR_GENERIC; goto out; } @@ -290,8 +217,7 @@ generate_dh_keyblock(krb5_context context, pk_client_params *client_params, client_params->dh_public_key, client_params->dh); if (dh_gen_keylen == -1) { - krb5_set_error_string(context, "Can't compute Diffie-Hellman key (%s)", - ERR_error_string(ERR_get_error(), NULL)); + krb5_set_error_string(context, "Can't compute Diffie-Hellman key"); ret = KRB5KRB_ERR_GENERIC; goto out; } @@ -321,7 +247,7 @@ integer_to_BN(krb5_context context, const char *field, heim_integer *f) krb5_set_error_string(context, "PKINIT: parsing BN failed %s", field); return NULL; } - bn->neg = f->negative; + BN_set_negative(bn, f->negative); return bn; } @@ -376,8 +302,7 @@ get_dh_param(krb5_context context, dh = DH_new(); if (dh == NULL) { - krb5_set_error_string(context, "Cannot create DH structure (%s)", - ERR_error_string(ERR_get_error(), NULL)); + krb5_set_error_string(context, "Cannot create DH structure"); ret = ENOMEM; goto out; } @@ -413,9 +338,10 @@ get_dh_param(krb5_context context, goto out; } - if (DH_check(dh, &dhret) != 1) { - krb5_set_error_string(context, "PKINIT DH data not ok: %s", - ERR_error_string(ERR_get_error(), NULL)); + + if (DH_check_pubkey(dh, client_params->dh_public_key, &dhret) != 1 || + dhret != 0) { + krb5_set_error_string(context, "PKINIT DH data not ok"); ret = KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED; goto out; } @@ -498,11 +424,12 @@ _kdc_pk_rd_padata(krb5_context context, { pk_client_params *client_params; krb5_error_code ret; - heim_oid eContentType = { 0, NULL }; + heim_oid eContentType = { 0, NULL }, contentInfoOid = { 0, NULL }; krb5_data eContent = { 0, NULL }; krb5_data signed_content = { 0, NULL }; const char *type = "unknown type"; const heim_oid *pa_contentType; + int have_data; *ret_params = NULL; @@ -520,7 +447,7 @@ _kdc_pk_rd_padata(krb5_context context, if (pa->padata_type == KRB5_PADATA_PK_AS_REQ_WIN) { PA_PK_AS_REQ_Win2k r; - ContentInfo info; + int have_data; type = "PK-INIT-Win2k"; pa_contentType = oid_id_pkcs7_data(); @@ -535,47 +462,20 @@ _kdc_pk_rd_padata(krb5_context context, goto out; } - ret = decode_ContentInfo(r.signed_auth_pack.data, - r.signed_auth_pack.length, &info, NULL); + ret = hx509_cms_unwrap_ContentInfo(&r.signed_auth_pack, + &contentInfoOid, + &signed_content, + &have_data); free_PA_PK_AS_REQ_Win2k(&r); if (ret) { krb5_set_error_string(context, "Can't decode PK-AS-REQ: %d", ret); goto out; } - if (heim_oid_cmp(&info.contentType, oid_id_pkcs7_signedData())) { - krb5_set_error_string(context, "PK-AS-REQ-Win2k invalid content " - "type oid"); - free_ContentInfo(&info); - ret = KRB5KRB_ERR_GENERIC; - goto out; - } - - if (info.content == NULL) { - krb5_set_error_string(context, - "PK-AS-REQ-Win2k no signed auth pack"); - free_ContentInfo(&info); - ret = KRB5KRB_ERR_GENERIC; - goto out; - } - - signed_content.data = malloc(info.content->length); - if (signed_content.data == NULL) { - ret = ENOMEM; - free_ContentInfo(&info); - krb5_set_error_string(context, "PK-AS-REQ-Win2k out of memory"); - goto out; - } - signed_content.length = info.content->length; - memcpy(signed_content.data, info.content->data, signed_content.length); - - free_ContentInfo(&info); - } else if (pa->padata_type == KRB5_PADATA_PK_AS_REQ) { PA_PK_AS_REQ r; - ContentInfo info; - type = "PK-INIT-27"; + type = "PK-INIT-IETF"; pa_contentType = oid_id_pkauthdata(); ret = decode_PA_PK_AS_REQ(pa->padata_value.data, @@ -587,43 +487,17 @@ _kdc_pk_rd_padata(krb5_context context, goto out; } - ret = decode_ContentInfo(r.signedAuthPack.data, - r.signedAuthPack.length, &info, NULL); - if (ret) { - krb5_set_error_string(context, "Can't decode PK-AS-REQ: %d", ret); - goto out; - } - - if (heim_oid_cmp(&info.contentType, oid_id_pkcs7_signedData())) { - krb5_set_error_string(context, "PK-AS-REQ invalid content " - "type oid"); - free_ContentInfo(&info); - free_PA_PK_AS_REQ(&r); - ret = KRB5KRB_ERR_GENERIC; - goto out; - } - - if (info.content == NULL) { - krb5_set_error_string(context, "PK-AS-REQ no signed auth pack"); - free_PA_PK_AS_REQ(&r); - free_ContentInfo(&info); - ret = KRB5KRB_ERR_GENERIC; - goto out; - } + /* XXX look at r.trustedCertifiers and r.kdcPkId */ - signed_content.data = malloc(info.content->length); - if (signed_content.data == NULL) { - ret = ENOMEM; - free_ContentInfo(&info); - free_PA_PK_AS_REQ(&r); - krb5_set_error_string(context, "PK-AS-REQ out of memory"); + ret = hx509_cms_unwrap_ContentInfo(&r.signedAuthPack, + &contentInfoOid, + &signed_content, + &have_data); + free_PA_PK_AS_REQ(&r); + if (ret) { + krb5_set_error_string(context, "Can't unwrap ContentInfo: %d", ret); goto out; } - signed_content.length = info.content->length; - memcpy(signed_content.data, info.content->data, signed_content.length); - - free_ContentInfo(&info); - free_PA_PK_AS_REQ(&r); } else { krb5_clear_error_string(context); @@ -631,24 +505,51 @@ _kdc_pk_rd_padata(krb5_context context, goto out; } - ret = _krb5_pk_verify_sign(context, - signed_content.data, - signed_content.length, - kdc_identity, - &eContentType, - &eContent, - &client_params->certificate); - if (ret) + ret = heim_oid_cmp(&contentInfoOid, oid_id_pkcs7_signedData()); + if (ret != 0) { + krb5_set_error_string(context, "PK-AS-REQ-Win2k invalid content " + "type oid"); + ret = KRB5KRB_ERR_GENERIC; + goto out; + } + + if (!have_data) { + krb5_set_error_string(context, + "PK-AS-REQ-Win2k no signed auth pack"); + ret = KRB5KRB_ERR_GENERIC; goto out; + } + + { + hx509_certs signer_certs; + + ret = hx509_cms_verify_signed(kdc_identity->hx509ctx, + kdc_identity->verify_ctx, + signed_content.data, + signed_content.length, + kdc_identity->certpool, + &eContentType, + &eContent, + &signer_certs); + if (ret) { + kdc_log(context, config, 0, + "PK-INIT failed to verify signature %d", ret); + goto out; + } + + ret = hx509_get_one_cert(kdc_identity->hx509ctx, signer_certs, + &client_params->cert); + hx509_certs_free(&signer_certs); + if (ret) + goto out; + } -#if 0 /* Signature is correct, now verify the signed message */ if (heim_oid_cmp(&eContentType, pa_contentType)) { krb5_set_error_string(context, "got wrong oid for pkauthdata"); ret = KRB5_BADMSGTYPE; goto out; } -#endif if (pa->padata_type == KRB5_PADATA_PK_AS_REQ_WIN) { AuthPack_Win2k ap; @@ -716,19 +617,15 @@ _kdc_pk_rd_padata(krb5_context context, } else krb5_abortx(context, "internal pkinit error"); - /* - * Remaining fields (ie kdcCert and encryptionCert) in the request - * are ignored for now. - */ - kdc_log(context, config, 0, "PK-INIT request of type %s", type); - out: +out: if (signed_content.data) free(signed_content.data); krb5_data_free(&eContent); free_oid(&eContentType); + free_oid(&contentInfoOid); if (ret) _kdc_pk_free_client_param(context, client_params); else @@ -750,7 +647,7 @@ BN_to_integer(krb5_context context, BIGNUM *bn, heim_integer *integer) return ENOMEM; } BN_bn2bin(bn, integer->data); - integer->negative = bn->neg; + integer->negative = BN_is_negative(bn); return 0; } @@ -762,78 +659,11 @@ pk_mk_pa_reply_enckey(krb5_context context, krb5_keyblock *reply_key, ContentInfo *content_info) { - KeyTransRecipientInfo *ri; - EnvelopedData ed; krb5_error_code ret; - krb5_crypto crypto = NULL; - krb5_data buf, sd_data, enc_sd_data, iv, params; - krb5_keyblock tmp_key; - krb5_enctype enveloped_enctype; - X509_NAME *issuer_name; - heim_integer *serial; + krb5_data buf, o; size_t size; - AlgorithmIdentifier *enc_alg; - int i; - - krb5_data_zero(&enc_sd_data); - krb5_data_zero(&sd_data); - krb5_data_zero(&iv); - - memset(&tmp_key, 0, sizeof(tmp_key)); - memset(&ed, 0, sizeof(ed)); - - /* default to DES3 if client doesn't tell us */ - enveloped_enctype = ETYPE_DES3_CBC_NONE_CMS; - - for (i = 0; i < req->req_body.etype.len; i++) { - switch(req->req_body.etype.val[i]) { - case 15: /* des-ede3-cbc-Env-OID */ - enveloped_enctype = ETYPE_DES3_CBC_NONE_CMS; - break; - default: - break; - } - } - - ret = krb5_generate_random_keyblock(context, enveloped_enctype, &tmp_key); - if (ret) - goto out; - ret = krb5_crypto_init(context, &tmp_key, 0, &crypto); - if (ret) - goto out; - - - ret = krb5_crypto_getblocksize(context, crypto, &iv.length); - if (ret) - goto out; - - ret = krb5_data_alloc(&iv, iv.length); - if (ret) { - krb5_set_error_string(context, "malloc out of memory"); - goto out; - } - - krb5_generate_random_block(iv.data, iv.length); - - enc_alg = &ed.encryptedContentInfo.contentEncryptionAlgorithm; - - ret = krb5_enctype_to_oid(context, enveloped_enctype, &enc_alg->algorithm); - if (ret) - goto out; - - ret = krb5_crypto_set_params(context, crypto, &iv, ¶ms); - if (ret) - goto out; - - ALLOC(enc_alg->parameters); - if (enc_alg->parameters == NULL) { - krb5_data_free(¶ms); - krb5_set_error_string(context, "malloc out of memory"); - return ENOMEM; - } - enc_alg->parameters->data = params.data; - enc_alg->parameters->length = params.length; + krb5_data_zero(&buf); switch (client_params->type) { case PKINIT_COMPAT_WIN2K: { @@ -897,139 +727,21 @@ pk_mk_pa_reply_enckey(krb5_context context, if (buf.length != size) krb5_abortx(context, "Internal ASN.1 encoder error"); - /* - * CRL's are not transfered -- should be ? - */ - - ret = _krb5_pk_create_sign(context, - oid_id_pkrkeydata(), - &buf, - kdc_identity, - &sd_data); - krb5_data_free(&buf); - if (ret) - goto out; - - ret = krb5_encrypt_ivec(context, crypto, 0, - sd_data.data, sd_data.length, - &enc_sd_data, - iv.data); - - ALLOC_SEQ(&ed.recipientInfos, 1); - if (ed.recipientInfos.val == NULL) { - krb5_clear_error_string(context); - ret = ENOMEM; - goto out; - } - - ri = &ed.recipientInfos.val[0]; - - ri->version = 0; - ri->rid.element = choice_CMSIdentifier_issuerAndSerialNumber; - - issuer_name = X509_get_issuer_name(client_params->certificate->cert); - OPENSSL_ASN1_MALLOC_ENCODE(X509_NAME, buf.data, buf.length, - issuer_name, ret); - if (ret) { - krb5_clear_error_string(context); - goto out; - } - ret = decode_Name(buf.data, buf.length, - &ri->rid.u.issuerAndSerialNumber.issuer, - NULL); - free(buf.data); - if (ret) { - krb5_set_error_string(context, "pkinit: failed to parse Name"); - goto out; - } - - serial = &ri->rid.u.issuerAndSerialNumber.serialNumber; - { - ASN1_INTEGER *isn; - BIGNUM *bn; - - isn = X509_get_serialNumber(client_params->certificate->cert); - bn = ASN1_INTEGER_to_BN(isn, NULL); - if (bn == NULL) { - ret = ENOMEM; - krb5_clear_error_string(context); - goto out; - } - ret = BN_to_integer(context, bn, serial); - BN_free(bn); - if (ret) { - krb5_clear_error_string(context); - goto out; - } - } - - { - const heim_oid *pk_enc_key_oid; - krb5_data enc_tmp_key; - - ret = pk_encrypt_key(context, &tmp_key, - X509_get_pubkey(client_params->certificate->cert), - &enc_tmp_key, - &pk_enc_key_oid); - if (ret) - goto out; - - ri->encryptedKey.length = enc_tmp_key.length; - ri->encryptedKey.data = enc_tmp_key.data; - - ret = copy_oid(pk_enc_key_oid, &ri->keyEncryptionAlgorithm.algorithm); - if (ret) - goto out; - } - - /* - * - */ - - ed.version = 0; - ed.originatorInfo = NULL; - - ret = copy_oid(oid_id_pkcs7_signedData(), &ed.encryptedContentInfo.contentType); - if (ret) { - krb5_clear_error_string(context); - goto out; - } - - ALLOC(ed.encryptedContentInfo.encryptedContent); - if (ed.encryptedContentInfo.encryptedContent == NULL) { - krb5_clear_error_string(context); - ret = ENOMEM; - goto out; - } - - ed.encryptedContentInfo.encryptedContent->data = enc_sd_data.data; - ed.encryptedContentInfo.encryptedContent->length = enc_sd_data.length; - krb5_data_zero(&enc_sd_data); - - ed.unprotectedAttrs = NULL; - - ASN1_MALLOC_ENCODE(EnvelopedData, buf.data, buf.length, &ed, &size, ret); - if (ret) { - krb5_set_error_string(context, - "ASN.1 encoding of EnvelopedData failed (%d)", - ret); + ret = hx509_cms_envelope_1(kdc_identity->hx509ctx, + client_params->cert, + buf.data, buf.length, NULL, + oid_id_pkcs7_signedData(), &o); + if (ret) goto out; - } - + ret = _krb5_pk_mk_ContentInfo(context, - &buf, + &o, oid_id_pkcs7_envelopedData(), content_info); - krb5_data_free(&buf); + free_octet_string(&o); out: - if (crypto) - krb5_crypto_destroy(context, crypto); - krb5_free_keyblock_contents(context, &tmp_key); - krb5_data_free(&enc_sd_data); - krb5_data_free(&iv); - free_EnvelopedData(&ed); - + krb5_data_free(&buf); return ret; } @@ -1044,37 +756,32 @@ pk_mk_pa_reply_dh(krb5_context context, krb5_keyblock *reply_key, ContentInfo *content_info) { - ASN1_INTEGER *dh_pub_key = NULL; - ContentInfo contentinfo; KDCDHKeyInfo dh_info; + krb5_data signed_data, buf; + ContentInfo contentinfo; krb5_error_code ret; - SignedData sd; - krb5_data buf, signed_data; size_t size; + heim_integer i; memset(&contentinfo, 0, sizeof(contentinfo)); memset(&dh_info, 0, sizeof(dh_info)); - memset(&sd, 0, sizeof(sd)); krb5_data_zero(&buf); krb5_data_zero(&signed_data); - dh_pub_key = BN_to_ASN1_INTEGER(kdc_dh->pub_key, NULL); - if (dh_pub_key == NULL) { - krb5_set_error_string(context, "BN_to_ASN1_INTEGER() failed (%s)", - ERR_error_string(ERR_get_error(), NULL)); - ret = ENOMEM; - goto out; - } + ret = BN_to_integer(context, kdc_dh->pub_key, &i); + if (ret) + return ret; - OPENSSL_ASN1_MALLOC_ENCODE(ASN1_INTEGER, buf.data, buf.length, dh_pub_key, - ret); - ASN1_INTEGER_free(dh_pub_key); + ASN1_MALLOC_ENCODE(DHPublicKey, buf.data, buf.length, &i, &size, ret); if (ret) { - krb5_set_error_string(context, "Encoding of ASN1_INTEGER failed (%s)", - ERR_error_string(ERR_get_error(), NULL)); - goto out; + krb5_set_error_string(context, "ASN.1 encoding of " + "DHPublicKey failed (%d)", ret); + krb5_clear_error_string(context); + return ret; } - + if (buf.length != size) + krb5_abortx(context, "Internal ASN.1 encoder error"); + dh_info.subjectPublicKey.length = buf.length * 8; dh_info.subjectPublicKey.data = buf.data; @@ -1095,12 +802,36 @@ pk_mk_pa_reply_dh(krb5_context context, * filled in above */ - ret = _krb5_pk_create_sign(context, - oid_id_pkdhkeydata(), - &buf, - kdc_identity, - &signed_data); - krb5_data_free(&buf); + { + hx509_cert cert; + hx509_query *q; + + ret = hx509_query_alloc(kdc_identity->hx509ctx, &q); + if (ret) + goto out; + + hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY); + hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE); + + ret = hx509_certs_find(kdc_identity->hx509ctx, + kdc_identity->certs, + q, + &cert); + hx509_query_free(kdc_identity->hx509ctx, q); + if (ret) + goto out; + + ret = hx509_cms_create_signed_1(kdc_identity->hx509ctx, + oid_id_pkdhkeydata(), + buf.data, + buf.length, + NULL, + cert, + kdc_identity->anchors, + kdc_identity->certpool, + &signed_data); + hx509_cert_free(cert); + } if (ret) goto out; @@ -1112,6 +843,7 @@ pk_mk_pa_reply_dh(krb5_context context, goto out; out: + krb5_data_free(&buf); krb5_data_free(&signed_data); free_KDCDHKeyInfo(&dh_info); @@ -1322,62 +1054,59 @@ _kdc_pk_mk_pa_reply(krb5_context context, static int pk_principal_from_X509(krb5_context context, krb5_kdc_configuration *config, - struct krb5_pk_cert *client_cert, - krb5_principal *principal) + hx509_cert client_cert, + krb5_const_principal match) { - krb5_error_code ret; - GENERAL_NAMES *gens; - GENERAL_NAME *gen; - ASN1_OBJECT *obj; - int i; + hx509_octet_string_list list; + int ret, i, found = 0; - *principal = NULL; + memset(&list, 0 , sizeof(list)); - obj = OBJ_txt2obj("1.3.6.1.5.2.2",1); - - gens = X509_get_ext_d2i(client_cert->cert, NID_subject_alt_name, - NULL, NULL); - if (gens == NULL) - return 1; + ret = hx509_cert_find_subjectAltName_otherName(client_cert, + oid_id_pkinit_san(), + &list); + if (ret) + goto out; - for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) { + for (i = 0; !found && i < list.len; i++) { + krb5_principal_data principal; KRB5PrincipalName kn; - size_t len, size; - void *p; - - gen = sk_GENERAL_NAME_value(gens, i); - if (gen->type != GEN_OTHERNAME) - continue; - - if(OBJ_cmp(obj, gen->d.otherName->type_id) != 0) - continue; - - p = ASN1_STRING_data(gen->d.otherName->value->value.sequence); - len = ASN1_STRING_length(gen->d.otherName->value->value.sequence); + size_t size; - ret = decode_KRB5PrincipalName(p, len, &kn, &size); + ret = decode_KRB5PrincipalName(list.val[i].data, + list.val[i].length, + &kn, &size); if (ret) { kdc_log(context, config, 0, "Decoding kerberos name in certificate failed: %s", krb5_get_err_text(context, ret)); - continue; + break; } - - *principal = malloc(sizeof(**principal)); - if (*principal == NULL) { - free_KRB5PrincipalName(&kn); - return 1; + if (size != list.val[i].length) { + kdc_log(context, config, 0, + "Decoding kerberos name have extra bits on the end"); + return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH; } - (*principal)->name = kn.principalName; - (*principal)->realm = kn.realm; - return 0; + principal.name = kn.principalName; + principal.realm = kn.realm; + + if (krb5_principal_compare(context, &principal, match) == TRUE) + found = 1; + free_KRB5PrincipalName(&kn); } - return 1; -} +out: + hx509_free_octet_string_list(&list); + if (ret) + return ret; + + if (!found) + return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH; + + return 0; +} -/* XXX match with issuer too ? */ krb5_error_code _kdc_pk_check_client(krb5_context context, @@ -1387,45 +1116,34 @@ _kdc_pk_check_client(krb5_context context, pk_client_params *client_params, char **subject_name) { - struct krb5_pk_cert *client_cert = client_params->certificate; - krb5_principal cert_princ; - X509_NAME *name; - char *subject = NULL; krb5_error_code ret; - krb5_boolean b; + hx509_name name; int i; - *subject_name = NULL; - - name = X509_get_subject_name(client_cert->cert); - if (name == NULL) { - krb5_set_error_string(context, "PKINIT can't get subject name"); - return ENOMEM; - } - subject = X509_NAME_oneline(name, NULL, 0); - if (subject == NULL) { - krb5_set_error_string(context, "PKINIT can't get subject name"); - return ENOMEM; - } - *subject_name = strdup(subject); - if (*subject_name == NULL) { - krb5_set_error_string(context, "out of memory"); - return ENOMEM; - } - OPENSSL_free(subject); - if (config->enable_pkinit_princ_in_cert) { ret = pk_principal_from_X509(context, config, - client_cert, &cert_princ); - if (ret == 0) { - b = krb5_principal_compare(context, client_princ, cert_princ); - krb5_free_principal(context, cert_princ); - if (b == TRUE) - return 0; - } + client_params->cert, + client_princ); + if (ret == 0) + return 0; } + ret = hx509_cert_get_subject(client_params->cert, &name); + if (ret) + return ret; + + ret = hx509_name_to_string(name, subject_name); + hx509_name_free(&name); + if (ret) + return ret; + + kdc_log(context, config, 5, + "Trying to authorize subject DN %s", + *subject_name); + for (i = 0; i < principal_mappings.len; i++) { + krb5_boolean b; + b = krb5_principal_compare(context, client_princ, principal_mappings.val[i].principal); @@ -1436,6 +1154,7 @@ _kdc_pk_check_client(krb5_context context, return 0; } free(*subject_name); + *subject_name = NULL; krb5_set_error_string(context, "PKINIT no matching principals"); return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH; @@ -1477,7 +1196,9 @@ krb5_error_code _kdc_pk_initialize(krb5_context context, krb5_kdc_configuration *config, const char *user_id, - const char *x509_anchors) + const char *anchors, + char **pool, + char **revoke) { const char *file; krb5_error_code ret; @@ -1495,13 +1216,15 @@ _kdc_pk_initialize(krb5_context context, principal_mappings.len = 0; principal_mappings.val = NULL; - ret = _krb5_pk_load_openssl_id(context, - &kdc_identity, - user_id, - x509_anchors, - NULL, - NULL, - NULL); + ret = _krb5_pk_load_id(context, + &kdc_identity, + user_id, + anchors, + pool, + revoke, + NULL, + NULL, + NULL); if (ret) { krb5_warn(context, ret, "PKINIT: failed to load"); config->enable_pkinit = 0; -- cgit