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, const 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;
140 m = moduli[1]; /* XXX */
142 m = moduli[0]; /* XXX */
145 for (i = 0; moduli[i] != NULL; i++) {
146 if (bits < moduli[i]->bits)
149 if (moduli[i] == NULL) {
150 krb5_set_error_message(context, EINVAL,
151 N_("Did not find a DH group parameter "
152 "matching requirement of %lu bits", ""),
159 p = integer_to_BN(context, "p", &m->p);
160 g = integer_to_BN(context, "g", &m->g);
161 q = integer_to_BN(context, "q", &m->q);
162 if (p == NULL || g == NULL || q == NULL) {
169 if (DH_set0_pqg(dh, p, q, g) != 1) {
185 * Try searchin the key by to use by first looking for for PK-INIT
186 * EKU, then the Microsoft smart card EKU and last, no special EKU at all.
189 static krb5_error_code
190 find_cert(krb5_context context, struct krb5_pk_identity *id,
191 hx509_query *q, hx509_cert *cert)
193 struct certfind cf[4] = {
199 int ret = HX509_CERT_NOT_FOUND;
201 unsigned oids[] = { 1, 2, 840, 113635, 100, 3, 2, 1 };
202 const heim_oid mobileMe = { sizeof(oids)/sizeof(oids[0]), oids };
205 if (id->flags & PKINIT_BTMM)
208 cf[0].oid = &mobileMe;
209 cf[1].oid = &asn1_oid_id_pkekuoid;
210 cf[2].oid = &asn1_oid_id_pkinit_ms_eku;
213 for (i = start; i < sizeof(cf)/sizeof(cf[0]); i++) {
214 ret = hx509_query_match_eku(q, cf[i].oid);
216 pk_copy_error(context, context->hx509ctx, ret,
217 "Failed setting %s OID", cf[i].type);
221 ret = hx509_certs_find(context->hx509ctx, id->certs, q, cert);
224 pk_copy_error(context, context->hx509ctx, ret,
225 "Failed finding certificate with %s OID", cf[i].type);
231 static krb5_error_code
232 create_signature(krb5_context context,
233 const heim_oid *eContentType,
235 struct krb5_pk_identity *id,
236 hx509_peer_info peer,
241 if (id->cert == NULL)
242 flags |= HX509_CMS_SIGNATURE_NO_SIGNER;
244 ret = hx509_cms_create_signed_1(context->hx509ctx,
256 pk_copy_error(context, context->hx509ctx, ret,
257 "Create CMS signedData");
265 cert2epi(hx509_context context, void *ctx, hx509_cert c)
267 ExternalPrincipalIdentifiers *ids = ctx;
268 ExternalPrincipalIdentifier id;
269 hx509_name subject = NULL;
276 memset(&id, 0, sizeof(id));
278 ret = hx509_cert_get_subject(c, &subject);
282 if (hx509_name_is_null_p(subject) != 0) {
284 id.subjectName = calloc(1, sizeof(*id.subjectName));
285 if (id.subjectName == NULL) {
286 hx509_name_free(&subject);
287 free_ExternalPrincipalIdentifier(&id);
291 ret = hx509_name_binary(subject, id.subjectName);
293 hx509_name_free(&subject);
294 free_ExternalPrincipalIdentifier(&id);
298 hx509_name_free(&subject);
301 id.issuerAndSerialNumber = calloc(1, sizeof(*id.issuerAndSerialNumber));
302 if (id.issuerAndSerialNumber == NULL) {
303 free_ExternalPrincipalIdentifier(&id);
308 IssuerAndSerialNumber iasn;
312 memset(&iasn, 0, sizeof(iasn));
314 ret = hx509_cert_get_issuer(c, &issuer);
316 free_ExternalPrincipalIdentifier(&id);
320 ret = hx509_name_to_Name(issuer, &iasn.issuer);
321 hx509_name_free(&issuer);
323 free_ExternalPrincipalIdentifier(&id);
327 ret = hx509_cert_get_serialnumber(c, &iasn.serialNumber);
329 free_IssuerAndSerialNumber(&iasn);
330 free_ExternalPrincipalIdentifier(&id);
334 ASN1_MALLOC_ENCODE(IssuerAndSerialNumber,
335 id.issuerAndSerialNumber->data,
336 id.issuerAndSerialNumber->length,
338 free_IssuerAndSerialNumber(&iasn);
341 if (id.issuerAndSerialNumber->length != size)
345 id.subjectKeyIdentifier = NULL;
347 p = realloc(ids->val, sizeof(ids->val[0]) * (ids->len + 1));
349 free_ExternalPrincipalIdentifier(&id);
354 ids->val[ids->len] = id;
360 static krb5_error_code
361 build_edi(krb5_context context,
362 hx509_context hx509ctx,
364 ExternalPrincipalIdentifiers *ids)
366 return hx509_certs_iter_f(hx509ctx, certs, cert2epi, ids);
369 static krb5_error_code
370 build_auth_pack(krb5_context context,
372 krb5_pk_init_ctx ctx,
373 const KDC_REQ_BODY *body,
376 size_t buf_size, len = 0;
383 krb5_clear_error_message(context);
385 memset(&checksum, 0, sizeof(checksum));
387 krb5_us_timeofday(context, &sec, &usec);
388 a->pkAuthenticator.ctime = sec;
389 a->pkAuthenticator.nonce = nonce;
391 ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, body, &len, ret);
395 krb5_abortx(context, "internal error in ASN.1 encoder");
397 ret = krb5_create_checksum(context,
408 ALLOC(a->pkAuthenticator.paChecksum, 1);
409 if (a->pkAuthenticator.paChecksum == NULL) {
410 krb5_set_error_message(context, ENOMEM,
411 N_("malloc: out of memory", ""));
415 ret = krb5_data_copy(a->pkAuthenticator.paChecksum,
416 checksum.checksum.data, checksum.checksum.length);
417 free_Checksum(&checksum);
421 if (ctx->keyex == USE_DH || ctx->keyex == USE_ECDH) {
422 const char *moduli_file;
423 unsigned long dh_min_bits;
427 krb5_data_zero(&dhbuf);
431 moduli_file = krb5_config_get_string(context, NULL,
437 krb5_config_get_int_default(context, NULL, 0,
439 "pkinit_dh_min_bits",
442 ret = _krb5_parse_moduli(context, moduli_file, &ctx->m);
446 ctx->u.dh = DH_new();
447 if (ctx->u.dh == NULL) {
448 krb5_set_error_message(context, ENOMEM,
449 N_("malloc: out of memory", ""));
453 ret = select_dh_group(context, ctx->u.dh, dh_min_bits, ctx->m);
457 if (DH_generate_key(ctx->u.dh) != 1) {
458 krb5_set_error_message(context, ENOMEM,
459 N_("pkinit: failed to generate DH key", ""));
464 if (1 /* support_cached_dh */) {
465 ALLOC(a->clientDHNonce, 1);
466 if (a->clientDHNonce == NULL) {
467 krb5_clear_error_message(context);
470 ret = krb5_data_alloc(a->clientDHNonce, 40);
471 if (a->clientDHNonce == NULL) {
472 krb5_clear_error_message(context);
475 RAND_bytes(a->clientDHNonce->data, a->clientDHNonce->length);
476 ret = krb5_copy_data(context, a->clientDHNonce,
477 &ctx->clientDHNonce);
482 ALLOC(a->clientPublicValue, 1);
483 if (a->clientPublicValue == NULL)
486 if (ctx->keyex == USE_DH) {
488 const BIGNUM *p, *g, *q, *pub_key;
490 heim_integer dh_pub_key;
492 ret = der_copy_oid(&asn1_oid_id_dhpublicnumber,
493 &a->clientPublicValue->algorithm.algorithm);
497 memset(&dp, 0, sizeof(dp));
499 DH_get0_pqg(dh, &p, &q, &g);
500 ret = BN_to_integer(context, p, &dp.p);
502 free_DomainParameters(&dp);
505 ret = BN_to_integer(context, g, &dp.g);
507 free_DomainParameters(&dp);
510 ret = BN_to_integer(context, q, &dp.q);
512 free_DomainParameters(&dp);
516 dp.validationParms = NULL;
518 a->clientPublicValue->algorithm.parameters =
519 malloc(sizeof(*a->clientPublicValue->algorithm.parameters));
520 if (a->clientPublicValue->algorithm.parameters == NULL) {
521 free_DomainParameters(&dp);
525 ASN1_MALLOC_ENCODE(DomainParameters,
526 a->clientPublicValue->algorithm.parameters->data,
527 a->clientPublicValue->algorithm.parameters->length,
529 free_DomainParameters(&dp);
532 if (size != a->clientPublicValue->algorithm.parameters->length)
533 krb5_abortx(context, "Internal ASN1 encoder error");
535 DH_get0_key(dh, &pub_key, NULL);
536 ret = BN_to_integer(context, pub_key, &dh_pub_key);
540 ASN1_MALLOC_ENCODE(DHPublicKey, dhbuf.data, dhbuf.length,
541 &dh_pub_key, &size, ret);
542 der_free_heim_integer(&dh_pub_key);
545 if (size != dhbuf.length)
546 krb5_abortx(context, "asn1 internal error");
547 } else if (ctx->keyex == USE_ECDH) {
553 /* copy in public key, XXX find the best curve that the server support or use the clients curve if possible */
555 ecp.element = choice_ECParameters_namedCurve;
556 ret = der_copy_oid(&asn1_oid_id_ec_group_secp256r1,
561 ALLOC(a->clientPublicValue->algorithm.parameters, 1);
562 if (a->clientPublicValue->algorithm.parameters == NULL) {
563 free_ECParameters(&ecp);
566 ASN1_MALLOC_ENCODE(ECParameters, p, xlen, &ecp, &size, ret);
567 free_ECParameters(&ecp);
570 if ((int)size != xlen)
571 krb5_abortx(context, "asn1 internal error");
573 a->clientPublicValue->algorithm.parameters->data = p;
574 a->clientPublicValue->algorithm.parameters->length = size;
576 /* copy in public key */
578 ret = der_copy_oid(&asn1_oid_id_ecPublicKey,
579 &a->clientPublicValue->algorithm.algorithm);
583 ctx->u.eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
584 if (ctx->u.eckey == NULL)
587 ret = EC_KEY_generate_key(ctx->u.eckey);
591 /* encode onto dhkey */
593 xlen = i2o_ECPublicKey(ctx->u.eckey, NULL);
597 dhbuf.data = malloc(xlen);
598 if (dhbuf.data == NULL)
603 xlen = i2o_ECPublicKey(ctx->u.eckey, &p);
607 /* XXX verify that this is right with RFC3279 */
612 krb5_abortx(context, "internal error");
613 a->clientPublicValue->subjectPublicKey.length = dhbuf.length * 8;
614 a->clientPublicValue->subjectPublicKey.data = dhbuf.data;
618 a->supportedCMSTypes = calloc(1, sizeof(*a->supportedCMSTypes));
619 if (a->supportedCMSTypes == NULL)
622 ret = hx509_crypto_available(context->hx509ctx, HX509_SELECT_ALL,
624 &a->supportedCMSTypes->val,
625 &a->supportedCMSTypes->len);
633 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
634 _krb5_pk_mk_ContentInfo(krb5_context context,
635 const krb5_data *buf,
637 struct ContentInfo *content_info)
641 ret = der_copy_oid(oid, &content_info->contentType);
644 ALLOC(content_info->content, 1);
645 if (content_info->content == NULL)
647 content_info->content->data = malloc(buf->length);
648 if (content_info->content->data == NULL)
650 memcpy(content_info->content->data, buf->data, buf->length);
651 content_info->content->length = buf->length;
655 static krb5_error_code
656 pk_mk_padata(krb5_context context,
657 krb5_pk_init_ctx ctx,
658 const KDC_REQ_BODY *req_body,
662 struct ContentInfo content_info;
664 const heim_oid *oid = NULL;
666 krb5_data buf, sd_buf;
669 krb5_data_zero(&buf);
670 krb5_data_zero(&sd_buf);
671 memset(&content_info, 0, sizeof(content_info));
673 if (ctx->type == PKINIT_WIN2K) {
678 memset(&ap, 0, sizeof(ap));
680 /* fill in PKAuthenticator */
681 ret = copy_PrincipalName(req_body->sname, &ap.pkAuthenticator.kdcName);
683 free_AuthPack_Win2k(&ap);
684 krb5_clear_error_message(context);
687 ret = copy_Realm(&req_body->realm, &ap.pkAuthenticator.kdcRealm);
689 free_AuthPack_Win2k(&ap);
690 krb5_clear_error_message(context);
694 krb5_us_timeofday(context, &sec, &usec);
695 ap.pkAuthenticator.ctime = sec;
696 ap.pkAuthenticator.cusec = usec;
697 ap.pkAuthenticator.nonce = nonce;
699 ASN1_MALLOC_ENCODE(AuthPack_Win2k, buf.data, buf.length,
701 free_AuthPack_Win2k(&ap);
703 krb5_set_error_message(context, ret,
704 N_("Failed encoding AuthPackWin: %d", ""),
708 if (buf.length != size)
709 krb5_abortx(context, "internal ASN1 encoder error");
711 oid = &asn1_oid_id_pkcs7_data;
712 } else if (ctx->type == PKINIT_27) {
715 memset(&ap, 0, sizeof(ap));
717 ret = build_auth_pack(context, nonce, ctx, req_body, &ap);
723 ASN1_MALLOC_ENCODE(AuthPack, buf.data, buf.length, &ap, &size, ret);
726 krb5_set_error_message(context, ret,
727 N_("Failed encoding AuthPack: %d", ""),
731 if (buf.length != size)
732 krb5_abortx(context, "internal ASN1 encoder error");
734 oid = &asn1_oid_id_pkauthdata;
736 krb5_abortx(context, "internal pkinit error");
738 ret = create_signature(context, oid, &buf, ctx->id,
740 krb5_data_free(&buf);
744 ret = hx509_cms_wrap_ContentInfo(&asn1_oid_id_pkcs7_signedData, &sd_buf, &buf);
745 krb5_data_free(&sd_buf);
747 krb5_set_error_message(context, ret,
748 N_("ContentInfo wrapping of signedData failed",""));
752 if (ctx->type == PKINIT_WIN2K) {
753 PA_PK_AS_REQ_Win2k winreq;
755 pa_type = KRB5_PADATA_PK_AS_REQ_WIN;
757 memset(&winreq, 0, sizeof(winreq));
759 winreq.signed_auth_pack = buf;
761 ASN1_MALLOC_ENCODE(PA_PK_AS_REQ_Win2k, buf.data, buf.length,
762 &winreq, &size, ret);
763 free_PA_PK_AS_REQ_Win2k(&winreq);
765 } else if (ctx->type == PKINIT_27) {
768 pa_type = KRB5_PADATA_PK_AS_REQ;
770 memset(&req, 0, sizeof(req));
771 req.signedAuthPack = buf;
773 if (ctx->trustedCertifiers) {
775 req.trustedCertifiers = calloc(1, sizeof(*req.trustedCertifiers));
776 if (req.trustedCertifiers == NULL) {
778 krb5_set_error_message(context, ret,
779 N_("malloc: out of memory", ""));
780 free_PA_PK_AS_REQ(&req);
783 ret = build_edi(context, context->hx509ctx,
784 ctx->id->anchors, req.trustedCertifiers);
786 krb5_set_error_message(context, ret,
787 N_("pk-init: failed to build "
788 "trustedCertifiers", ""));
789 free_PA_PK_AS_REQ(&req);
795 ASN1_MALLOC_ENCODE(PA_PK_AS_REQ, buf.data, buf.length,
798 free_PA_PK_AS_REQ(&req);
801 krb5_abortx(context, "internal pkinit error");
803 krb5_set_error_message(context, ret, "PA-PK-AS-REQ %d", (int)ret);
806 if (buf.length != size)
807 krb5_abortx(context, "Internal ASN1 encoder error");
809 ret = krb5_padata_add(context, md, pa_type, buf.data, buf.length);
814 krb5_padata_add(context, md, KRB5_PADATA_PK_AS_09_BINDING, NULL, 0);
817 free_ContentInfo(&content_info);
823 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
824 _krb5_pk_mk_padata(krb5_context context,
828 const KDC_REQ_BODY *req_body,
832 krb5_pk_init_ctx ctx = c;
835 if (ctx->id->certs == NULL && ctx->anonymous == 0) {
836 krb5_set_error_message(context, HEIM_PKINIT_NO_PRIVATE_KEY,
837 N_("PKINIT: No user certificate given", ""));
838 return HEIM_PKINIT_NO_PRIVATE_KEY;
841 win2k_compat = krb5_config_get_bool_default(context, NULL,
849 ctx->require_binding =
850 krb5_config_get_bool_default(context, NULL,
854 "pkinit_win2k_require_binding",
856 ctx->type = PKINIT_WIN2K;
858 ctx->type = PKINIT_27;
861 krb5_config_get_bool_default(context, NULL,
865 "pkinit_require_eku",
867 if (ic_flags & KRB5_INIT_CREDS_NO_C_NO_EKU_CHECK)
868 ctx->require_eku = 0;
869 if (ctx->id->flags & PKINIT_BTMM)
870 ctx->require_eku = 0;
872 ctx->require_krbtgt_otherName =
873 krb5_config_get_bool_default(context, NULL,
877 "pkinit_require_krbtgt_otherName",
880 ctx->require_hostname_match =
881 krb5_config_get_bool_default(context, NULL,
885 "pkinit_require_hostname_match",
888 ctx->trustedCertifiers =
889 krb5_config_get_bool_default(context, NULL,
893 "pkinit_trustedCertifiers",
896 return pk_mk_padata(context, ctx, req_body, nonce, md);
899 static krb5_error_code
900 pk_verify_sign(krb5_context context,
903 struct krb5_pk_identity *id,
904 heim_oid *contentType,
906 struct krb5_pk_cert **signer)
908 hx509_certs signer_certs;
911 /* BTMM is broken in Leo and SnowLeo */
912 if (id->flags & PKINIT_BTMM) {
913 flags |= HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH;
914 flags |= HX509_CMS_VS_NO_KU_CHECK;
915 flags |= HX509_CMS_VS_NO_VALIDATE;
920 ret = hx509_cms_verify_signed(context->hx509ctx,
931 pk_copy_error(context, context->hx509ctx, ret,
932 "CMS verify signed failed");
936 *signer = calloc(1, sizeof(**signer));
937 if (*signer == NULL) {
938 krb5_clear_error_message(context);
943 ret = hx509_get_one_cert(context->hx509ctx, signer_certs, &(*signer)->cert);
945 pk_copy_error(context, context->hx509ctx, ret,
946 "Failed to get on of the signer certs");
951 hx509_certs_free(&signer_certs);
954 hx509_cert_free((*signer)->cert);
963 static krb5_error_code
964 get_reply_key_win(krb5_context context,
965 const krb5_data *content,
969 ReplyKeyPack_Win2k key_pack;
973 ret = decode_ReplyKeyPack_Win2k(content->data,
978 krb5_set_error_message(context, ret,
979 N_("PKINIT decoding reply key failed", ""));
980 free_ReplyKeyPack_Win2k(&key_pack);
984 if ((unsigned)key_pack.nonce != nonce) {
985 krb5_set_error_message(context, ret,
986 N_("PKINIT enckey nonce is wrong", ""));
987 free_ReplyKeyPack_Win2k(&key_pack);
988 return KRB5KRB_AP_ERR_MODIFIED;
991 *key = malloc (sizeof (**key));
993 free_ReplyKeyPack_Win2k(&key_pack);
994 krb5_set_error_message(context, ENOMEM,
995 N_("malloc: out of memory", ""));
999 ret = copy_EncryptionKey(&key_pack.replyKey, *key);
1000 free_ReplyKeyPack_Win2k(&key_pack);
1002 krb5_set_error_message(context, ret,
1003 N_("PKINIT failed copying reply key", ""));
1011 static krb5_error_code
1012 get_reply_key(krb5_context context,
1013 const krb5_data *content,
1014 const krb5_data *req_buffer,
1015 krb5_keyblock **key)
1017 ReplyKeyPack key_pack;
1018 krb5_error_code ret;
1021 ret = decode_ReplyKeyPack(content->data,
1026 krb5_set_error_message(context, ret,
1027 N_("PKINIT decoding reply key failed", ""));
1028 free_ReplyKeyPack(&key_pack);
1036 * XXX Verify kp.replyKey is a allowed enctype in the
1037 * configuration file
1040 ret = krb5_crypto_init(context, &key_pack.replyKey, 0, &crypto);
1042 free_ReplyKeyPack(&key_pack);
1046 ret = krb5_verify_checksum(context, crypto, 6,
1047 req_buffer->data, req_buffer->length,
1048 &key_pack.asChecksum);
1049 krb5_crypto_destroy(context, crypto);
1051 free_ReplyKeyPack(&key_pack);
1056 *key = malloc (sizeof (**key));
1058 free_ReplyKeyPack(&key_pack);
1059 krb5_set_error_message(context, ENOMEM,
1060 N_("malloc: out of memory", ""));
1064 ret = copy_EncryptionKey(&key_pack.replyKey, *key);
1065 free_ReplyKeyPack(&key_pack);
1067 krb5_set_error_message(context, ret,
1068 N_("PKINIT failed copying reply key", ""));
1077 static krb5_error_code
1078 pk_verify_host(krb5_context context,
1080 const krb5_krbhst_info *hi,
1081 struct krb5_pk_init_ctx_data *ctx,
1082 struct krb5_pk_cert *host)
1084 krb5_error_code ret = 0;
1086 if (ctx->require_eku) {
1087 ret = hx509_cert_check_eku(context->hx509ctx, host->cert,
1088 &asn1_oid_id_pkkdcekuoid, 0);
1090 krb5_set_error_message(context, ret,
1091 N_("No PK-INIT KDC EKU in kdc certificate", ""));
1095 if (ctx->require_krbtgt_otherName) {
1096 hx509_octet_string_list list;
1099 ret = hx509_cert_find_subjectAltName_otherName(context->hx509ctx,
1101 &asn1_oid_id_pkinit_san,
1104 krb5_set_error_message(context, ret,
1105 N_("Failed to find the PK-INIT "
1106 "subjectAltName in the KDC "
1107 "certificate", ""));
1112 for (i = 0; i < list.len; i++) {
1113 KRB5PrincipalName r;
1115 ret = decode_KRB5PrincipalName(list.val[i].data,
1120 krb5_set_error_message(context, ret,
1121 N_("Failed to decode the PK-INIT "
1122 "subjectAltName in the "
1123 "KDC certificate", ""));
1128 if (r.principalName.name_string.len != 2 ||
1129 strcmp(r.principalName.name_string.val[0], KRB5_TGS_NAME) != 0 ||
1130 strcmp(r.principalName.name_string.val[1], realm) != 0 ||
1131 strcmp(r.realm, realm) != 0)
1133 ret = KRB5_KDC_ERR_INVALID_CERTIFICATE;
1134 krb5_set_error_message(context, ret,
1135 N_("KDC have wrong realm name in "
1136 "the certificate", ""));
1139 free_KRB5PrincipalName(&r);
1143 hx509_free_octet_string_list(&list);
1149 ret = hx509_verify_hostname(context->hx509ctx, host->cert,
1150 ctx->require_hostname_match,
1153 hi->ai->ai_addr, hi->ai->ai_addrlen);
1156 krb5_set_error_message(context, ret,
1157 N_("Address mismatch in "
1158 "the KDC certificate", ""));
1163 static krb5_error_code
1164 pk_rd_pa_reply_enckey(krb5_context context,
1166 const heim_octet_string *indata,
1167 const heim_oid *dataType,
1169 krb5_pk_init_ctx ctx,
1171 const krb5_krbhst_info *hi,
1173 const krb5_data *req_buffer,
1175 krb5_keyblock **key)
1177 krb5_error_code ret;
1178 struct krb5_pk_cert *host = NULL;
1180 heim_oid contentType = { 0, NULL };
1181 int flags = HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT;
1183 if (der_heim_oid_cmp(&asn1_oid_id_pkcs7_envelopedData, dataType)) {
1184 krb5_set_error_message(context, EINVAL,
1185 N_("PKINIT: Invalid content type", ""));
1189 if (ctx->type == PKINIT_WIN2K)
1190 flags |= HX509_CMS_UE_ALLOW_WEAK;
1192 ret = hx509_cms_unenvelope(context->hx509ctx,
1202 pk_copy_error(context, context->hx509ctx, ret,
1203 "Failed to unenvelope CMS data in PK-INIT reply");
1206 der_free_oid(&contentType);
1208 /* win2k uses ContentInfo */
1209 if (type == PKINIT_WIN2K) {
1211 heim_octet_string out;
1213 ret = hx509_cms_unwrap_ContentInfo(&content, &type2, &out, NULL);
1215 /* windows LH with interesting CMS packets */
1216 size_t ph = 1 + der_length_len(content.length);
1217 unsigned char *ptr = malloc(content.length + ph);
1220 memcpy(ptr + ph, content.data, content.length);
1222 ret = der_put_length_and_tag (ptr + ph - 1, ph, content.length,
1223 ASN1_C_UNIV, CONS, UT_Sequence, &l);
1228 content.length += ph;
1230 ret = hx509_cms_unwrap_ContentInfo(&content, &type2, &out, NULL);
1234 if (der_heim_oid_cmp(&type2, &asn1_oid_id_pkcs7_signedData)) {
1235 ret = EINVAL; /* XXX */
1236 krb5_set_error_message(context, ret,
1237 N_("PKINIT: Invalid content type", ""));
1238 der_free_oid(&type2);
1239 der_free_octet_string(&out);
1242 der_free_oid(&type2);
1243 krb5_data_free(&content);
1244 ret = krb5_data_copy(&content, out.data, out.length);
1245 der_free_octet_string(&out);
1247 krb5_set_error_message(context, ret,
1248 N_("malloc: out of memory", ""));
1253 ret = pk_verify_sign(context,
1263 /* make sure that it is the kdc's certificate */
1264 ret = pk_verify_host(context, realm, hi, ctx, host);
1270 if (type == PKINIT_WIN2K) {
1271 if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkcs7_data) != 0) {
1272 ret = KRB5KRB_AP_ERR_MSG_TYPE;
1273 krb5_set_error_message(context, ret, "PKINIT: reply key, wrong oid");
1277 if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkrkeydata) != 0) {
1278 ret = KRB5KRB_AP_ERR_MSG_TYPE;
1279 krb5_set_error_message(context, ret, "PKINIT: reply key, wrong oid");
1287 ret = get_reply_key(context, &content, req_buffer, key);
1288 if (ret != 0 && ctx->require_binding == 0)
1289 ret = get_reply_key_win(context, &content, nonce, key);
1292 ret = get_reply_key(context, &content, req_buffer, key);
1298 /* XXX compare given etype with key->etype */
1302 _krb5_pk_cert_free(host);
1303 der_free_oid(&contentType);
1304 krb5_data_free(&content);
1309 static krb5_error_code
1310 pk_rd_pa_reply_dh(krb5_context context,
1311 const heim_octet_string *indata,
1312 const heim_oid *dataType,
1314 krb5_pk_init_ctx ctx,
1316 const krb5_krbhst_info *hi,
1321 krb5_keyblock **key)
1323 const unsigned char *p;
1324 unsigned char *dh_gen_key = NULL;
1325 struct krb5_pk_cert *host = NULL;
1326 BIGNUM *kdc_dh_pubkey = NULL;
1327 KDCDHKeyInfo kdc_dh_info;
1328 heim_oid contentType = { 0, NULL };
1330 krb5_error_code ret;
1331 int dh_gen_keylen = 0;
1334 krb5_data_zero(&content);
1335 memset(&kdc_dh_info, 0, sizeof(kdc_dh_info));
1337 if (der_heim_oid_cmp(&asn1_oid_id_pkcs7_signedData, dataType)) {
1338 krb5_set_error_message(context, EINVAL,
1339 N_("PKINIT: Invalid content type", ""));
1343 ret = pk_verify_sign(context,
1353 /* make sure that it is the kdc's certificate */
1354 ret = pk_verify_host(context, realm, hi, ctx, host);
1358 if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkdhkeydata)) {
1359 ret = KRB5KRB_AP_ERR_MSG_TYPE;
1360 krb5_set_error_message(context, ret,
1361 N_("pkinit - dh reply contains wrong oid", ""));
1365 ret = decode_KDCDHKeyInfo(content.data,
1371 krb5_set_error_message(context, ret,
1372 N_("pkinit - failed to decode "
1373 "KDC DH Key Info", ""));
1377 if (kdc_dh_info.nonce != nonce) {
1378 ret = KRB5KRB_AP_ERR_MODIFIED;
1379 krb5_set_error_message(context, ret,
1380 N_("PKINIT: DH nonce is wrong", ""));
1384 if (kdc_dh_info.dhKeyExpiration) {
1386 ret = KRB5KRB_ERR_GENERIC;
1387 krb5_set_error_message(context, ret,
1388 N_("pkinit; got key expiration "
1389 "without server nonce", ""));
1393 ret = KRB5KRB_ERR_GENERIC;
1394 krb5_set_error_message(context, ret,
1395 N_("pkinit; got DH reuse but no "
1396 "client nonce", ""));
1401 ret = KRB5KRB_ERR_GENERIC;
1402 krb5_set_error_message(context, ret,
1403 N_("pkinit: got server nonce "
1404 "without key expiration", ""));
1411 p = kdc_dh_info.subjectPublicKey.data;
1412 size = (kdc_dh_info.subjectPublicKey.length + 7) / 8;
1414 if (ctx->keyex == USE_DH) {
1416 ret = decode_DHPublicKey(p, size, &k, NULL);
1418 krb5_set_error_message(context, ret,
1419 N_("pkinit: can't decode "
1420 "without key expiration", ""));
1424 kdc_dh_pubkey = integer_to_BN(context, "DHPublicKey", &k);
1425 free_DHPublicKey(&k);
1426 if (kdc_dh_pubkey == NULL) {
1432 size = DH_size(ctx->u.dh);
1434 dh_gen_key = malloc(size);
1435 if (dh_gen_key == NULL) {
1437 krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
1441 dh_gen_keylen = DH_compute_key(dh_gen_key, kdc_dh_pubkey, ctx->u.dh);
1442 if (dh_gen_keylen == -1) {
1443 ret = KRB5KRB_ERR_GENERIC;
1445 krb5_set_error_message(context, ret,
1446 N_("PKINIT: Can't compute Diffie-Hellman key", ""));
1449 if (dh_gen_keylen < (int)size) {
1450 size -= dh_gen_keylen;
1451 memmove(dh_gen_key + size, dh_gen_key, dh_gen_keylen);
1452 memset(dh_gen_key, 0, size);
1457 const EC_GROUP *group;
1458 EC_KEY *public = NULL;
1460 group = EC_KEY_get0_group(ctx->u.eckey);
1462 public = EC_KEY_new();
1463 if (public == NULL) {
1467 if (EC_KEY_set_group(public, group) != 1) {
1468 EC_KEY_free(public);
1473 if (o2i_ECPublicKey(&public, &p, size) == NULL) {
1474 EC_KEY_free(public);
1475 ret = KRB5KRB_ERR_GENERIC;
1476 krb5_set_error_message(context, ret,
1477 N_("PKINIT: Can't parse ECDH public key", ""));
1481 size = (EC_GROUP_get_degree(group) + 7) / 8;
1482 dh_gen_key = malloc(size);
1483 if (dh_gen_key == NULL) {
1484 EC_KEY_free(public);
1486 krb5_set_error_message(context, ret,
1487 N_("malloc: out of memory", ""));
1490 dh_gen_keylen = ECDH_compute_key(dh_gen_key, size,
1491 EC_KEY_get0_public_key(public), ctx->u.eckey, NULL);
1492 EC_KEY_free(public);
1493 if (dh_gen_keylen == -1) {
1494 ret = KRB5KRB_ERR_GENERIC;
1496 krb5_set_error_message(context, ret,
1497 N_("PKINIT: Can't compute ECDH public key", ""));
1505 if (dh_gen_keylen <= 0) {
1507 krb5_set_error_message(context, ret,
1508 N_("PKINIT: resulting DH key <= 0", ""));
1513 *key = malloc (sizeof (**key));
1516 krb5_set_error_message(context, ret,
1517 N_("malloc: out of memory", ""));
1521 ret = _krb5_pk_octetstring2key(context,
1523 dh_gen_key, dh_gen_keylen,
1527 krb5_set_error_message(context, ret,
1528 N_("PKINIT: can't create key from DH key", ""));
1536 BN_free(kdc_dh_pubkey);
1538 memset(dh_gen_key, 0, dh_gen_keylen);
1542 _krb5_pk_cert_free(host);
1544 krb5_data_free(&content);
1545 der_free_oid(&contentType);
1546 free_KDCDHKeyInfo(&kdc_dh_info);
1551 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1552 _krb5_pk_rd_pa_reply(krb5_context context,
1556 const krb5_krbhst_info *hi,
1558 const krb5_data *req_buffer,
1560 krb5_keyblock **key)
1562 krb5_pk_init_ctx ctx = c;
1563 krb5_error_code ret;
1566 /* Check for IETF PK-INIT first */
1567 if (ctx->type == PKINIT_27) {
1569 heim_octet_string os, data;
1572 if (pa->padata_type != KRB5_PADATA_PK_AS_REP) {
1573 krb5_set_error_message(context, EINVAL,
1574 N_("PKINIT: wrong padata recv", ""));
1578 ret = decode_PA_PK_AS_REP(pa->padata_value.data,
1579 pa->padata_value.length,
1583 krb5_set_error_message(context, ret,
1584 N_("Failed to decode pkinit AS rep", ""));
1588 switch (rep.element) {
1589 case choice_PA_PK_AS_REP_dhInfo:
1590 _krb5_debug(context, 5, "krb5_get_init_creds: using pkinit dh");
1591 os = rep.u.dhInfo.dhSignedData;
1593 case choice_PA_PK_AS_REP_encKeyPack:
1594 _krb5_debug(context, 5, "krb5_get_init_creds: using kinit enc reply key");
1595 os = rep.u.encKeyPack;
1598 PA_PK_AS_REP_BTMM btmm;
1599 free_PA_PK_AS_REP(&rep);
1600 memset(&rep, 0, sizeof(rep));
1602 _krb5_debug(context, 5, "krb5_get_init_creds: using BTMM kinit enc reply key");
1604 ret = decode_PA_PK_AS_REP_BTMM(pa->padata_value.data,
1605 pa->padata_value.length,
1609 krb5_set_error_message(context, EINVAL,
1610 N_("PKINIT: -27 reply "
1611 "invalid content type", ""));
1615 if (btmm.dhSignedData || btmm.encKeyPack == NULL) {
1616 free_PA_PK_AS_REP_BTMM(&btmm);
1618 krb5_set_error_message(context, ret,
1619 N_("DH mode not supported for BTMM mode", ""));
1624 * Transform to IETF style PK-INIT reply so that free works below
1627 rep.element = choice_PA_PK_AS_REP_encKeyPack;
1628 rep.u.encKeyPack.data = btmm.encKeyPack->data;
1629 rep.u.encKeyPack.length = btmm.encKeyPack->length;
1630 btmm.encKeyPack->data = NULL;
1631 btmm.encKeyPack->length = 0;
1632 free_PA_PK_AS_REP_BTMM(&btmm);
1633 os = rep.u.encKeyPack;
1637 ret = hx509_cms_unwrap_ContentInfo(&os, &oid, &data, NULL);
1639 free_PA_PK_AS_REP(&rep);
1640 krb5_set_error_message(context, ret,
1641 N_("PKINIT: failed to unwrap CI", ""));
1645 switch (rep.element) {
1646 case choice_PA_PK_AS_REP_dhInfo:
1647 ret = pk_rd_pa_reply_dh(context, &data, &oid, realm, ctx, etype, hi,
1649 rep.u.dhInfo.serverDHNonce,
1652 case choice_PA_PK_AS_REP_encKeyPack:
1653 ret = pk_rd_pa_reply_enckey(context, PKINIT_27, &data, &oid, realm,
1654 ctx, etype, hi, nonce, req_buffer, pa, key);
1657 krb5_abortx(context, "pk-init as-rep case not possible to happen");
1659 der_free_octet_string(&data);
1661 free_PA_PK_AS_REP(&rep);
1663 } else if (ctx->type == PKINIT_WIN2K) {
1664 PA_PK_AS_REP_Win2k w2krep;
1666 /* Check for Windows encoding of the AS-REP pa data */
1668 #if 0 /* should this be ? */
1669 if (pa->padata_type != KRB5_PADATA_PK_AS_REP) {
1670 krb5_set_error_message(context, EINVAL,
1671 "PKINIT: wrong padata recv");
1676 memset(&w2krep, 0, sizeof(w2krep));
1678 ret = decode_PA_PK_AS_REP_Win2k(pa->padata_value.data,
1679 pa->padata_value.length,
1683 krb5_set_error_message(context, ret,
1684 N_("PKINIT: Failed decoding windows "
1685 "pkinit reply %d", ""), (int)ret);
1689 krb5_clear_error_message(context);
1691 switch (w2krep.element) {
1692 case choice_PA_PK_AS_REP_Win2k_encKeyPack: {
1693 heim_octet_string data;
1696 ret = hx509_cms_unwrap_ContentInfo(&w2krep.u.encKeyPack,
1698 free_PA_PK_AS_REP_Win2k(&w2krep);
1700 krb5_set_error_message(context, ret,
1701 N_("PKINIT: failed to unwrap CI", ""));
1705 ret = pk_rd_pa_reply_enckey(context, PKINIT_WIN2K, &data, &oid, realm,
1706 ctx, etype, hi, nonce, req_buffer, pa, key);
1707 der_free_octet_string(&data);
1713 free_PA_PK_AS_REP_Win2k(&w2krep);
1715 krb5_set_error_message(context, ret,
1716 N_("PKINIT: win2k reply invalid "
1717 "content type", ""));
1723 krb5_set_error_message(context, ret,
1724 N_("PKINIT: unknown reply type", ""));
1731 krb5_context context;
1732 krb5_prompter_fct prompter;
1733 void *prompter_data;
1737 hx_pass_prompter(void *data, const hx509_prompt *prompter)
1739 krb5_error_code ret;
1741 krb5_data password_data;
1742 struct prompter *p = data;
1744 password_data.data = prompter->reply.data;
1745 password_data.length = prompter->reply.length;
1747 prompt.prompt = prompter->prompt;
1748 prompt.hidden = hx509_prompt_hidden(prompter->type);
1749 prompt.reply = &password_data;
1751 switch (prompter->type) {
1752 case HX509_PROMPT_TYPE_INFO:
1753 prompt.type = KRB5_PROMPT_TYPE_INFO;
1755 case HX509_PROMPT_TYPE_PASSWORD:
1756 case HX509_PROMPT_TYPE_QUESTION:
1758 prompt.type = KRB5_PROMPT_TYPE_PASSWORD;
1762 ret = (*p->prompter)(p->context, p->prompter_data, NULL, NULL, 1, &prompt);
1764 memset (prompter->reply.data, 0, prompter->reply.length);
1770 static krb5_error_code
1771 _krb5_pk_set_user_id(krb5_context context,
1772 krb5_principal principal,
1773 krb5_pk_init_ctx ctx,
1774 struct hx509_certs_data *certs)
1776 hx509_certs c = hx509_certs_ref(certs);
1777 hx509_query *q = NULL;
1781 hx509_certs_free(&ctx->id->certs);
1782 if (ctx->id->cert) {
1783 hx509_cert_free(ctx->id->cert);
1784 ctx->id->cert = NULL;
1790 ret = hx509_query_alloc(context->hx509ctx, &q);
1792 pk_copy_error(context, context->hx509ctx, ret,
1793 "Allocate query to find signing certificate");
1797 hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
1798 hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE);
1800 if (principal && strncmp("LKDC:SHA1.", krb5_principal_get_realm(context, principal), 9) == 0) {
1801 ctx->id->flags |= PKINIT_BTMM;
1804 ret = find_cert(context, ctx->id, q, &ctx->id->cert);
1805 hx509_query_free(context->hx509ctx, q);
1807 if (ret == 0 && _krb5_have_debug(context, 2)) {
1812 ret = hx509_cert_get_subject(ctx->id->cert, &name);
1816 ret = hx509_name_to_string(name, &str);
1817 hx509_name_free(&name);
1821 ret = hx509_cert_get_serialnumber(ctx->id->cert, &i);
1827 ret = der_print_hex_heim_integer(&i, &sn);
1828 der_free_heim_integer(&i);
1834 _krb5_debug(context, 2, "using cert: subject: %s sn: %s", str, sn);
1843 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1844 _krb5_pk_load_id(krb5_context context,
1845 struct krb5_pk_identity **ret_id,
1846 const char *user_id,
1847 const char *anchor_id,
1848 char * const *chain_list,
1849 char * const *revoke_list,
1850 krb5_prompter_fct prompter,
1851 void *prompter_data,
1854 struct krb5_pk_identity *id = NULL;
1860 if (anchor_id == NULL) {
1861 krb5_set_error_message(context, HEIM_PKINIT_NO_VALID_CA,
1862 N_("PKINIT: No anchor given", ""));
1863 return HEIM_PKINIT_NO_VALID_CA;
1868 id = calloc(1, sizeof(*id));
1870 krb5_set_error_message(context, ENOMEM,
1871 N_("malloc: out of memory", ""));
1878 ret = hx509_lock_init(context->hx509ctx, &lock);
1880 pk_copy_error(context, context->hx509ctx, ret, "Failed init lock");
1884 if (password && password[0])
1885 hx509_lock_add_password(lock, password);
1888 p.context = context;
1889 p.prompter = prompter;
1890 p.prompter_data = prompter_data;
1892 ret = hx509_lock_set_prompter(lock, hx_pass_prompter, &p);
1894 hx509_lock_free(lock);
1899 ret = hx509_certs_init(context->hx509ctx, user_id, 0, lock, &id->certs);
1900 hx509_lock_free(lock);
1902 pk_copy_error(context, context->hx509ctx, ret,
1903 "Failed to init cert certs");
1910 ret = hx509_certs_init(context->hx509ctx, anchor_id, 0, NULL, &id->anchors);
1912 pk_copy_error(context, context->hx509ctx, ret,
1913 "Failed to init anchors");
1917 ret = hx509_certs_init(context->hx509ctx, "MEMORY:pkinit-cert-chain",
1918 0, NULL, &id->certpool);
1920 pk_copy_error(context, context->hx509ctx, ret,
1921 "Failed to init chain");
1925 while (chain_list && *chain_list) {
1926 ret = hx509_certs_append(context->hx509ctx, id->certpool,
1929 pk_copy_error(context, context->hx509ctx, ret,
1930 "Failed to laod chain %s",
1938 ret = hx509_revoke_init(context->hx509ctx, &id->revokectx);
1940 pk_copy_error(context, context->hx509ctx, ret,
1941 "Failed init revoke list");
1945 while (*revoke_list) {
1946 ret = hx509_revoke_add_crl(context->hx509ctx,
1950 pk_copy_error(context, context->hx509ctx, ret,
1951 "Failed load revoke list");
1957 hx509_context_set_missing_revoke(context->hx509ctx, 1);
1959 ret = hx509_verify_init_ctx(context->hx509ctx, &id->verify_ctx);
1961 pk_copy_error(context, context->hx509ctx, ret,
1962 "Failed init verify context");
1966 hx509_verify_attach_anchors(id->verify_ctx, id->anchors);
1967 hx509_verify_attach_revoke(id->verify_ctx, id->revokectx);
1971 hx509_verify_destroy_ctx(id->verify_ctx);
1972 hx509_certs_free(&id->certs);
1973 hx509_certs_free(&id->anchors);
1974 hx509_certs_free(&id->certpool);
1975 hx509_revoke_free(&id->revokectx);
1988 pk_copy_error(krb5_context context,
1989 hx509_context hx509ctx,
1999 ret = vasprintf(&f, fmt, va);
2001 if (ret == -1 || f == NULL) {
2002 krb5_clear_error_message(context);
2006 s = hx509_get_error_string(hx509ctx, hxret);
2008 krb5_clear_error_message(context);
2012 krb5_set_error_message(context, hxret, "%s: %s", f, s);
2018 parse_integer(krb5_context context, char **p, const char *file, int lineno,
2019 const char *name, heim_integer *integer)
2023 p1 = strsep(p, " \t");
2025 krb5_set_error_message(context, EINVAL,
2026 N_("moduli file %s missing %s on line %d", ""),
2027 file, name, lineno);
2030 ret = der_parse_hex_heim_integer(p1, integer);
2032 krb5_set_error_message(context, ret,
2033 N_("moduli file %s failed parsing %s "
2035 file, name, lineno);
2043 _krb5_parse_moduli_line(krb5_context context,
2047 struct krb5_dh_moduli **m)
2049 struct krb5_dh_moduli *m1;
2055 m1 = calloc(1, sizeof(*m1));
2057 krb5_set_error_message(context, ENOMEM,
2058 N_("malloc: out of memory", ""));
2062 while (isspace((unsigned char)*p))
2070 p1 = strsep(&p, " \t");
2072 krb5_set_error_message(context, ret,
2073 N_("moduli file %s missing name on line %d", ""),
2077 m1->name = strdup(p1);
2078 if (m1->name == NULL) {
2080 krb5_set_error_message(context, ret, N_("malloc: out of memeory", ""));
2084 p1 = strsep(&p, " \t");
2086 krb5_set_error_message(context, ret,
2087 N_("moduli file %s missing bits on line %d", ""),
2092 m1->bits = atoi(p1);
2093 if (m1->bits == 0) {
2094 krb5_set_error_message(context, ret,
2095 N_("moduli file %s have un-parsable "
2096 "bits on line %d", ""), file, lineno);
2100 ret = parse_integer(context, &p, file, lineno, "p", &m1->p);
2103 ret = parse_integer(context, &p, file, lineno, "g", &m1->g);
2106 ret = parse_integer(context, &p, file, lineno, "q", &m1->q);
2115 der_free_heim_integer(&m1->p);
2116 der_free_heim_integer(&m1->g);
2117 der_free_heim_integer(&m1->q);
2123 _krb5_free_moduli(struct krb5_dh_moduli **moduli)
2126 for (i = 0; moduli[i] != NULL; i++) {
2127 free(moduli[i]->name);
2128 der_free_heim_integer(&moduli[i]->p);
2129 der_free_heim_integer(&moduli[i]->g);
2130 der_free_heim_integer(&moduli[i]->q);
2136 static const char *default_moduli_RFC2412_MODP_group2 =
2138 "RFC2412-MODP-group2 "
2142 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
2143 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
2144 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
2145 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
2146 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
2147 "FFFFFFFF" "FFFFFFFF "
2151 "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68"
2152 "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E"
2153 "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122"
2154 "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6"
2155 "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F67329C0"
2156 "FFFFFFFF" "FFFFFFFF";
2158 static const char *default_moduli_rfc3526_MODP_group14 =
2160 "rfc3526-MODP-group14 "
2164 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
2165 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
2166 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
2167 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
2168 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D"
2169 "C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"
2170 "83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"
2171 "670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"
2172 "E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"
2173 "DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
2174 "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF "
2178 "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68"
2179 "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E"
2180 "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122"
2181 "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6"
2182 "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F6722D9E"
2183 "E1003E5C" "50B1DF82" "CC6D241B" "0E2AE9CD" "348B1FD4" "7E9267AF"
2184 "C1B2AE91" "EE51D6CB" "0E3179AB" "1042A95D" "CF6A9483" "B84B4B36"
2185 "B3861AA7" "255E4C02" "78BA3604" "650C10BE" "19482F23" "171B671D"
2186 "F1CF3B96" "0C074301" "CD93C1D1" "7603D147" "DAE2AEF8" "37A62964"
2187 "EF15E5FB" "4AAC0B8C" "1CCAA4BE" "754AB572" "8AE9130C" "4C7D0288"
2188 "0AB9472D" "45565534" "7FFFFFFF" "FFFFFFFF";
2191 _krb5_parse_moduli(krb5_context context, const char *file,
2192 struct krb5_dh_moduli ***moduli)
2194 /* name bits P G Q */
2195 krb5_error_code ret;
2196 struct krb5_dh_moduli **m = NULL, **m2;
2199 int lineno = 0, n = 0;
2203 m = calloc(1, sizeof(m[0]) * 3);
2205 krb5_set_error_message(context, ENOMEM,
2206 N_("malloc: out of memory", ""));
2210 strlcpy(buf, default_moduli_rfc3526_MODP_group14, sizeof(buf));
2211 ret = _krb5_parse_moduli_line(context, "builtin", 1, buf, &m[0]);
2213 _krb5_free_moduli(m);
2218 strlcpy(buf, default_moduli_RFC2412_MODP_group2, sizeof(buf));
2219 ret = _krb5_parse_moduli_line(context, "builtin", 1, buf, &m[1]);
2221 _krb5_free_moduli(m);
2230 #ifdef KRB5_USE_PATH_TOKENS
2234 if (_krb5_expand_path_tokens(context, file, &exp_file) == 0) {
2235 f = fopen(exp_file, "r");
2236 krb5_xfree(exp_file);
2242 f = fopen(file, "r");
2251 while(fgets(buf, sizeof(buf), f) != NULL) {
2252 struct krb5_dh_moduli *element;
2254 buf[strcspn(buf, "\n")] = '\0';
2257 m2 = realloc(m, (n + 2) * sizeof(m[0]));
2259 _krb5_free_moduli(m);
2260 krb5_set_error_message(context, ENOMEM,
2261 N_("malloc: out of memory", ""));
2268 ret = _krb5_parse_moduli_line(context, file, lineno, buf, &element);
2270 _krb5_free_moduli(m);
2273 if (element == NULL)
2285 _krb5_dh_group_ok(krb5_context context, unsigned long bits,
2286 heim_integer *p, heim_integer *g, heim_integer *q,
2287 struct krb5_dh_moduli **moduli,
2295 for (i = 0; moduli[i] != NULL; i++) {
2296 if (der_heim_integer_cmp(&moduli[i]->g, g) == 0 &&
2297 der_heim_integer_cmp(&moduli[i]->p, p) == 0 &&
2298 (q == NULL || der_heim_integer_cmp(&moduli[i]->q, q) == 0))
2300 if (bits && bits > moduli[i]->bits) {
2301 krb5_set_error_message(context,
2302 KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED,
2303 N_("PKINIT: DH group parameter %s "
2304 "no accepted, not enough bits "
2307 return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
2310 *name = strdup(moduli[i]->name);
2314 krb5_set_error_message(context,
2315 KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED,
2316 N_("PKINIT: DH group parameter no ok", ""));
2317 return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
2321 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
2322 _krb5_get_init_creds_opt_free_pkinit(krb5_get_init_creds_opt *opt)
2325 krb5_pk_init_ctx ctx;
2327 if (opt->opt_private == NULL || opt->opt_private->pk_init_ctx == NULL)
2329 ctx = opt->opt_private->pk_init_ctx;
2330 switch (ctx->keyex) {
2340 EC_KEY_free(ctx->u.eckey);
2345 hx509_verify_destroy_ctx(ctx->id->verify_ctx);
2346 hx509_certs_free(&ctx->id->certs);
2347 hx509_cert_free(ctx->id->cert);
2348 hx509_certs_free(&ctx->id->anchors);
2349 hx509_certs_free(&ctx->id->certpool);
2351 if (ctx->clientDHNonce) {
2352 krb5_free_data(NULL, ctx->clientDHNonce);
2353 ctx->clientDHNonce = NULL;
2356 _krb5_free_moduli(ctx->m);
2360 free(opt->opt_private->pk_init_ctx);
2361 opt->opt_private->pk_init_ctx = NULL;
2365 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2366 krb5_get_init_creds_opt_set_pkinit(krb5_context context,
2367 krb5_get_init_creds_opt *opt,
2368 krb5_principal principal,
2369 const char *user_id,
2370 const char *x509_anchors,
2371 char * const * pool,
2372 char * const * pki_revoke,
2374 krb5_prompter_fct prompter,
2375 void *prompter_data,
2379 krb5_error_code ret;
2380 char *anchors = NULL;
2382 if (opt->opt_private == NULL) {
2383 krb5_set_error_message(context, EINVAL,
2384 N_("PKINIT: on non extendable opt", ""));
2388 opt->opt_private->pk_init_ctx =
2389 calloc(1, sizeof(*opt->opt_private->pk_init_ctx));
2390 if (opt->opt_private->pk_init_ctx == NULL) {
2391 krb5_set_error_message(context, ENOMEM,
2392 N_("malloc: out of memory", ""));
2395 opt->opt_private->pk_init_ctx->require_binding = 0;
2396 opt->opt_private->pk_init_ctx->require_eku = 1;
2397 opt->opt_private->pk_init_ctx->require_krbtgt_otherName = 1;
2398 opt->opt_private->pk_init_ctx->peer = NULL;
2400 /* XXX implement krb5_appdefault_strings */
2402 pool = krb5_config_get_strings(context, NULL,
2407 if (pki_revoke == NULL)
2408 pki_revoke = krb5_config_get_strings(context, NULL,
2413 if (x509_anchors == NULL) {
2414 krb5_appdefault_string(context, "kinit",
2415 krb5_principal_get_realm(context, principal),
2416 "pkinit_anchors", NULL, &anchors);
2417 x509_anchors = anchors;
2421 opt->opt_private->pk_init_ctx->anonymous = 1;
2423 ret = _krb5_pk_load_id(context,
2424 &opt->opt_private->pk_init_ctx->id,
2433 free(opt->opt_private->pk_init_ctx);
2434 opt->opt_private->pk_init_ctx = NULL;
2438 if (opt->opt_private->pk_init_ctx->id->certs) {
2439 _krb5_pk_set_user_id(context,
2441 opt->opt_private->pk_init_ctx,
2442 opt->opt_private->pk_init_ctx->id->certs);
2444 opt->opt_private->pk_init_ctx->id->cert = NULL;
2446 if ((flags & 2) == 0) {
2447 hx509_context hx509ctx = context->hx509ctx;
2448 hx509_cert cert = opt->opt_private->pk_init_ctx->id->cert;
2450 opt->opt_private->pk_init_ctx->keyex = USE_DH;
2453 * If its a ECDSA certs, lets select ECDSA as the keyex algorithm.
2456 AlgorithmIdentifier alg;
2458 ret = hx509_cert_get_SPKI_AlgorithmIdentifier(hx509ctx, cert, &alg);
2460 if (der_heim_oid_cmp(&alg.algorithm, &asn1_oid_id_ecPublicKey) == 0)
2461 opt->opt_private->pk_init_ctx->keyex = USE_ECDH;
2462 free_AlgorithmIdentifier(&alg);
2467 opt->opt_private->pk_init_ctx->keyex = USE_RSA;
2469 if (opt->opt_private->pk_init_ctx->id->certs == NULL) {
2470 krb5_set_error_message(context, EINVAL,
2471 N_("No anonymous pkinit support in RSA mode", ""));
2478 krb5_set_error_message(context, EINVAL,
2479 N_("no support for PKINIT compiled in", ""));
2484 krb5_error_code KRB5_LIB_FUNCTION
2485 krb5_get_init_creds_opt_set_pkinit_user_certs(krb5_context context,
2486 krb5_get_init_creds_opt *opt,
2487 struct hx509_certs_data *certs)
2490 if (opt->opt_private == NULL) {
2491 krb5_set_error_message(context, EINVAL,
2492 N_("PKINIT: on non extendable opt", ""));
2495 if (opt->opt_private->pk_init_ctx == NULL) {
2496 krb5_set_error_message(context, EINVAL,
2497 N_("PKINIT: on pkinit context", ""));
2501 _krb5_pk_set_user_id(context, NULL, opt->opt_private->pk_init_ctx, certs);
2505 krb5_set_error_message(context, EINVAL,
2506 N_("no support for PKINIT compiled in", ""));
2514 get_ms_san(hx509_context context, hx509_cert cert, char **upn)
2516 hx509_octet_string_list list;
2521 ret = hx509_cert_find_subjectAltName_otherName(context,
2523 &asn1_oid_id_pkinit_ms_san,
2528 if (list.len > 0 && list.val[0].length > 0)
2529 ret = decode_MS_UPN_SAN(list.val[0].data, list.val[0].length,
2533 hx509_free_octet_string_list(&list);
2539 find_ms_san(hx509_context context, hx509_cert cert, void *ctx)
2544 ret = get_ms_san(context, cert, &upn);
2555 * Private since it need to be redesigned using krb5_get_init_creds()
2558 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2559 krb5_pk_enterprise_cert(krb5_context context,
2560 const char *user_id,
2561 krb5_const_realm realm,
2562 krb5_principal *principal,
2563 struct hx509_certs_data **res)
2566 krb5_error_code ret;
2567 hx509_certs certs, result;
2568 hx509_cert cert = NULL;
2576 if (user_id == NULL) {
2577 krb5_set_error_message(context, ENOENT, "no user id");
2581 ret = hx509_certs_init(context->hx509ctx, user_id, 0, NULL, &certs);
2583 pk_copy_error(context, context->hx509ctx, ret,
2584 "Failed to init cert certs");
2588 ret = hx509_query_alloc(context->hx509ctx, &q);
2590 krb5_set_error_message(context, ret, "out of memory");
2591 hx509_certs_free(&certs);
2595 hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
2596 hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE);
2597 hx509_query_match_eku(q, &asn1_oid_id_pkinit_ms_eku);
2598 hx509_query_match_cmp_func(q, find_ms_san, NULL);
2600 ret = hx509_certs_filter(context->hx509ctx, certs, q, &result);
2601 hx509_query_free(context->hx509ctx, q);
2602 hx509_certs_free(&certs);
2604 pk_copy_error(context, context->hx509ctx, ret,
2605 "Failed to find PKINIT certificate");
2609 ret = hx509_get_one_cert(context->hx509ctx, result, &cert);
2610 hx509_certs_free(&result);
2612 pk_copy_error(context, context->hx509ctx, ret,
2613 "Failed to get one cert");
2617 ret = get_ms_san(context->hx509ctx, cert, &name);
2619 pk_copy_error(context, context->hx509ctx, ret,
2620 "Failed to get MS SAN");
2624 ret = krb5_make_principal(context, principal, realm, name, NULL);
2629 krb5_principal_set_type(context, *principal, KRB5_NT_ENTERPRISE_PRINCIPAL);
2632 ret = hx509_certs_init(context->hx509ctx, "MEMORY:", 0, NULL, res);
2636 ret = hx509_certs_add(context->hx509ctx, *res, cert);
2638 hx509_certs_free(res);
2644 hx509_cert_free(cert);
2648 krb5_set_error_message(context, EINVAL,
2649 N_("no support for PKINIT compiled in", ""));