2 * Copyright (c) 2003 - 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #include "krb5_locl.h"
38 struct krb5_dh_moduli {
49 #include <pkcs8_asn1.h>
50 #include <pkcs9_asn1.h>
51 #include <pkcs12_asn1.h>
52 #include <pkinit_asn1.h>
61 struct krb5_pk_init_ctx_data {
62 struct krb5_pk_identity *id;
63 enum { USE_RSA, USE_DH, USE_ECDH } keyex;
70 krb5_data *clientDHNonce;
71 struct krb5_dh_moduli **m;
73 enum krb5_pk_type type;
74 unsigned int require_binding:1;
75 unsigned int require_eku:1;
76 unsigned int require_krbtgt_otherName:1;
77 unsigned int require_hostname_match:1;
78 unsigned int trustedCertifiers:1;
79 unsigned int anonymous:1;
83 pk_copy_error(krb5_context context,
84 hx509_context hx509ctx,
88 __attribute__ ((format (printf, 4, 5)));
94 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
95 _krb5_pk_cert_free(struct krb5_pk_cert *cert)
98 hx509_cert_free(cert->cert);
103 static krb5_error_code
104 BN_to_integer(krb5_context context, BIGNUM *bn, heim_integer *integer)
106 integer->length = BN_num_bytes(bn);
107 integer->data = malloc(integer->length);
108 if (integer->data == NULL) {
109 krb5_clear_error_message(context);
112 BN_bn2bin(bn, integer->data);
113 integer->negative = BN_is_negative(bn);
118 integer_to_BN(krb5_context context, const char *field, const heim_integer *f)
122 bn = BN_bin2bn((const unsigned char *)f->data, f->length, NULL);
124 krb5_set_error_message(context, ENOMEM,
125 N_("PKINIT: parsing BN failed %s", ""), field);
128 BN_set_negative(bn, f->negative);
132 static krb5_error_code
133 select_dh_group(krb5_context context, DH *dh, unsigned long bits,
134 struct krb5_dh_moduli **moduli)
136 const struct krb5_dh_moduli *m;
139 m = moduli[1]; /* XXX */
141 m = moduli[0]; /* XXX */
144 for (i = 0; moduli[i] != NULL; i++) {
145 if (bits < moduli[i]->bits)
148 if (moduli[i] == NULL) {
149 krb5_set_error_message(context, EINVAL,
150 N_("Did not find a DH group parameter "
151 "matching requirement of %lu bits", ""),
158 dh->p = integer_to_BN(context, "p", &m->p);
161 dh->g = integer_to_BN(context, "g", &m->g);
164 dh->q = integer_to_BN(context, "q", &m->q);
177 * Try searchin the key by to use by first looking for for PK-INIT
178 * EKU, then the Microsoft smart card EKU and last, no special EKU at all.
181 static krb5_error_code
182 find_cert(krb5_context context, struct krb5_pk_identity *id,
183 hx509_query *q, hx509_cert *cert)
185 struct certfind cf[4] = {
191 int i, ret, start = 1;
192 unsigned oids[] = { 1, 2, 840, 113635, 100, 3, 2, 1 };
193 const heim_oid mobileMe = { sizeof(oids)/sizeof(oids[0]), oids };
196 if (id->flags & PKINIT_BTMM)
199 cf[0].oid = &mobileMe;
200 cf[1].oid = &asn1_oid_id_pkekuoid;
201 cf[2].oid = &asn1_oid_id_pkinit_ms_eku;
204 for (i = start; i < sizeof(cf)/sizeof(cf[0]); i++) {
205 ret = hx509_query_match_eku(q, cf[i].oid);
207 pk_copy_error(context, context->hx509ctx, ret,
208 "Failed setting %s OID", cf[i].type);
212 ret = hx509_certs_find(context->hx509ctx, id->certs, q, cert);
215 pk_copy_error(context, context->hx509ctx, ret,
216 "Failed finding certificate with %s OID", cf[i].type);
222 static krb5_error_code
223 create_signature(krb5_context context,
224 const heim_oid *eContentType,
226 struct krb5_pk_identity *id,
227 hx509_peer_info peer,
232 if (id->cert == NULL)
233 flags |= HX509_CMS_SIGNATURE_NO_SIGNER;
235 ret = hx509_cms_create_signed_1(context->hx509ctx,
247 pk_copy_error(context, context->hx509ctx, ret,
248 "Create CMS signedData");
256 cert2epi(hx509_context context, void *ctx, hx509_cert c)
258 ExternalPrincipalIdentifiers *ids = ctx;
259 ExternalPrincipalIdentifier id;
260 hx509_name subject = NULL;
267 memset(&id, 0, sizeof(id));
269 ret = hx509_cert_get_subject(c, &subject);
273 if (hx509_name_is_null_p(subject) != 0) {
275 id.subjectName = calloc(1, sizeof(*id.subjectName));
276 if (id.subjectName == NULL) {
277 hx509_name_free(&subject);
278 free_ExternalPrincipalIdentifier(&id);
282 ret = hx509_name_binary(subject, id.subjectName);
284 hx509_name_free(&subject);
285 free_ExternalPrincipalIdentifier(&id);
289 hx509_name_free(&subject);
292 id.issuerAndSerialNumber = calloc(1, sizeof(*id.issuerAndSerialNumber));
293 if (id.issuerAndSerialNumber == NULL) {
294 free_ExternalPrincipalIdentifier(&id);
299 IssuerAndSerialNumber iasn;
303 memset(&iasn, 0, sizeof(iasn));
305 ret = hx509_cert_get_issuer(c, &issuer);
307 free_ExternalPrincipalIdentifier(&id);
311 ret = hx509_name_to_Name(issuer, &iasn.issuer);
312 hx509_name_free(&issuer);
314 free_ExternalPrincipalIdentifier(&id);
318 ret = hx509_cert_get_serialnumber(c, &iasn.serialNumber);
320 free_IssuerAndSerialNumber(&iasn);
321 free_ExternalPrincipalIdentifier(&id);
325 ASN1_MALLOC_ENCODE(IssuerAndSerialNumber,
326 id.issuerAndSerialNumber->data,
327 id.issuerAndSerialNumber->length,
329 free_IssuerAndSerialNumber(&iasn);
332 if (id.issuerAndSerialNumber->length != size)
336 id.subjectKeyIdentifier = NULL;
338 p = realloc(ids->val, sizeof(ids->val[0]) * (ids->len + 1));
340 free_ExternalPrincipalIdentifier(&id);
345 ids->val[ids->len] = id;
351 static krb5_error_code
352 build_edi(krb5_context context,
353 hx509_context hx509ctx,
355 ExternalPrincipalIdentifiers *ids)
357 return hx509_certs_iter_f(hx509ctx, certs, cert2epi, ids);
360 static krb5_error_code
361 build_auth_pack(krb5_context context,
363 krb5_pk_init_ctx ctx,
364 const KDC_REQ_BODY *body,
367 size_t buf_size, len;
374 krb5_clear_error_message(context);
376 memset(&checksum, 0, sizeof(checksum));
378 krb5_us_timeofday(context, &sec, &usec);
379 a->pkAuthenticator.ctime = sec;
380 a->pkAuthenticator.nonce = nonce;
382 ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, body, &len, ret);
386 krb5_abortx(context, "internal error in ASN.1 encoder");
388 ret = krb5_create_checksum(context,
399 ALLOC(a->pkAuthenticator.paChecksum, 1);
400 if (a->pkAuthenticator.paChecksum == NULL) {
401 krb5_set_error_message(context, ENOMEM,
402 N_("malloc: out of memory", ""));
406 ret = krb5_data_copy(a->pkAuthenticator.paChecksum,
407 checksum.checksum.data, checksum.checksum.length);
408 free_Checksum(&checksum);
412 if (ctx->keyex == USE_DH || ctx->keyex == USE_ECDH) {
413 const char *moduli_file;
414 unsigned long dh_min_bits;
418 krb5_data_zero(&dhbuf);
422 moduli_file = krb5_config_get_string(context, NULL,
428 krb5_config_get_int_default(context, NULL, 0,
430 "pkinit_dh_min_bits",
433 ret = _krb5_parse_moduli(context, moduli_file, &ctx->m);
437 ctx->u.dh = DH_new();
438 if (ctx->u.dh == NULL) {
439 krb5_set_error_message(context, ENOMEM,
440 N_("malloc: out of memory", ""));
444 ret = select_dh_group(context, ctx->u.dh, dh_min_bits, ctx->m);
448 if (DH_generate_key(ctx->u.dh) != 1) {
449 krb5_set_error_message(context, ENOMEM,
450 N_("pkinit: failed to generate DH key", ""));
455 if (1 /* support_cached_dh */) {
456 ALLOC(a->clientDHNonce, 1);
457 if (a->clientDHNonce == NULL) {
458 krb5_clear_error_message(context);
461 ret = krb5_data_alloc(a->clientDHNonce, 40);
462 if (a->clientDHNonce == NULL) {
463 krb5_clear_error_message(context);
466 RAND_bytes(a->clientDHNonce->data, a->clientDHNonce->length);
467 ret = krb5_copy_data(context, a->clientDHNonce,
468 &ctx->clientDHNonce);
473 ALLOC(a->clientPublicValue, 1);
474 if (a->clientPublicValue == NULL)
477 if (ctx->keyex == USE_DH) {
480 heim_integer dh_pub_key;
482 ret = der_copy_oid(&asn1_oid_id_dhpublicnumber,
483 &a->clientPublicValue->algorithm.algorithm);
487 memset(&dp, 0, sizeof(dp));
489 ret = BN_to_integer(context, dh->p, &dp.p);
491 free_DomainParameters(&dp);
494 ret = BN_to_integer(context, dh->g, &dp.g);
496 free_DomainParameters(&dp);
499 ret = BN_to_integer(context, dh->q, &dp.q);
501 free_DomainParameters(&dp);
505 dp.validationParms = NULL;
507 a->clientPublicValue->algorithm.parameters =
508 malloc(sizeof(*a->clientPublicValue->algorithm.parameters));
509 if (a->clientPublicValue->algorithm.parameters == NULL) {
510 free_DomainParameters(&dp);
514 ASN1_MALLOC_ENCODE(DomainParameters,
515 a->clientPublicValue->algorithm.parameters->data,
516 a->clientPublicValue->algorithm.parameters->length,
518 free_DomainParameters(&dp);
521 if (size != a->clientPublicValue->algorithm.parameters->length)
522 krb5_abortx(context, "Internal ASN1 encoder error");
524 ret = BN_to_integer(context, dh->pub_key, &dh_pub_key);
528 ASN1_MALLOC_ENCODE(DHPublicKey, dhbuf.data, dhbuf.length,
529 &dh_pub_key, &size, ret);
530 der_free_heim_integer(&dh_pub_key);
533 if (size != dhbuf.length)
534 krb5_abortx(context, "asn1 internal error");
535 } else if (ctx->keyex == USE_ECDH) {
541 /* copy in public key, XXX find the best curve that the server support or use the clients curve if possible */
543 ecp.element = choice_ECParameters_namedCurve;
544 ret = der_copy_oid(&asn1_oid_id_ec_group_secp256r1,
549 ALLOC(a->clientPublicValue->algorithm.parameters, 1);
550 if (a->clientPublicValue->algorithm.parameters == NULL) {
551 free_ECParameters(&ecp);
554 ASN1_MALLOC_ENCODE(ECParameters, p, len, &ecp, &size, ret);
555 free_ECParameters(&ecp);
559 krb5_abortx(context, "asn1 internal error");
561 a->clientPublicValue->algorithm.parameters->data = p;
562 a->clientPublicValue->algorithm.parameters->length = size;
564 /* copy in public key */
566 ret = der_copy_oid(&asn1_oid_id_ecPublicKey,
567 &a->clientPublicValue->algorithm.algorithm);
571 ctx->u.eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
572 if (ctx->u.eckey == NULL)
575 ret = EC_KEY_generate_key(ctx->u.eckey);
579 /* encode onto dhkey */
581 len = i2o_ECPublicKey(ctx->u.eckey, NULL);
585 dhbuf.data = malloc(len);
586 if (dhbuf.data == NULL)
591 len = i2o_ECPublicKey(ctx->u.eckey, &p);
595 /* XXX verify that this is right with RFC3279 */
600 krb5_abortx(context, "internal error");
601 a->clientPublicValue->subjectPublicKey.length = dhbuf.length * 8;
602 a->clientPublicValue->subjectPublicKey.data = dhbuf.data;
606 a->supportedCMSTypes = calloc(1, sizeof(*a->supportedCMSTypes));
607 if (a->supportedCMSTypes == NULL)
610 ret = hx509_crypto_available(context->hx509ctx, HX509_SELECT_ALL, NULL,
611 &a->supportedCMSTypes->val,
612 &a->supportedCMSTypes->len);
620 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
621 _krb5_pk_mk_ContentInfo(krb5_context context,
622 const krb5_data *buf,
624 struct ContentInfo *content_info)
628 ret = der_copy_oid(oid, &content_info->contentType);
631 ALLOC(content_info->content, 1);
632 if (content_info->content == NULL)
634 content_info->content->data = malloc(buf->length);
635 if (content_info->content->data == NULL)
637 memcpy(content_info->content->data, buf->data, buf->length);
638 content_info->content->length = buf->length;
642 static krb5_error_code
643 pk_mk_padata(krb5_context context,
644 krb5_pk_init_ctx ctx,
645 const KDC_REQ_BODY *req_body,
649 struct ContentInfo content_info;
653 krb5_data buf, sd_buf;
656 krb5_data_zero(&buf);
657 krb5_data_zero(&sd_buf);
658 memset(&content_info, 0, sizeof(content_info));
660 if (ctx->type == PKINIT_WIN2K) {
665 memset(&ap, 0, sizeof(ap));
667 /* fill in PKAuthenticator */
668 ret = copy_PrincipalName(req_body->sname, &ap.pkAuthenticator.kdcName);
670 free_AuthPack_Win2k(&ap);
671 krb5_clear_error_message(context);
674 ret = copy_Realm(&req_body->realm, &ap.pkAuthenticator.kdcRealm);
676 free_AuthPack_Win2k(&ap);
677 krb5_clear_error_message(context);
681 krb5_us_timeofday(context, &sec, &usec);
682 ap.pkAuthenticator.ctime = sec;
683 ap.pkAuthenticator.cusec = usec;
684 ap.pkAuthenticator.nonce = nonce;
686 ASN1_MALLOC_ENCODE(AuthPack_Win2k, buf.data, buf.length,
688 free_AuthPack_Win2k(&ap);
690 krb5_set_error_message(context, ret,
691 N_("Failed encoding AuthPackWin: %d", ""),
695 if (buf.length != size)
696 krb5_abortx(context, "internal ASN1 encoder error");
698 oid = &asn1_oid_id_pkcs7_data;
699 } else if (ctx->type == PKINIT_27) {
702 memset(&ap, 0, sizeof(ap));
704 ret = build_auth_pack(context, nonce, ctx, req_body, &ap);
710 ASN1_MALLOC_ENCODE(AuthPack, buf.data, buf.length, &ap, &size, ret);
713 krb5_set_error_message(context, ret,
714 N_("Failed encoding AuthPack: %d", ""),
718 if (buf.length != size)
719 krb5_abortx(context, "internal ASN1 encoder error");
721 oid = &asn1_oid_id_pkauthdata;
723 krb5_abortx(context, "internal pkinit error");
725 ret = create_signature(context, oid, &buf, ctx->id,
727 krb5_data_free(&buf);
731 ret = hx509_cms_wrap_ContentInfo(&asn1_oid_id_pkcs7_signedData, &sd_buf, &buf);
732 krb5_data_free(&sd_buf);
734 krb5_set_error_message(context, ret,
735 N_("ContentInfo wrapping of signedData failed",""));
739 if (ctx->type == PKINIT_WIN2K) {
740 PA_PK_AS_REQ_Win2k winreq;
742 pa_type = KRB5_PADATA_PK_AS_REQ_WIN;
744 memset(&winreq, 0, sizeof(winreq));
746 winreq.signed_auth_pack = buf;
748 ASN1_MALLOC_ENCODE(PA_PK_AS_REQ_Win2k, buf.data, buf.length,
749 &winreq, &size, ret);
750 free_PA_PK_AS_REQ_Win2k(&winreq);
752 } else if (ctx->type == PKINIT_27) {
755 pa_type = KRB5_PADATA_PK_AS_REQ;
757 memset(&req, 0, sizeof(req));
758 req.signedAuthPack = buf;
760 if (ctx->trustedCertifiers) {
762 req.trustedCertifiers = calloc(1, sizeof(*req.trustedCertifiers));
763 if (req.trustedCertifiers == NULL) {
765 krb5_set_error_message(context, ret,
766 N_("malloc: out of memory", ""));
767 free_PA_PK_AS_REQ(&req);
770 ret = build_edi(context, context->hx509ctx,
771 ctx->id->anchors, req.trustedCertifiers);
773 krb5_set_error_message(context, ret,
774 N_("pk-init: failed to build "
775 "trustedCertifiers", ""));
776 free_PA_PK_AS_REQ(&req);
782 ASN1_MALLOC_ENCODE(PA_PK_AS_REQ, buf.data, buf.length,
785 free_PA_PK_AS_REQ(&req);
788 krb5_abortx(context, "internal pkinit error");
790 krb5_set_error_message(context, ret, "PA-PK-AS-REQ %d", (int)ret);
793 if (buf.length != size)
794 krb5_abortx(context, "Internal ASN1 encoder error");
796 ret = krb5_padata_add(context, md, pa_type, buf.data, buf.length);
801 krb5_padata_add(context, md, KRB5_PADATA_PK_AS_09_BINDING, NULL, 0);
804 free_ContentInfo(&content_info);
810 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
811 _krb5_pk_mk_padata(krb5_context context,
815 const KDC_REQ_BODY *req_body,
819 krb5_pk_init_ctx ctx = c;
822 if (ctx->id->certs == NULL && ctx->anonymous == 0) {
823 krb5_set_error_message(context, HEIM_PKINIT_NO_PRIVATE_KEY,
824 N_("PKINIT: No user certificate given", ""));
825 return HEIM_PKINIT_NO_PRIVATE_KEY;
828 win2k_compat = krb5_config_get_bool_default(context, NULL,
836 ctx->require_binding =
837 krb5_config_get_bool_default(context, NULL,
841 "pkinit_win2k_require_binding",
843 ctx->type = PKINIT_WIN2K;
845 ctx->type = PKINIT_27;
848 krb5_config_get_bool_default(context, NULL,
852 "pkinit_require_eku",
854 if (ic_flags & KRB5_INIT_CREDS_NO_C_NO_EKU_CHECK)
855 ctx->require_eku = 0;
856 if (ctx->id->flags & PKINIT_BTMM)
857 ctx->require_eku = 0;
859 ctx->require_krbtgt_otherName =
860 krb5_config_get_bool_default(context, NULL,
864 "pkinit_require_krbtgt_otherName",
867 ctx->require_hostname_match =
868 krb5_config_get_bool_default(context, NULL,
872 "pkinit_require_hostname_match",
875 ctx->trustedCertifiers =
876 krb5_config_get_bool_default(context, NULL,
880 "pkinit_trustedCertifiers",
883 return pk_mk_padata(context, ctx, req_body, nonce, md);
886 static krb5_error_code
887 pk_verify_sign(krb5_context context,
890 struct krb5_pk_identity *id,
891 heim_oid *contentType,
893 struct krb5_pk_cert **signer)
895 hx509_certs signer_certs;
898 /* BTMM is broken in Leo and SnowLeo */
899 if (id->flags & PKINIT_BTMM) {
900 flags |= HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH;
901 flags |= HX509_CMS_VS_NO_KU_CHECK;
902 flags |= HX509_CMS_VS_NO_VALIDATE;
907 ret = hx509_cms_verify_signed(context->hx509ctx,
918 pk_copy_error(context, context->hx509ctx, ret,
919 "CMS verify signed failed");
923 *signer = calloc(1, sizeof(**signer));
924 if (*signer == NULL) {
925 krb5_clear_error_message(context);
930 ret = hx509_get_one_cert(context->hx509ctx, signer_certs, &(*signer)->cert);
932 pk_copy_error(context, context->hx509ctx, ret,
933 "Failed to get on of the signer certs");
938 hx509_certs_free(&signer_certs);
941 hx509_cert_free((*signer)->cert);
950 static krb5_error_code
951 get_reply_key_win(krb5_context context,
952 const krb5_data *content,
956 ReplyKeyPack_Win2k key_pack;
960 ret = decode_ReplyKeyPack_Win2k(content->data,
965 krb5_set_error_message(context, ret,
966 N_("PKINIT decoding reply key failed", ""));
967 free_ReplyKeyPack_Win2k(&key_pack);
971 if (key_pack.nonce != nonce) {
972 krb5_set_error_message(context, ret,
973 N_("PKINIT enckey nonce is wrong", ""));
974 free_ReplyKeyPack_Win2k(&key_pack);
975 return KRB5KRB_AP_ERR_MODIFIED;
978 *key = malloc (sizeof (**key));
980 free_ReplyKeyPack_Win2k(&key_pack);
981 krb5_set_error_message(context, ENOMEM,
982 N_("malloc: out of memory", ""));
986 ret = copy_EncryptionKey(&key_pack.replyKey, *key);
987 free_ReplyKeyPack_Win2k(&key_pack);
989 krb5_set_error_message(context, ret,
990 N_("PKINIT failed copying reply key", ""));
998 static krb5_error_code
999 get_reply_key(krb5_context context,
1000 const krb5_data *content,
1001 const krb5_data *req_buffer,
1002 krb5_keyblock **key)
1004 ReplyKeyPack key_pack;
1005 krb5_error_code ret;
1008 ret = decode_ReplyKeyPack(content->data,
1013 krb5_set_error_message(context, ret,
1014 N_("PKINIT decoding reply key failed", ""));
1015 free_ReplyKeyPack(&key_pack);
1023 * XXX Verify kp.replyKey is a allowed enctype in the
1024 * configuration file
1027 ret = krb5_crypto_init(context, &key_pack.replyKey, 0, &crypto);
1029 free_ReplyKeyPack(&key_pack);
1033 ret = krb5_verify_checksum(context, crypto, 6,
1034 req_buffer->data, req_buffer->length,
1035 &key_pack.asChecksum);
1036 krb5_crypto_destroy(context, crypto);
1038 free_ReplyKeyPack(&key_pack);
1043 *key = malloc (sizeof (**key));
1045 free_ReplyKeyPack(&key_pack);
1046 krb5_set_error_message(context, ENOMEM,
1047 N_("malloc: out of memory", ""));
1051 ret = copy_EncryptionKey(&key_pack.replyKey, *key);
1052 free_ReplyKeyPack(&key_pack);
1054 krb5_set_error_message(context, ret,
1055 N_("PKINIT failed copying reply key", ""));
1064 static krb5_error_code
1065 pk_verify_host(krb5_context context,
1067 const krb5_krbhst_info *hi,
1068 struct krb5_pk_init_ctx_data *ctx,
1069 struct krb5_pk_cert *host)
1071 krb5_error_code ret = 0;
1073 if (ctx->require_eku) {
1074 ret = hx509_cert_check_eku(context->hx509ctx, host->cert,
1075 &asn1_oid_id_pkkdcekuoid, 0);
1077 krb5_set_error_message(context, ret,
1078 N_("No PK-INIT KDC EKU in kdc certificate", ""));
1082 if (ctx->require_krbtgt_otherName) {
1083 hx509_octet_string_list list;
1086 ret = hx509_cert_find_subjectAltName_otherName(context->hx509ctx,
1088 &asn1_oid_id_pkinit_san,
1091 krb5_set_error_message(context, ret,
1092 N_("Failed to find the PK-INIT "
1093 "subjectAltName in the KDC "
1094 "certificate", ""));
1099 for (i = 0; i < list.len; i++) {
1100 KRB5PrincipalName r;
1102 ret = decode_KRB5PrincipalName(list.val[i].data,
1107 krb5_set_error_message(context, ret,
1108 N_("Failed to decode the PK-INIT "
1109 "subjectAltName in the "
1110 "KDC certificate", ""));
1115 if (r.principalName.name_string.len != 2 ||
1116 strcmp(r.principalName.name_string.val[0], KRB5_TGS_NAME) != 0 ||
1117 strcmp(r.principalName.name_string.val[1], realm) != 0 ||
1118 strcmp(r.realm, realm) != 0)
1120 ret = KRB5_KDC_ERR_INVALID_CERTIFICATE;
1121 krb5_set_error_message(context, ret,
1122 N_("KDC have wrong realm name in "
1123 "the certificate", ""));
1126 free_KRB5PrincipalName(&r);
1130 hx509_free_octet_string_list(&list);
1136 ret = hx509_verify_hostname(context->hx509ctx, host->cert,
1137 ctx->require_hostname_match,
1140 hi->ai->ai_addr, hi->ai->ai_addrlen);
1143 krb5_set_error_message(context, ret,
1144 N_("Address mismatch in "
1145 "the KDC certificate", ""));
1150 static krb5_error_code
1151 pk_rd_pa_reply_enckey(krb5_context context,
1153 const heim_octet_string *indata,
1154 const heim_oid *dataType,
1156 krb5_pk_init_ctx ctx,
1158 const krb5_krbhst_info *hi,
1160 const krb5_data *req_buffer,
1162 krb5_keyblock **key)
1164 krb5_error_code ret;
1165 struct krb5_pk_cert *host = NULL;
1167 heim_oid contentType = { 0, NULL };
1168 int flags = HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT;
1170 if (der_heim_oid_cmp(&asn1_oid_id_pkcs7_envelopedData, dataType)) {
1171 krb5_set_error_message(context, EINVAL,
1172 N_("PKINIT: Invalid content type", ""));
1176 if (ctx->type == PKINIT_WIN2K)
1177 flags |= HX509_CMS_UE_ALLOW_WEAK;
1179 ret = hx509_cms_unenvelope(context->hx509ctx,
1189 pk_copy_error(context, context->hx509ctx, ret,
1190 "Failed to unenvelope CMS data in PK-INIT reply");
1193 der_free_oid(&contentType);
1195 /* win2k uses ContentInfo */
1196 if (type == PKINIT_WIN2K) {
1198 heim_octet_string out;
1200 ret = hx509_cms_unwrap_ContentInfo(&content, &type2, &out, NULL);
1202 /* windows LH with interesting CMS packets */
1203 size_t ph = 1 + der_length_len(content.length);
1204 unsigned char *ptr = malloc(content.length + ph);
1207 memcpy(ptr + ph, content.data, content.length);
1209 ret = der_put_length_and_tag (ptr + ph - 1, ph, content.length,
1210 ASN1_C_UNIV, CONS, UT_Sequence, &l);
1215 content.length += ph;
1217 ret = hx509_cms_unwrap_ContentInfo(&content, &type2, &out, NULL);
1221 if (der_heim_oid_cmp(&type2, &asn1_oid_id_pkcs7_signedData)) {
1222 ret = EINVAL; /* XXX */
1223 krb5_set_error_message(context, ret,
1224 N_("PKINIT: Invalid content type", ""));
1225 der_free_oid(&type2);
1226 der_free_octet_string(&out);
1229 der_free_oid(&type2);
1230 krb5_data_free(&content);
1231 ret = krb5_data_copy(&content, out.data, out.length);
1232 der_free_octet_string(&out);
1234 krb5_set_error_message(context, ret,
1235 N_("malloc: out of memory", ""));
1240 ret = pk_verify_sign(context,
1250 /* make sure that it is the kdc's certificate */
1251 ret = pk_verify_host(context, realm, hi, ctx, host);
1257 if (type == PKINIT_WIN2K) {
1258 if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkcs7_data) != 0) {
1259 ret = KRB5KRB_AP_ERR_MSG_TYPE;
1260 krb5_set_error_message(context, ret, "PKINIT: reply key, wrong oid");
1264 if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkrkeydata) != 0) {
1265 ret = KRB5KRB_AP_ERR_MSG_TYPE;
1266 krb5_set_error_message(context, ret, "PKINIT: reply key, wrong oid");
1274 ret = get_reply_key(context, &content, req_buffer, key);
1275 if (ret != 0 && ctx->require_binding == 0)
1276 ret = get_reply_key_win(context, &content, nonce, key);
1279 ret = get_reply_key(context, &content, req_buffer, key);
1285 /* XXX compare given etype with key->etype */
1289 _krb5_pk_cert_free(host);
1290 der_free_oid(&contentType);
1291 krb5_data_free(&content);
1296 static krb5_error_code
1297 pk_rd_pa_reply_dh(krb5_context context,
1298 const heim_octet_string *indata,
1299 const heim_oid *dataType,
1301 krb5_pk_init_ctx ctx,
1303 const krb5_krbhst_info *hi,
1308 krb5_keyblock **key)
1310 const unsigned char *p;
1311 unsigned char *dh_gen_key = NULL;
1312 struct krb5_pk_cert *host = NULL;
1313 BIGNUM *kdc_dh_pubkey = NULL;
1314 KDCDHKeyInfo kdc_dh_info;
1315 heim_oid contentType = { 0, NULL };
1317 krb5_error_code ret;
1318 int dh_gen_keylen = 0;
1321 krb5_data_zero(&content);
1322 memset(&kdc_dh_info, 0, sizeof(kdc_dh_info));
1324 if (der_heim_oid_cmp(&asn1_oid_id_pkcs7_signedData, dataType)) {
1325 krb5_set_error_message(context, EINVAL,
1326 N_("PKINIT: Invalid content type", ""));
1330 ret = pk_verify_sign(context,
1340 /* make sure that it is the kdc's certificate */
1341 ret = pk_verify_host(context, realm, hi, ctx, host);
1345 if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkdhkeydata)) {
1346 ret = KRB5KRB_AP_ERR_MSG_TYPE;
1347 krb5_set_error_message(context, ret,
1348 N_("pkinit - dh reply contains wrong oid", ""));
1352 ret = decode_KDCDHKeyInfo(content.data,
1358 krb5_set_error_message(context, ret,
1359 N_("pkinit - failed to decode "
1360 "KDC DH Key Info", ""));
1364 if (kdc_dh_info.nonce != nonce) {
1365 ret = KRB5KRB_AP_ERR_MODIFIED;
1366 krb5_set_error_message(context, ret,
1367 N_("PKINIT: DH nonce is wrong", ""));
1371 if (kdc_dh_info.dhKeyExpiration) {
1373 ret = KRB5KRB_ERR_GENERIC;
1374 krb5_set_error_message(context, ret,
1375 N_("pkinit; got key expiration "
1376 "without server nonce", ""));
1380 ret = KRB5KRB_ERR_GENERIC;
1381 krb5_set_error_message(context, ret,
1382 N_("pkinit; got DH reuse but no "
1383 "client nonce", ""));
1388 ret = KRB5KRB_ERR_GENERIC;
1389 krb5_set_error_message(context, ret,
1390 N_("pkinit: got server nonce "
1391 "without key expiration", ""));
1398 p = kdc_dh_info.subjectPublicKey.data;
1399 size = (kdc_dh_info.subjectPublicKey.length + 7) / 8;
1401 if (ctx->keyex == USE_DH) {
1403 ret = decode_DHPublicKey(p, size, &k, NULL);
1405 krb5_set_error_message(context, ret,
1406 N_("pkinit: can't decode "
1407 "without key expiration", ""));
1411 kdc_dh_pubkey = integer_to_BN(context, "DHPublicKey", &k);
1412 free_DHPublicKey(&k);
1413 if (kdc_dh_pubkey == NULL) {
1419 size = DH_size(ctx->u.dh);
1421 dh_gen_key = malloc(size);
1422 if (dh_gen_key == NULL) {
1424 krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
1428 dh_gen_keylen = DH_compute_key(dh_gen_key, kdc_dh_pubkey, ctx->u.dh);
1429 if (dh_gen_keylen == -1) {
1430 ret = KRB5KRB_ERR_GENERIC;
1432 krb5_set_error_message(context, ret,
1433 N_("PKINIT: Can't compute Diffie-Hellman key", ""));
1436 if (dh_gen_keylen < size) {
1437 size -= dh_gen_keylen;
1438 memmove(dh_gen_key + size, dh_gen_key, dh_gen_keylen);
1439 memset(dh_gen_key, 0, size);
1444 const EC_GROUP *group;
1445 EC_KEY *public = NULL;
1447 group = EC_KEY_get0_group(ctx->u.eckey);
1449 public = EC_KEY_new();
1450 if (public == NULL) {
1454 if (EC_KEY_set_group(public, group) != 1) {
1455 EC_KEY_free(public);
1460 if (o2i_ECPublicKey(&public, &p, size) == NULL) {
1461 EC_KEY_free(public);
1462 ret = KRB5KRB_ERR_GENERIC;
1463 krb5_set_error_message(context, ret,
1464 N_("PKINIT: Can't parse ECDH public key", ""));
1468 size = (EC_GROUP_get_degree(group) + 7) / 8;
1469 dh_gen_key = malloc(size);
1470 if (dh_gen_key == NULL) {
1471 EC_KEY_free(public);
1473 krb5_set_error_message(context, ret,
1474 N_("malloc: out of memory", ""));
1477 dh_gen_keylen = ECDH_compute_key(dh_gen_key, size,
1478 EC_KEY_get0_public_key(public), ctx->u.eckey, NULL);
1479 EC_KEY_free(public);
1480 if (dh_gen_keylen == -1) {
1481 ret = KRB5KRB_ERR_GENERIC;
1483 krb5_set_error_message(context, ret,
1484 N_("PKINIT: Can't compute ECDH public key", ""));
1492 if (dh_gen_keylen <= 0) {
1494 krb5_set_error_message(context, ret,
1495 N_("PKINIT: resulting DH key <= 0", ""));
1500 *key = malloc (sizeof (**key));
1503 krb5_set_error_message(context, ret,
1504 N_("malloc: out of memory", ""));
1508 ret = _krb5_pk_octetstring2key(context,
1510 dh_gen_key, dh_gen_keylen,
1514 krb5_set_error_message(context, ret,
1515 N_("PKINIT: can't create key from DH key", ""));
1523 BN_free(kdc_dh_pubkey);
1525 memset(dh_gen_key, 0, dh_gen_keylen);
1529 _krb5_pk_cert_free(host);
1531 krb5_data_free(&content);
1532 der_free_oid(&contentType);
1533 free_KDCDHKeyInfo(&kdc_dh_info);
1538 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1539 _krb5_pk_rd_pa_reply(krb5_context context,
1543 const krb5_krbhst_info *hi,
1545 const krb5_data *req_buffer,
1547 krb5_keyblock **key)
1549 krb5_pk_init_ctx ctx = c;
1550 krb5_error_code ret;
1553 /* Check for IETF PK-INIT first */
1554 if (ctx->type == PKINIT_27) {
1556 heim_octet_string os, data;
1559 if (pa->padata_type != KRB5_PADATA_PK_AS_REP) {
1560 krb5_set_error_message(context, EINVAL,
1561 N_("PKINIT: wrong padata recv", ""));
1565 ret = decode_PA_PK_AS_REP(pa->padata_value.data,
1566 pa->padata_value.length,
1570 krb5_set_error_message(context, ret,
1571 N_("Failed to decode pkinit AS rep", ""));
1575 switch (rep.element) {
1576 case choice_PA_PK_AS_REP_dhInfo:
1577 _krb5_debug(context, 5, "krb5_get_init_creds: using pkinit dh");
1578 os = rep.u.dhInfo.dhSignedData;
1580 case choice_PA_PK_AS_REP_encKeyPack:
1581 _krb5_debug(context, 5, "krb5_get_init_creds: using kinit enc reply key");
1582 os = rep.u.encKeyPack;
1585 PA_PK_AS_REP_BTMM btmm;
1586 free_PA_PK_AS_REP(&rep);
1587 memset(&rep, 0, sizeof(rep));
1589 _krb5_debug(context, 5, "krb5_get_init_creds: using BTMM kinit enc reply key");
1591 ret = decode_PA_PK_AS_REP_BTMM(pa->padata_value.data,
1592 pa->padata_value.length,
1596 krb5_set_error_message(context, EINVAL,
1597 N_("PKINIT: -27 reply "
1598 "invalid content type", ""));
1602 if (btmm.dhSignedData || btmm.encKeyPack == NULL) {
1603 free_PA_PK_AS_REP_BTMM(&btmm);
1605 krb5_set_error_message(context, ret,
1606 N_("DH mode not supported for BTMM mode", ""));
1611 * Transform to IETF style PK-INIT reply so that free works below
1614 rep.element = choice_PA_PK_AS_REP_encKeyPack;
1615 rep.u.encKeyPack.data = btmm.encKeyPack->data;
1616 rep.u.encKeyPack.length = btmm.encKeyPack->length;
1617 btmm.encKeyPack->data = NULL;
1618 btmm.encKeyPack->length = 0;
1619 free_PA_PK_AS_REP_BTMM(&btmm);
1620 os = rep.u.encKeyPack;
1624 ret = hx509_cms_unwrap_ContentInfo(&os, &oid, &data, NULL);
1626 free_PA_PK_AS_REP(&rep);
1627 krb5_set_error_message(context, ret,
1628 N_("PKINIT: failed to unwrap CI", ""));
1632 switch (rep.element) {
1633 case choice_PA_PK_AS_REP_dhInfo:
1634 ret = pk_rd_pa_reply_dh(context, &data, &oid, realm, ctx, etype, hi,
1636 rep.u.dhInfo.serverDHNonce,
1639 case choice_PA_PK_AS_REP_encKeyPack:
1640 ret = pk_rd_pa_reply_enckey(context, PKINIT_27, &data, &oid, realm,
1641 ctx, etype, hi, nonce, req_buffer, pa, key);
1644 krb5_abortx(context, "pk-init as-rep case not possible to happen");
1646 der_free_octet_string(&data);
1648 free_PA_PK_AS_REP(&rep);
1650 } else if (ctx->type == PKINIT_WIN2K) {
1651 PA_PK_AS_REP_Win2k w2krep;
1653 /* Check for Windows encoding of the AS-REP pa data */
1655 #if 0 /* should this be ? */
1656 if (pa->padata_type != KRB5_PADATA_PK_AS_REP) {
1657 krb5_set_error_message(context, EINVAL,
1658 "PKINIT: wrong padata recv");
1663 memset(&w2krep, 0, sizeof(w2krep));
1665 ret = decode_PA_PK_AS_REP_Win2k(pa->padata_value.data,
1666 pa->padata_value.length,
1670 krb5_set_error_message(context, ret,
1671 N_("PKINIT: Failed decoding windows "
1672 "pkinit reply %d", ""), (int)ret);
1676 krb5_clear_error_message(context);
1678 switch (w2krep.element) {
1679 case choice_PA_PK_AS_REP_Win2k_encKeyPack: {
1680 heim_octet_string data;
1683 ret = hx509_cms_unwrap_ContentInfo(&w2krep.u.encKeyPack,
1685 free_PA_PK_AS_REP_Win2k(&w2krep);
1687 krb5_set_error_message(context, ret,
1688 N_("PKINIT: failed to unwrap CI", ""));
1692 ret = pk_rd_pa_reply_enckey(context, PKINIT_WIN2K, &data, &oid, realm,
1693 ctx, etype, hi, nonce, req_buffer, pa, key);
1694 der_free_octet_string(&data);
1700 free_PA_PK_AS_REP_Win2k(&w2krep);
1702 krb5_set_error_message(context, ret,
1703 N_("PKINIT: win2k reply invalid "
1704 "content type", ""));
1710 krb5_set_error_message(context, ret,
1711 N_("PKINIT: unknown reply type", ""));
1718 krb5_context context;
1719 krb5_prompter_fct prompter;
1720 void *prompter_data;
1724 hx_pass_prompter(void *data, const hx509_prompt *prompter)
1726 krb5_error_code ret;
1728 krb5_data password_data;
1729 struct prompter *p = data;
1731 password_data.data = prompter->reply.data;
1732 password_data.length = prompter->reply.length;
1734 prompt.prompt = prompter->prompt;
1735 prompt.hidden = hx509_prompt_hidden(prompter->type);
1736 prompt.reply = &password_data;
1738 switch (prompter->type) {
1739 case HX509_PROMPT_TYPE_INFO:
1740 prompt.type = KRB5_PROMPT_TYPE_INFO;
1742 case HX509_PROMPT_TYPE_PASSWORD:
1743 case HX509_PROMPT_TYPE_QUESTION:
1745 prompt.type = KRB5_PROMPT_TYPE_PASSWORD;
1749 ret = (*p->prompter)(p->context, p->prompter_data, NULL, NULL, 1, &prompt);
1751 memset (prompter->reply.data, 0, prompter->reply.length);
1757 static krb5_error_code
1758 _krb5_pk_set_user_id(krb5_context context,
1759 krb5_principal principal,
1760 krb5_pk_init_ctx ctx,
1761 struct hx509_certs_data *certs)
1763 hx509_certs c = hx509_certs_ref(certs);
1764 hx509_query *q = NULL;
1768 hx509_certs_free(&ctx->id->certs);
1769 if (ctx->id->cert) {
1770 hx509_cert_free(ctx->id->cert);
1771 ctx->id->cert = NULL;
1777 ret = hx509_query_alloc(context->hx509ctx, &q);
1779 pk_copy_error(context, context->hx509ctx, ret,
1780 "Allocate query to find signing certificate");
1784 hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
1785 hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE);
1787 if (principal && strncmp("LKDC:SHA1.", krb5_principal_get_realm(context, principal), 9) == 0) {
1788 ctx->id->flags |= PKINIT_BTMM;
1791 ret = find_cert(context, ctx->id, q, &ctx->id->cert);
1792 hx509_query_free(context->hx509ctx, q);
1794 if (ret == 0 && _krb5_have_debug(context, 2)) {
1799 ret = hx509_cert_get_subject(ctx->id->cert, &name);
1803 ret = hx509_name_to_string(name, &str);
1804 hx509_name_free(&name);
1808 ret = hx509_cert_get_serialnumber(ctx->id->cert, &i);
1814 ret = der_print_hex_heim_integer(&i, &sn);
1815 der_free_heim_integer(&i);
1821 _krb5_debug(context, 2, "using cert: subject: %s sn: %s", str, sn);
1830 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1831 _krb5_pk_load_id(krb5_context context,
1832 struct krb5_pk_identity **ret_id,
1833 const char *user_id,
1834 const char *anchor_id,
1835 char * const *chain_list,
1836 char * const *revoke_list,
1837 krb5_prompter_fct prompter,
1838 void *prompter_data,
1841 struct krb5_pk_identity *id = NULL;
1847 if (anchor_id == NULL) {
1848 krb5_set_error_message(context, HEIM_PKINIT_NO_VALID_CA,
1849 N_("PKINIT: No anchor given", ""));
1850 return HEIM_PKINIT_NO_VALID_CA;
1855 id = calloc(1, sizeof(*id));
1857 krb5_set_error_message(context, ENOMEM,
1858 N_("malloc: out of memory", ""));
1865 ret = hx509_lock_init(context->hx509ctx, &lock);
1867 pk_copy_error(context, context->hx509ctx, ret, "Failed init lock");
1871 if (password && password[0])
1872 hx509_lock_add_password(lock, password);
1875 p.context = context;
1876 p.prompter = prompter;
1877 p.prompter_data = prompter_data;
1879 ret = hx509_lock_set_prompter(lock, hx_pass_prompter, &p);
1881 hx509_lock_free(lock);
1886 ret = hx509_certs_init(context->hx509ctx, user_id, 0, lock, &id->certs);
1887 hx509_lock_free(lock);
1889 pk_copy_error(context, context->hx509ctx, ret,
1890 "Failed to init cert certs");
1897 ret = hx509_certs_init(context->hx509ctx, anchor_id, 0, NULL, &id->anchors);
1899 pk_copy_error(context, context->hx509ctx, ret,
1900 "Failed to init anchors");
1904 ret = hx509_certs_init(context->hx509ctx, "MEMORY:pkinit-cert-chain",
1905 0, NULL, &id->certpool);
1907 pk_copy_error(context, context->hx509ctx, ret,
1908 "Failed to init chain");
1912 while (chain_list && *chain_list) {
1913 ret = hx509_certs_append(context->hx509ctx, id->certpool,
1916 pk_copy_error(context, context->hx509ctx, ret,
1917 "Failed to laod chain %s",
1925 ret = hx509_revoke_init(context->hx509ctx, &id->revokectx);
1927 pk_copy_error(context, context->hx509ctx, ret,
1928 "Failed init revoke list");
1932 while (*revoke_list) {
1933 ret = hx509_revoke_add_crl(context->hx509ctx,
1937 pk_copy_error(context, context->hx509ctx, ret,
1938 "Failed load revoke list");
1944 hx509_context_set_missing_revoke(context->hx509ctx, 1);
1946 ret = hx509_verify_init_ctx(context->hx509ctx, &id->verify_ctx);
1948 pk_copy_error(context, context->hx509ctx, ret,
1949 "Failed init verify context");
1953 hx509_verify_attach_anchors(id->verify_ctx, id->anchors);
1954 hx509_verify_attach_revoke(id->verify_ctx, id->revokectx);
1958 hx509_verify_destroy_ctx(id->verify_ctx);
1959 hx509_certs_free(&id->certs);
1960 hx509_certs_free(&id->anchors);
1961 hx509_certs_free(&id->certpool);
1962 hx509_revoke_free(&id->revokectx);
1975 pk_copy_error(krb5_context context,
1976 hx509_context hx509ctx,
1986 ret = vasprintf(&f, fmt, va);
1988 if (ret == -1 || f == NULL) {
1989 krb5_clear_error_message(context);
1993 s = hx509_get_error_string(hx509ctx, hxret);
1995 krb5_clear_error_message(context);
1999 krb5_set_error_message(context, hxret, "%s: %s", f, s);
2005 parse_integer(krb5_context context, char **p, const char *file, int lineno,
2006 const char *name, heim_integer *integer)
2010 p1 = strsep(p, " \t");
2012 krb5_set_error_message(context, EINVAL,
2013 N_("moduli file %s missing %s on line %d", ""),
2014 file, name, lineno);
2017 ret = der_parse_hex_heim_integer(p1, integer);
2019 krb5_set_error_message(context, ret,
2020 N_("moduli file %s failed parsing %s "
2022 file, name, lineno);
2030 _krb5_parse_moduli_line(krb5_context context,
2034 struct krb5_dh_moduli **m)
2036 struct krb5_dh_moduli *m1;
2042 m1 = calloc(1, sizeof(*m1));
2044 krb5_set_error_message(context, ENOMEM,
2045 N_("malloc: out of memory", ""));
2049 while (isspace((unsigned char)*p))
2057 p1 = strsep(&p, " \t");
2059 krb5_set_error_message(context, ret,
2060 N_("moduli file %s missing name on line %d", ""),
2064 m1->name = strdup(p1);
2065 if (m1->name == NULL) {
2067 krb5_set_error_message(context, ret, N_("malloc: out of memeory", ""));
2071 p1 = strsep(&p, " \t");
2073 krb5_set_error_message(context, ret,
2074 N_("moduli file %s missing bits on line %d", ""),
2079 m1->bits = atoi(p1);
2080 if (m1->bits == 0) {
2081 krb5_set_error_message(context, ret,
2082 N_("moduli file %s have un-parsable "
2083 "bits on line %d", ""), file, lineno);
2087 ret = parse_integer(context, &p, file, lineno, "p", &m1->p);
2090 ret = parse_integer(context, &p, file, lineno, "g", &m1->g);
2093 ret = parse_integer(context, &p, file, lineno, "q", &m1->q);
2102 der_free_heim_integer(&m1->p);
2103 der_free_heim_integer(&m1->g);
2104 der_free_heim_integer(&m1->q);
2110 _krb5_free_moduli(struct krb5_dh_moduli **moduli)
2113 for (i = 0; moduli[i] != NULL; i++) {
2114 free(moduli[i]->name);
2115 der_free_heim_integer(&moduli[i]->p);
2116 der_free_heim_integer(&moduli[i]->g);
2117 der_free_heim_integer(&moduli[i]->q);
2123 static const char *default_moduli_RFC2412_MODP_group2 =
2125 "RFC2412-MODP-group2 "
2129 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
2130 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
2131 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
2132 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
2133 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
2134 "FFFFFFFF" "FFFFFFFF "
2138 "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68"
2139 "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E"
2140 "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122"
2141 "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6"
2142 "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F67329C0"
2143 "FFFFFFFF" "FFFFFFFF";
2145 static const char *default_moduli_rfc3526_MODP_group14 =
2147 "rfc3526-MODP-group14 "
2151 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
2152 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
2153 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
2154 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
2155 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D"
2156 "C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"
2157 "83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"
2158 "670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"
2159 "E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"
2160 "DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
2161 "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF "
2165 "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68"
2166 "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E"
2167 "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122"
2168 "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6"
2169 "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F6722D9E"
2170 "E1003E5C" "50B1DF82" "CC6D241B" "0E2AE9CD" "348B1FD4" "7E9267AF"
2171 "C1B2AE91" "EE51D6CB" "0E3179AB" "1042A95D" "CF6A9483" "B84B4B36"
2172 "B3861AA7" "255E4C02" "78BA3604" "650C10BE" "19482F23" "171B671D"
2173 "F1CF3B96" "0C074301" "CD93C1D1" "7603D147" "DAE2AEF8" "37A62964"
2174 "EF15E5FB" "4AAC0B8C" "1CCAA4BE" "754AB572" "8AE9130C" "4C7D0288"
2175 "0AB9472D" "45565534" "7FFFFFFF" "FFFFFFFF";
2178 _krb5_parse_moduli(krb5_context context, const char *file,
2179 struct krb5_dh_moduli ***moduli)
2181 /* name bits P G Q */
2182 krb5_error_code ret;
2183 struct krb5_dh_moduli **m = NULL, **m2;
2186 int lineno = 0, n = 0;
2190 m = calloc(1, sizeof(m[0]) * 3);
2192 krb5_set_error_message(context, ENOMEM,
2193 N_("malloc: out of memory", ""));
2197 strlcpy(buf, default_moduli_rfc3526_MODP_group14, sizeof(buf));
2198 ret = _krb5_parse_moduli_line(context, "builtin", 1, buf, &m[0]);
2200 _krb5_free_moduli(m);
2205 strlcpy(buf, default_moduli_RFC2412_MODP_group2, sizeof(buf));
2206 ret = _krb5_parse_moduli_line(context, "builtin", 1, buf, &m[1]);
2208 _krb5_free_moduli(m);
2217 f = fopen(file, "r");
2224 while(fgets(buf, sizeof(buf), f) != NULL) {
2225 struct krb5_dh_moduli *element;
2227 buf[strcspn(buf, "\n")] = '\0';
2230 m2 = realloc(m, (n + 2) * sizeof(m[0]));
2232 _krb5_free_moduli(m);
2233 krb5_set_error_message(context, ENOMEM,
2234 N_("malloc: out of memory", ""));
2241 ret = _krb5_parse_moduli_line(context, file, lineno, buf, &element);
2243 _krb5_free_moduli(m);
2246 if (element == NULL)
2258 _krb5_dh_group_ok(krb5_context context, unsigned long bits,
2259 heim_integer *p, heim_integer *g, heim_integer *q,
2260 struct krb5_dh_moduli **moduli,
2268 for (i = 0; moduli[i] != NULL; i++) {
2269 if (der_heim_integer_cmp(&moduli[i]->g, g) == 0 &&
2270 der_heim_integer_cmp(&moduli[i]->p, p) == 0 &&
2271 (q == NULL || der_heim_integer_cmp(&moduli[i]->q, q) == 0))
2273 if (bits && bits > moduli[i]->bits) {
2274 krb5_set_error_message(context,
2275 KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED,
2276 N_("PKINIT: DH group parameter %s "
2277 "no accepted, not enough bits "
2280 return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
2283 *name = strdup(moduli[i]->name);
2287 krb5_set_error_message(context,
2288 KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED,
2289 N_("PKINIT: DH group parameter no ok", ""));
2290 return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
2294 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
2295 _krb5_get_init_creds_opt_free_pkinit(krb5_get_init_creds_opt *opt)
2298 krb5_pk_init_ctx ctx;
2300 if (opt->opt_private == NULL || opt->opt_private->pk_init_ctx == NULL)
2302 ctx = opt->opt_private->pk_init_ctx;
2303 switch (ctx->keyex) {
2313 EC_KEY_free(ctx->u.eckey);
2318 hx509_verify_destroy_ctx(ctx->id->verify_ctx);
2319 hx509_certs_free(&ctx->id->certs);
2320 hx509_cert_free(ctx->id->cert);
2321 hx509_certs_free(&ctx->id->anchors);
2322 hx509_certs_free(&ctx->id->certpool);
2324 if (ctx->clientDHNonce) {
2325 krb5_free_data(NULL, ctx->clientDHNonce);
2326 ctx->clientDHNonce = NULL;
2329 _krb5_free_moduli(ctx->m);
2333 free(opt->opt_private->pk_init_ctx);
2334 opt->opt_private->pk_init_ctx = NULL;
2338 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2339 krb5_get_init_creds_opt_set_pkinit(krb5_context context,
2340 krb5_get_init_creds_opt *opt,
2341 krb5_principal principal,
2342 const char *user_id,
2343 const char *x509_anchors,
2344 char * const * pool,
2345 char * const * pki_revoke,
2347 krb5_prompter_fct prompter,
2348 void *prompter_data,
2352 krb5_error_code ret;
2353 char *anchors = NULL;
2355 if (opt->opt_private == NULL) {
2356 krb5_set_error_message(context, EINVAL,
2357 N_("PKINIT: on non extendable opt", ""));
2361 opt->opt_private->pk_init_ctx =
2362 calloc(1, sizeof(*opt->opt_private->pk_init_ctx));
2363 if (opt->opt_private->pk_init_ctx == NULL) {
2364 krb5_set_error_message(context, ENOMEM,
2365 N_("malloc: out of memory", ""));
2368 opt->opt_private->pk_init_ctx->require_binding = 0;
2369 opt->opt_private->pk_init_ctx->require_eku = 1;
2370 opt->opt_private->pk_init_ctx->require_krbtgt_otherName = 1;
2371 opt->opt_private->pk_init_ctx->peer = NULL;
2373 /* XXX implement krb5_appdefault_strings */
2375 pool = krb5_config_get_strings(context, NULL,
2380 if (pki_revoke == NULL)
2381 pki_revoke = krb5_config_get_strings(context, NULL,
2386 if (x509_anchors == NULL) {
2387 krb5_appdefault_string(context, "kinit",
2388 krb5_principal_get_realm(context, principal),
2389 "pkinit_anchors", NULL, &anchors);
2390 x509_anchors = anchors;
2394 opt->opt_private->pk_init_ctx->anonymous = 1;
2396 ret = _krb5_pk_load_id(context,
2397 &opt->opt_private->pk_init_ctx->id,
2406 free(opt->opt_private->pk_init_ctx);
2407 opt->opt_private->pk_init_ctx = NULL;
2411 if (opt->opt_private->pk_init_ctx->id->certs) {
2412 _krb5_pk_set_user_id(context,
2414 opt->opt_private->pk_init_ctx,
2415 opt->opt_private->pk_init_ctx->id->certs);
2417 opt->opt_private->pk_init_ctx->id->cert = NULL;
2419 if ((flags & 2) == 0) {
2420 hx509_context hx509ctx = context->hx509ctx;
2421 hx509_cert cert = opt->opt_private->pk_init_ctx->id->cert;
2423 opt->opt_private->pk_init_ctx->keyex = USE_DH;
2426 * If its a ECDSA certs, lets select ECDSA as the keyex algorithm.
2429 AlgorithmIdentifier alg;
2431 ret = hx509_cert_get_SPKI_AlgorithmIdentifier(hx509ctx, cert, &alg);
2433 if (der_heim_oid_cmp(&alg.algorithm, &asn1_oid_id_ecPublicKey) == 0)
2434 opt->opt_private->pk_init_ctx->keyex = USE_ECDH;
2435 free_AlgorithmIdentifier(&alg);
2440 opt->opt_private->pk_init_ctx->keyex = USE_RSA;
2442 if (opt->opt_private->pk_init_ctx->id->certs == NULL) {
2443 krb5_set_error_message(context, EINVAL,
2444 N_("No anonymous pkinit support in RSA mode", ""));
2451 krb5_set_error_message(context, EINVAL,
2452 N_("no support for PKINIT compiled in", ""));
2457 krb5_error_code KRB5_LIB_FUNCTION
2458 _krb5_get_init_creds_opt_set_pkinit_user_certs(krb5_context context,
2459 krb5_get_init_creds_opt *opt,
2460 struct hx509_certs_data *certs)
2463 if (opt->opt_private == NULL) {
2464 krb5_set_error_message(context, EINVAL,
2465 N_("PKINIT: on non extendable opt", ""));
2468 if (opt->opt_private->pk_init_ctx == NULL) {
2469 krb5_set_error_message(context, EINVAL,
2470 N_("PKINIT: on pkinit context", ""));
2474 _krb5_pk_set_user_id(context, NULL, opt->opt_private->pk_init_ctx, certs);
2478 krb5_set_error_message(context, EINVAL,
2479 N_("no support for PKINIT compiled in", ""));
2487 get_ms_san(hx509_context context, hx509_cert cert, char **upn)
2489 hx509_octet_string_list list;
2494 ret = hx509_cert_find_subjectAltName_otherName(context,
2496 &asn1_oid_id_pkinit_ms_san,
2501 if (list.len > 0 && list.val[0].length > 0)
2502 ret = decode_MS_UPN_SAN(list.val[0].data, list.val[0].length,
2506 hx509_free_octet_string_list(&list);
2512 find_ms_san(hx509_context context, hx509_cert cert, void *ctx)
2517 ret = get_ms_san(context, cert, &upn);
2528 * Private since it need to be redesigned using krb5_get_init_creds()
2531 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2532 _krb5_pk_enterprise_cert(krb5_context context,
2533 const char *user_id,
2534 krb5_const_realm realm,
2535 krb5_principal *principal,
2536 struct hx509_certs_data **res)
2539 krb5_error_code ret;
2540 hx509_certs certs, result;
2549 if (user_id == NULL) {
2550 krb5_set_error_message(context, ENOENT, "no user id");
2554 ret = hx509_certs_init(context->hx509ctx, user_id, 0, NULL, &certs);
2556 pk_copy_error(context, context->hx509ctx, ret,
2557 "Failed to init cert certs");
2561 ret = hx509_query_alloc(context->hx509ctx, &q);
2563 krb5_set_error_message(context, ret, "out of memory");
2564 hx509_certs_free(&certs);
2568 hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
2569 hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE);
2570 hx509_query_match_eku(q, &asn1_oid_id_pkinit_ms_eku);
2571 hx509_query_match_cmp_func(q, find_ms_san, NULL);
2573 ret = hx509_certs_filter(context->hx509ctx, certs, q, &result);
2574 hx509_query_free(context->hx509ctx, q);
2575 hx509_certs_free(&certs);
2577 pk_copy_error(context, context->hx509ctx, ret,
2578 "Failed to find PKINIT certificate");
2582 ret = hx509_get_one_cert(context->hx509ctx, result, &cert);
2583 hx509_certs_free(&result);
2585 pk_copy_error(context, context->hx509ctx, ret,
2586 "Failed to get one cert");
2590 ret = get_ms_san(context->hx509ctx, cert, &name);
2592 pk_copy_error(context, context->hx509ctx, ret,
2593 "Failed to get MS SAN");
2597 ret = krb5_make_principal(context, principal, realm, name, NULL);
2602 krb5_principal_set_type(context, *principal, KRB5_NT_ENTERPRISE_PRINCIPAL);
2605 ret = hx509_certs_init(context->hx509ctx, "MEMORY:", 0, NULL, res);
2607 hx509_cert_free(cert);
2611 ret = hx509_certs_add(context->hx509ctx, *res, cert);
2613 hx509_certs_free(res);
2619 hx509_cert_free(cert);
2623 krb5_set_error_message(context, EINVAL,
2624 N_("no support for PKINIT compiled in", ""));