2 * Copyright (c) 2003 - 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include "krb5_locl.h"
36 struct krb5_dh_moduli {
47 #include <pkcs8_asn1.h>
48 #include <pkcs9_asn1.h>
49 #include <pkcs12_asn1.h>
50 #include <pkinit_asn1.h>
59 struct krb5_pk_init_ctx_data {
60 struct krb5_pk_identity *id;
61 enum { USE_RSA, USE_DH, USE_ECDH } keyex;
68 krb5_data *clientDHNonce;
69 struct krb5_dh_moduli **m;
71 enum krb5_pk_type type;
72 unsigned int require_binding:1;
73 unsigned int require_eku:1;
74 unsigned int require_krbtgt_otherName:1;
75 unsigned int require_hostname_match:1;
76 unsigned int trustedCertifiers:1;
80 pk_copy_error(krb5_context context,
81 hx509_context hx509ctx,
85 __attribute__ ((format (printf, 4, 5)));
91 void KRB5_LIB_FUNCTION
92 _krb5_pk_cert_free(struct krb5_pk_cert *cert)
95 hx509_cert_free(cert->cert);
100 static krb5_error_code
101 BN_to_integer(krb5_context context, BIGNUM *bn, heim_integer *integer)
103 integer->length = BN_num_bytes(bn);
104 integer->data = malloc(integer->length);
105 if (integer->data == NULL) {
106 krb5_clear_error_message(context);
109 BN_bn2bin(bn, integer->data);
110 integer->negative = BN_is_negative(bn);
115 integer_to_BN(krb5_context context, const char *field, const heim_integer *f)
119 bn = BN_bin2bn((const unsigned char *)f->data, f->length, NULL);
121 krb5_set_error_message(context, ENOMEM,
122 N_("PKINIT: parsing BN failed %s", ""), field);
125 BN_set_negative(bn, f->negative);
129 static krb5_error_code
130 select_dh_group(krb5_context context, DH *dh, unsigned long bits,
131 struct krb5_dh_moduli **moduli)
133 const struct krb5_dh_moduli *m;
136 m = moduli[1]; /* XXX */
138 m = moduli[0]; /* XXX */
141 for (i = 0; moduli[i] != NULL; i++) {
142 if (bits < moduli[i]->bits)
145 if (moduli[i] == NULL) {
146 krb5_set_error_message(context, EINVAL,
147 N_("Did not find a DH group parameter "
148 "matching requirement of %lu bits", ""),
155 dh->p = integer_to_BN(context, "p", &m->p);
158 dh->g = integer_to_BN(context, "g", &m->g);
161 dh->q = integer_to_BN(context, "q", &m->q);
174 * Try searchin the key by to use by first looking for for PK-INIT
175 * EKU, then the Microsoft smart card EKU and last, no special EKU at all.
178 static krb5_error_code
179 find_cert(krb5_context context, struct krb5_pk_identity *id,
180 hx509_query *q, hx509_cert *cert)
182 struct certfind cf[3] = {
189 cf[0].oid = &asn1_oid_id_pkekuoid;
190 cf[1].oid = &asn1_oid_id_pkinit_ms_eku;
193 for (i = 0; i < sizeof(cf)/sizeof(cf[0]); i++) {
194 ret = hx509_query_match_eku(q, cf[i].oid);
196 pk_copy_error(context, id->hx509ctx, ret,
197 "Failed setting %s OID", cf[i].type);
201 ret = hx509_certs_find(id->hx509ctx, id->certs, q, cert);
204 pk_copy_error(context, id->hx509ctx, ret,
205 "Failed finding certificate with %s OID", cf[i].type);
211 static krb5_error_code
212 create_signature(krb5_context context,
213 const heim_oid *eContentType,
215 struct krb5_pk_identity *id,
216 hx509_peer_info peer,
221 if (id->cert == NULL)
222 flags |= HX509_CMS_SIGNATURE_NO_SIGNER;
224 ret = hx509_cms_create_signed_1(id->hx509ctx,
236 pk_copy_error(context, id->hx509ctx, ret,
237 "Create CMS signedData");
245 cert2epi(hx509_context context, void *ctx, hx509_cert c)
247 ExternalPrincipalIdentifiers *ids = ctx;
248 ExternalPrincipalIdentifier id;
249 hx509_name subject = NULL;
256 memset(&id, 0, sizeof(id));
258 ret = hx509_cert_get_subject(c, &subject);
262 if (hx509_name_is_null_p(subject) != 0) {
264 id.subjectName = calloc(1, sizeof(*id.subjectName));
265 if (id.subjectName == NULL) {
266 hx509_name_free(&subject);
267 free_ExternalPrincipalIdentifier(&id);
271 ret = hx509_name_binary(subject, id.subjectName);
273 hx509_name_free(&subject);
274 free_ExternalPrincipalIdentifier(&id);
278 hx509_name_free(&subject);
281 id.issuerAndSerialNumber = calloc(1, sizeof(*id.issuerAndSerialNumber));
282 if (id.issuerAndSerialNumber == NULL) {
283 free_ExternalPrincipalIdentifier(&id);
288 IssuerAndSerialNumber iasn;
292 memset(&iasn, 0, sizeof(iasn));
294 ret = hx509_cert_get_issuer(c, &issuer);
296 free_ExternalPrincipalIdentifier(&id);
300 ret = hx509_name_to_Name(issuer, &iasn.issuer);
301 hx509_name_free(&issuer);
303 free_ExternalPrincipalIdentifier(&id);
307 ret = hx509_cert_get_serialnumber(c, &iasn.serialNumber);
309 free_IssuerAndSerialNumber(&iasn);
310 free_ExternalPrincipalIdentifier(&id);
314 ASN1_MALLOC_ENCODE(IssuerAndSerialNumber,
315 id.issuerAndSerialNumber->data,
316 id.issuerAndSerialNumber->length,
318 free_IssuerAndSerialNumber(&iasn);
321 if (id.issuerAndSerialNumber->length != size)
325 id.subjectKeyIdentifier = NULL;
327 p = realloc(ids->val, sizeof(ids->val[0]) * (ids->len + 1));
329 free_ExternalPrincipalIdentifier(&id);
334 ids->val[ids->len] = id;
340 static krb5_error_code
341 build_edi(krb5_context context,
342 hx509_context hx509ctx,
344 ExternalPrincipalIdentifiers *ids)
346 return hx509_certs_iter(hx509ctx, certs, cert2epi, ids);
349 static krb5_error_code
350 build_auth_pack(krb5_context context,
352 krb5_pk_init_ctx ctx,
353 const KDC_REQ_BODY *body,
356 size_t buf_size, len;
363 krb5_clear_error_message(context);
365 memset(&checksum, 0, sizeof(checksum));
367 krb5_us_timeofday(context, &sec, &usec);
368 a->pkAuthenticator.ctime = sec;
369 a->pkAuthenticator.nonce = nonce;
371 ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, body, &len, ret);
375 krb5_abortx(context, "internal error in ASN.1 encoder");
377 ret = krb5_create_checksum(context,
388 ALLOC(a->pkAuthenticator.paChecksum, 1);
389 if (a->pkAuthenticator.paChecksum == NULL) {
390 krb5_set_error_message(context, ENOMEM,
391 N_("malloc: out of memory", ""));
395 ret = krb5_data_copy(a->pkAuthenticator.paChecksum,
396 checksum.checksum.data, checksum.checksum.length);
397 free_Checksum(&checksum);
401 if (ctx->keyex == USE_DH || ctx->keyex == USE_ECDH) {
402 const char *moduli_file;
403 unsigned long dh_min_bits;
407 krb5_data_zero(&dhbuf);
411 moduli_file = krb5_config_get_string(context, NULL,
417 krb5_config_get_int_default(context, NULL, 0,
419 "pkinit_dh_min_bits",
422 ret = _krb5_parse_moduli(context, moduli_file, &ctx->m);
426 ctx->u.dh = DH_new();
427 if (ctx->u.dh == NULL) {
428 krb5_set_error_message(context, ENOMEM,
429 N_("malloc: out of memory", ""));
433 ret = select_dh_group(context, ctx->u.dh, dh_min_bits, ctx->m);
437 if (DH_generate_key(ctx->u.dh) != 1) {
438 krb5_set_error_message(context, ENOMEM,
439 N_("pkinit: failed to generate DH key", ""));
444 if (1 /* support_cached_dh */) {
445 ALLOC(a->clientDHNonce, 1);
446 if (a->clientDHNonce == NULL) {
447 krb5_clear_error_message(context);
450 ret = krb5_data_alloc(a->clientDHNonce, 40);
451 if (a->clientDHNonce == NULL) {
452 krb5_clear_error_message(context);
455 RAND_bytes(a->clientDHNonce->data, a->clientDHNonce->length);
456 ret = krb5_copy_data(context, a->clientDHNonce,
457 &ctx->clientDHNonce);
462 ALLOC(a->clientPublicValue, 1);
463 if (a->clientPublicValue == NULL)
466 if (ctx->keyex == USE_DH) {
469 heim_integer dh_pub_key;
471 ret = der_copy_oid(&asn1_oid_id_dhpublicnumber,
472 &a->clientPublicValue->algorithm.algorithm);
476 memset(&dp, 0, sizeof(dp));
478 ret = BN_to_integer(context, dh->p, &dp.p);
480 free_DomainParameters(&dp);
483 ret = BN_to_integer(context, dh->g, &dp.g);
485 free_DomainParameters(&dp);
488 ret = BN_to_integer(context, dh->q, &dp.q);
490 free_DomainParameters(&dp);
494 dp.validationParms = NULL;
496 a->clientPublicValue->algorithm.parameters =
497 malloc(sizeof(*a->clientPublicValue->algorithm.parameters));
498 if (a->clientPublicValue->algorithm.parameters == NULL) {
499 free_DomainParameters(&dp);
503 ASN1_MALLOC_ENCODE(DomainParameters,
504 a->clientPublicValue->algorithm.parameters->data,
505 a->clientPublicValue->algorithm.parameters->length,
507 free_DomainParameters(&dp);
510 if (size != a->clientPublicValue->algorithm.parameters->length)
511 krb5_abortx(context, "Internal ASN1 encoder error");
513 ret = BN_to_integer(context, dh->pub_key, &dh_pub_key);
517 ASN1_MALLOC_ENCODE(DHPublicKey, dhbuf.data, dhbuf.length,
518 &dh_pub_key, &size, ret);
519 der_free_heim_integer(&dh_pub_key);
522 if (size != dhbuf.length)
523 krb5_abortx(context, "asn1 internal error");
524 } else if (ctx->keyex == USE_ECDH) {
530 /* copy in public key, XXX find the best curve that the server support or use the clients curve if possible */
532 ecp.element = choice_ECParameters_namedCurve;
533 ret = der_copy_oid(&asn1_oid_id_ec_group_secp256r1,
538 ALLOC(a->clientPublicValue->algorithm.parameters, 1);
539 if (a->clientPublicValue->algorithm.parameters == NULL) {
540 free_ECParameters(&ecp);
543 ASN1_MALLOC_ENCODE(ECParameters, p, len, &ecp, &size, ret);
544 free_ECParameters(&ecp);
548 krb5_abortx(context, "asn1 internal error");
550 a->clientPublicValue->algorithm.parameters->data = p;
551 a->clientPublicValue->algorithm.parameters->length = size;
553 /* copy in public key */
555 ret = der_copy_oid(&asn1_oid_id_ecPublicKey,
556 &a->clientPublicValue->algorithm.algorithm);
560 ctx->u.eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
561 if (ctx->u.eckey == NULL)
564 ret = EC_KEY_generate_key(ctx->u.eckey);
568 /* encode onto dhkey */
570 len = i2o_ECPublicKey(ctx->u.eckey, NULL);
574 dhbuf.data = malloc(len);
575 if (dhbuf.data == NULL)
580 len = i2o_ECPublicKey(ctx->u.eckey, &p);
584 /* XXX verify that this is right with RFC3279 */
589 krb5_abortx(context, "internal error");
590 a->clientPublicValue->subjectPublicKey.length = dhbuf.length * 8;
591 a->clientPublicValue->subjectPublicKey.data = dhbuf.data;
595 a->supportedCMSTypes = calloc(1, sizeof(*a->supportedCMSTypes));
596 if (a->supportedCMSTypes == NULL)
599 ret = hx509_crypto_available(ctx->id->hx509ctx, HX509_SELECT_ALL, NULL,
600 &a->supportedCMSTypes->val,
601 &a->supportedCMSTypes->len);
609 krb5_error_code KRB5_LIB_FUNCTION
610 _krb5_pk_mk_ContentInfo(krb5_context context,
611 const krb5_data *buf,
613 struct ContentInfo *content_info)
617 ret = der_copy_oid(oid, &content_info->contentType);
620 ALLOC(content_info->content, 1);
621 if (content_info->content == NULL)
623 content_info->content->data = malloc(buf->length);
624 if (content_info->content->data == NULL)
626 memcpy(content_info->content->data, buf->data, buf->length);
627 content_info->content->length = buf->length;
631 static krb5_error_code
632 pk_mk_padata(krb5_context context,
633 krb5_pk_init_ctx ctx,
634 const KDC_REQ_BODY *req_body,
638 struct ContentInfo content_info;
642 krb5_data buf, sd_buf;
645 krb5_data_zero(&buf);
646 krb5_data_zero(&sd_buf);
647 memset(&content_info, 0, sizeof(content_info));
649 if (ctx->type == PKINIT_WIN2K) {
654 memset(&ap, 0, sizeof(ap));
656 /* fill in PKAuthenticator */
657 ret = copy_PrincipalName(req_body->sname, &ap.pkAuthenticator.kdcName);
659 free_AuthPack_Win2k(&ap);
660 krb5_clear_error_message(context);
663 ret = copy_Realm(&req_body->realm, &ap.pkAuthenticator.kdcRealm);
665 free_AuthPack_Win2k(&ap);
666 krb5_clear_error_message(context);
670 krb5_us_timeofday(context, &sec, &usec);
671 ap.pkAuthenticator.ctime = sec;
672 ap.pkAuthenticator.cusec = usec;
673 ap.pkAuthenticator.nonce = nonce;
675 ASN1_MALLOC_ENCODE(AuthPack_Win2k, buf.data, buf.length,
677 free_AuthPack_Win2k(&ap);
679 krb5_set_error_message(context, ret,
680 N_("Failed encoding AuthPackWin: %d", ""),
684 if (buf.length != size)
685 krb5_abortx(context, "internal ASN1 encoder error");
687 oid = &asn1_oid_id_pkcs7_data;
688 } else if (ctx->type == PKINIT_27) {
691 memset(&ap, 0, sizeof(ap));
693 ret = build_auth_pack(context, nonce, ctx, req_body, &ap);
699 ASN1_MALLOC_ENCODE(AuthPack, buf.data, buf.length, &ap, &size, ret);
702 krb5_set_error_message(context, ret,
703 N_("Failed encoding AuthPack: %d", ""),
707 if (buf.length != size)
708 krb5_abortx(context, "internal ASN1 encoder error");
710 oid = &asn1_oid_id_pkauthdata;
712 krb5_abortx(context, "internal pkinit error");
714 ret = create_signature(context, oid, &buf, ctx->id,
716 krb5_data_free(&buf);
720 ret = hx509_cms_wrap_ContentInfo(&asn1_oid_id_pkcs7_signedData, &sd_buf, &buf);
721 krb5_data_free(&sd_buf);
723 krb5_set_error_message(context, ret,
724 N_("ContentInfo wrapping of signedData failed",""));
728 if (ctx->type == PKINIT_WIN2K) {
729 PA_PK_AS_REQ_Win2k winreq;
731 pa_type = KRB5_PADATA_PK_AS_REQ_WIN;
733 memset(&winreq, 0, sizeof(winreq));
735 winreq.signed_auth_pack = buf;
737 ASN1_MALLOC_ENCODE(PA_PK_AS_REQ_Win2k, buf.data, buf.length,
738 &winreq, &size, ret);
739 free_PA_PK_AS_REQ_Win2k(&winreq);
741 } else if (ctx->type == PKINIT_27) {
744 pa_type = KRB5_PADATA_PK_AS_REQ;
746 memset(&req, 0, sizeof(req));
747 req.signedAuthPack = buf;
749 if (ctx->trustedCertifiers) {
751 req.trustedCertifiers = calloc(1, sizeof(*req.trustedCertifiers));
752 if (req.trustedCertifiers == NULL) {
754 krb5_set_error_message(context, ret,
755 N_("malloc: out of memory", ""));
756 free_PA_PK_AS_REQ(&req);
759 ret = build_edi(context, ctx->id->hx509ctx,
760 ctx->id->anchors, req.trustedCertifiers);
762 krb5_set_error_message(context, ret,
763 N_("pk-init: failed to build "
764 "trustedCertifiers", ""));
765 free_PA_PK_AS_REQ(&req);
771 ASN1_MALLOC_ENCODE(PA_PK_AS_REQ, buf.data, buf.length,
774 free_PA_PK_AS_REQ(&req);
777 krb5_abortx(context, "internal pkinit error");
779 krb5_set_error_message(context, ret, "PA-PK-AS-REQ %d", (int)ret);
782 if (buf.length != size)
783 krb5_abortx(context, "Internal ASN1 encoder error");
785 ret = krb5_padata_add(context, md, pa_type, buf.data, buf.length);
790 krb5_padata_add(context, md, KRB5_PADATA_PK_AS_09_BINDING, NULL, 0);
793 free_ContentInfo(&content_info);
799 krb5_error_code KRB5_LIB_FUNCTION
800 _krb5_pk_mk_padata(krb5_context context,
802 const KDC_REQ_BODY *req_body,
806 krb5_pk_init_ctx ctx = c;
809 win2k_compat = krb5_config_get_bool_default(context, NULL,
817 ctx->require_binding =
818 krb5_config_get_bool_default(context, NULL,
822 "pkinit_win2k_require_binding",
824 ctx->type = PKINIT_WIN2K;
826 ctx->type = PKINIT_27;
829 krb5_config_get_bool_default(context, NULL,
833 "pkinit_require_eku",
835 ctx->require_krbtgt_otherName =
836 krb5_config_get_bool_default(context, NULL,
840 "pkinit_require_krbtgt_otherName",
843 ctx->require_hostname_match =
844 krb5_config_get_bool_default(context, NULL,
848 "pkinit_require_hostname_match",
851 ctx->trustedCertifiers =
852 krb5_config_get_bool_default(context, NULL,
856 "pkinit_trustedCertifiers",
859 return pk_mk_padata(context, ctx, req_body, nonce, md);
862 static krb5_error_code
863 pk_verify_sign(krb5_context context,
866 struct krb5_pk_identity *id,
867 heim_oid *contentType,
869 struct krb5_pk_cert **signer)
871 hx509_certs signer_certs;
876 ret = hx509_cms_verify_signed(id->hx509ctx,
878 HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH|HX509_CMS_VS_NO_KU_CHECK,
887 pk_copy_error(context, id->hx509ctx, ret,
888 "CMS verify signed failed");
892 *signer = calloc(1, sizeof(**signer));
893 if (*signer == NULL) {
894 krb5_clear_error_message(context);
899 ret = hx509_get_one_cert(id->hx509ctx, signer_certs, &(*signer)->cert);
901 pk_copy_error(context, id->hx509ctx, ret,
902 "Failed to get on of the signer certs");
907 hx509_certs_free(&signer_certs);
910 hx509_cert_free((*signer)->cert);
919 static krb5_error_code
920 get_reply_key_win(krb5_context context,
921 const krb5_data *content,
925 ReplyKeyPack_Win2k key_pack;
929 ret = decode_ReplyKeyPack_Win2k(content->data,
934 krb5_set_error_message(context, ret,
935 N_("PKINIT decoding reply key failed", ""));
936 free_ReplyKeyPack_Win2k(&key_pack);
940 if (key_pack.nonce != nonce) {
941 krb5_set_error_message(context, ret,
942 N_("PKINIT enckey nonce is wrong", ""));
943 free_ReplyKeyPack_Win2k(&key_pack);
944 return KRB5KRB_AP_ERR_MODIFIED;
947 *key = malloc (sizeof (**key));
949 free_ReplyKeyPack_Win2k(&key_pack);
950 krb5_set_error_message(context, ENOMEM,
951 N_("malloc: out of memory", ""));
955 ret = copy_EncryptionKey(&key_pack.replyKey, *key);
956 free_ReplyKeyPack_Win2k(&key_pack);
958 krb5_set_error_message(context, ret,
959 N_("PKINIT failed copying reply key", ""));
967 static krb5_error_code
968 get_reply_key(krb5_context context,
969 const krb5_data *content,
970 const krb5_data *req_buffer,
973 ReplyKeyPack key_pack;
977 ret = decode_ReplyKeyPack(content->data,
982 krb5_set_error_message(context, ret,
983 N_("PKINIT decoding reply key failed", ""));
984 free_ReplyKeyPack(&key_pack);
992 * XXX Verify kp.replyKey is a allowed enctype in the
996 ret = krb5_crypto_init(context, &key_pack.replyKey, 0, &crypto);
998 free_ReplyKeyPack(&key_pack);
1002 ret = krb5_verify_checksum(context, crypto, 6,
1003 req_buffer->data, req_buffer->length,
1004 &key_pack.asChecksum);
1005 krb5_crypto_destroy(context, crypto);
1007 free_ReplyKeyPack(&key_pack);
1012 *key = malloc (sizeof (**key));
1014 free_ReplyKeyPack(&key_pack);
1015 krb5_set_error_message(context, ENOMEM,
1016 N_("malloc: out of memory", ""));
1020 ret = copy_EncryptionKey(&key_pack.replyKey, *key);
1021 free_ReplyKeyPack(&key_pack);
1023 krb5_set_error_message(context, ret,
1024 N_("PKINIT failed copying reply key", ""));
1033 static krb5_error_code
1034 pk_verify_host(krb5_context context,
1036 const krb5_krbhst_info *hi,
1037 struct krb5_pk_init_ctx_data *ctx,
1038 struct krb5_pk_cert *host)
1040 krb5_error_code ret = 0;
1042 if (ctx->require_eku) {
1043 ret = hx509_cert_check_eku(ctx->id->hx509ctx, host->cert,
1044 &asn1_oid_id_pkkdcekuoid, 0);
1046 krb5_set_error_message(context, ret,
1047 N_("No PK-INIT KDC EKU in kdc certificate", ""));
1051 if (ctx->require_krbtgt_otherName) {
1052 hx509_octet_string_list list;
1055 ret = hx509_cert_find_subjectAltName_otherName(ctx->id->hx509ctx,
1057 &asn1_oid_id_pkinit_san,
1060 krb5_set_error_message(context, ret,
1061 N_("Failed to find the PK-INIT "
1062 "subjectAltName in the KDC "
1063 "certificate", ""));
1068 for (i = 0; i < list.len; i++) {
1069 KRB5PrincipalName r;
1071 ret = decode_KRB5PrincipalName(list.val[i].data,
1076 krb5_set_error_message(context, ret,
1077 N_("Failed to decode the PK-INIT "
1078 "subjectAltName in the "
1079 "KDC certificate", ""));
1084 if (r.principalName.name_string.len != 2 ||
1085 strcmp(r.principalName.name_string.val[0], KRB5_TGS_NAME) != 0 ||
1086 strcmp(r.principalName.name_string.val[1], realm) != 0 ||
1087 strcmp(r.realm, realm) != 0)
1089 ret = KRB5_KDC_ERR_INVALID_CERTIFICATE;
1090 krb5_set_error_message(context, ret,
1091 N_("KDC have wrong realm name in "
1092 "the certificate", ""));
1095 free_KRB5PrincipalName(&r);
1099 hx509_free_octet_string_list(&list);
1105 ret = hx509_verify_hostname(ctx->id->hx509ctx, host->cert,
1106 ctx->require_hostname_match,
1109 hi->ai->ai_addr, hi->ai->ai_addrlen);
1112 krb5_set_error_message(context, ret,
1113 N_("Address mismatch in "
1114 "the KDC certificate", ""));
1119 static krb5_error_code
1120 pk_rd_pa_reply_enckey(krb5_context context,
1122 const heim_octet_string *indata,
1123 const heim_oid *dataType,
1125 krb5_pk_init_ctx ctx,
1127 const krb5_krbhst_info *hi,
1129 const krb5_data *req_buffer,
1131 krb5_keyblock **key)
1133 krb5_error_code ret;
1134 struct krb5_pk_cert *host = NULL;
1136 heim_oid contentType = { 0, NULL };
1137 int flags = HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT;
1139 if (der_heim_oid_cmp(&asn1_oid_id_pkcs7_envelopedData, dataType)) {
1140 krb5_set_error_message(context, EINVAL,
1141 N_("PKINIT: Invalid content type", ""));
1145 if (ctx->type == PKINIT_WIN2K)
1146 flags |= HX509_CMS_UE_ALLOW_WEAK;
1148 ret = hx509_cms_unenvelope(ctx->id->hx509ctx,
1158 pk_copy_error(context, ctx->id->hx509ctx, ret,
1159 "Failed to unenvelope CMS data in PK-INIT reply");
1162 der_free_oid(&contentType);
1164 #if 0 /* windows LH with interesting CMS packets, leaks memory */
1166 size_t ph = 1 + der_length_len (length);
1167 unsigned char *ptr = malloc(length + ph);
1170 memcpy(ptr + ph, p, length);
1172 ret = der_put_length_and_tag (ptr + ph - 1, ph, length,
1173 ASN1_C_UNIV, CONS, UT_Sequence, &l);
1182 /* win2k uses ContentInfo */
1183 if (type == PKINIT_WIN2K) {
1185 heim_octet_string out;
1187 ret = hx509_cms_unwrap_ContentInfo(&content, &type, &out, NULL);
1190 if (der_heim_oid_cmp(&type, &asn1_oid_id_pkcs7_signedData)) {
1191 ret = EINVAL; /* XXX */
1192 krb5_set_error_message(context, ret,
1193 N_("PKINIT: Invalid content type", ""));
1194 der_free_oid(&type);
1195 der_free_octet_string(&out);
1198 der_free_oid(&type);
1199 krb5_data_free(&content);
1200 ret = krb5_data_copy(&content, out.data, out.length);
1201 der_free_octet_string(&out);
1203 krb5_set_error_message(context, ret,
1204 N_("malloc: out of memory", ""));
1209 ret = pk_verify_sign(context,
1219 /* make sure that it is the kdc's certificate */
1220 ret = pk_verify_host(context, realm, hi, ctx, host);
1226 if (type == PKINIT_WIN2K) {
1227 if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkcs7_data) != 0) {
1228 ret = KRB5KRB_AP_ERR_MSG_TYPE;
1229 krb5_set_error_message(context, ret, "PKINIT: reply key, wrong oid");
1233 if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkrkeydata) != 0) {
1234 ret = KRB5KRB_AP_ERR_MSG_TYPE;
1235 krb5_set_error_message(context, ret, "PKINIT: reply key, wrong oid");
1243 ret = get_reply_key(context, &content, req_buffer, key);
1244 if (ret != 0 && ctx->require_binding == 0)
1245 ret = get_reply_key_win(context, &content, nonce, key);
1248 ret = get_reply_key(context, &content, req_buffer, key);
1254 /* XXX compare given etype with key->etype */
1258 _krb5_pk_cert_free(host);
1259 der_free_oid(&contentType);
1260 krb5_data_free(&content);
1265 static krb5_error_code
1266 pk_rd_pa_reply_dh(krb5_context context,
1267 const heim_octet_string *indata,
1268 const heim_oid *dataType,
1270 krb5_pk_init_ctx ctx,
1272 const krb5_krbhst_info *hi,
1277 krb5_keyblock **key)
1279 const unsigned char *p;
1280 unsigned char *dh_gen_key = NULL;
1281 struct krb5_pk_cert *host = NULL;
1282 BIGNUM *kdc_dh_pubkey = NULL;
1283 KDCDHKeyInfo kdc_dh_info;
1284 heim_oid contentType = { 0, NULL };
1286 krb5_error_code ret;
1287 int dh_gen_keylen = 0;
1290 krb5_data_zero(&content);
1291 memset(&kdc_dh_info, 0, sizeof(kdc_dh_info));
1293 if (der_heim_oid_cmp(&asn1_oid_id_pkcs7_signedData, dataType)) {
1294 krb5_set_error_message(context, EINVAL,
1295 N_("PKINIT: Invalid content type", ""));
1299 ret = pk_verify_sign(context,
1309 /* make sure that it is the kdc's certificate */
1310 ret = pk_verify_host(context, realm, hi, ctx, host);
1314 if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkdhkeydata)) {
1315 ret = KRB5KRB_AP_ERR_MSG_TYPE;
1316 krb5_set_error_message(context, ret,
1317 N_("pkinit - dh reply contains wrong oid", ""));
1321 ret = decode_KDCDHKeyInfo(content.data,
1327 krb5_set_error_message(context, ret,
1328 N_("pkinit - failed to decode "
1329 "KDC DH Key Info", ""));
1333 if (kdc_dh_info.nonce != nonce) {
1334 ret = KRB5KRB_AP_ERR_MODIFIED;
1335 krb5_set_error_message(context, ret,
1336 N_("PKINIT: DH nonce is wrong", ""));
1340 if (kdc_dh_info.dhKeyExpiration) {
1342 ret = KRB5KRB_ERR_GENERIC;
1343 krb5_set_error_message(context, ret,
1344 N_("pkinit; got key expiration "
1345 "without server nonce", ""));
1349 ret = KRB5KRB_ERR_GENERIC;
1350 krb5_set_error_message(context, ret,
1351 N_("pkinit; got DH reuse but no "
1352 "client nonce", ""));
1357 ret = KRB5KRB_ERR_GENERIC;
1358 krb5_set_error_message(context, ret,
1359 N_("pkinit: got server nonce "
1360 "without key expiration", ""));
1367 p = kdc_dh_info.subjectPublicKey.data;
1368 size = (kdc_dh_info.subjectPublicKey.length + 7) / 8;
1370 if (ctx->keyex == USE_DH) {
1372 ret = decode_DHPublicKey(p, size, &k, NULL);
1374 krb5_set_error_message(context, ret,
1375 N_("pkinit: can't decode "
1376 "without key expiration", ""));
1380 kdc_dh_pubkey = integer_to_BN(context, "DHPublicKey", &k);
1381 free_DHPublicKey(&k);
1382 if (kdc_dh_pubkey == NULL) {
1388 dh_gen_keylen = DH_size(ctx->u.dh);
1389 size = BN_num_bytes(ctx->u.dh->p);
1390 if (size < dh_gen_keylen)
1391 size = dh_gen_keylen;
1393 dh_gen_key = malloc(size);
1394 if (dh_gen_key == NULL) {
1396 krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
1399 memset(dh_gen_key, 0, size - dh_gen_keylen);
1401 dh_gen_keylen = DH_compute_key(dh_gen_key + (size - dh_gen_keylen),
1402 kdc_dh_pubkey, ctx->u.dh);
1403 if (dh_gen_keylen == -1) {
1404 ret = KRB5KRB_ERR_GENERIC;
1406 krb5_set_error_message(context, ret,
1407 N_("PKINIT: Can't compute Diffie-Hellman key", ""));
1412 const EC_GROUP *group;
1413 EC_KEY *public = NULL;
1415 group = EC_KEY_get0_group(ctx->u.eckey);
1417 public = EC_KEY_new();
1418 if (public == NULL) {
1422 if (EC_KEY_set_group(public, group) != 1) {
1423 EC_KEY_free(public);
1428 if (o2i_ECPublicKey(&public, &p, size) == NULL) {
1429 EC_KEY_free(public);
1430 ret = KRB5KRB_ERR_GENERIC;
1431 krb5_set_error_message(context, ret,
1432 N_("PKINIT: Can't parse ECDH public key", ""));
1436 size = (EC_GROUP_get_degree(group) + 7) / 8;
1437 dh_gen_key = malloc(size);
1438 if (dh_gen_key == NULL) {
1439 EC_KEY_free(public);
1441 krb5_set_error_message(context, ret,
1442 N_("malloc: out of memory", ""));
1445 dh_gen_keylen = ECDH_compute_key(dh_gen_key, size,
1446 EC_KEY_get0_public_key(public), ctx->u.eckey, NULL);
1447 EC_KEY_free(public);
1448 if (dh_gen_keylen == -1) {
1449 ret = KRB5KRB_ERR_GENERIC;
1451 krb5_set_error_message(context, ret,
1452 N_("PKINIT: Can't compute ECDH public key", ""));
1460 if (dh_gen_keylen <= 0) {
1462 krb5_set_error_message(context, ret,
1463 N_("PKINIT: resulting DH key <= 0", ""));
1468 *key = malloc (sizeof (**key));
1471 krb5_set_error_message(context, ret,
1472 N_("malloc: out of memory", ""));
1476 ret = _krb5_pk_octetstring2key(context,
1478 dh_gen_key, dh_gen_keylen,
1482 krb5_set_error_message(context, ret,
1483 N_("PKINIT: can't create key from DH key", ""));
1491 BN_free(kdc_dh_pubkey);
1493 memset(dh_gen_key, 0, dh_gen_keylen);
1497 _krb5_pk_cert_free(host);
1499 krb5_data_free(&content);
1500 der_free_oid(&contentType);
1501 free_KDCDHKeyInfo(&kdc_dh_info);
1506 krb5_error_code KRB5_LIB_FUNCTION
1507 _krb5_pk_rd_pa_reply(krb5_context context,
1511 const krb5_krbhst_info *hi,
1513 const krb5_data *req_buffer,
1515 krb5_keyblock **key)
1517 krb5_pk_init_ctx ctx = c;
1518 krb5_error_code ret;
1521 /* Check for IETF PK-INIT first */
1522 if (ctx->type == PKINIT_27) {
1524 heim_octet_string os, data;
1527 if (pa->padata_type != KRB5_PADATA_PK_AS_REP) {
1528 krb5_set_error_message(context, EINVAL,
1529 N_("PKINIT: wrong padata recv", ""));
1533 ret = decode_PA_PK_AS_REP(pa->padata_value.data,
1534 pa->padata_value.length,
1538 krb5_set_error_message(context, ret,
1539 N_("Failed to decode pkinit AS rep", ""));
1543 switch (rep.element) {
1544 case choice_PA_PK_AS_REP_dhInfo:
1545 os = rep.u.dhInfo.dhSignedData;
1547 case choice_PA_PK_AS_REP_encKeyPack:
1548 os = rep.u.encKeyPack;
1551 PA_PK_AS_REP_BTMM btmm;
1552 free_PA_PK_AS_REP(&rep);
1553 memset(&rep, 0, sizeof(rep));
1555 ret = decode_PA_PK_AS_REP_BTMM(pa->padata_value.data,
1556 pa->padata_value.length,
1560 krb5_set_error_message(context, EINVAL,
1561 N_("PKINIT: -27 reply "
1562 "invalid content type", ""));
1566 if (btmm.dhSignedData || btmm.encKeyPack == NULL) {
1567 free_PA_PK_AS_REP_BTMM(&btmm);
1569 krb5_set_error_message(context, ret,
1570 N_("DH mode not supported for BTMM mode", ""));
1575 * Transform to IETF style PK-INIT reply so that free works below
1578 rep.element = choice_PA_PK_AS_REP_encKeyPack;
1579 rep.u.encKeyPack.data = btmm.encKeyPack->data;
1580 rep.u.encKeyPack.length = btmm.encKeyPack->length;
1581 btmm.encKeyPack->data = NULL;
1582 btmm.encKeyPack->length = 0;
1583 free_PA_PK_AS_REP_BTMM(&btmm);
1584 os = rep.u.encKeyPack;
1588 ret = hx509_cms_unwrap_ContentInfo(&os, &oid, &data, NULL);
1590 free_PA_PK_AS_REP(&rep);
1591 krb5_set_error_message(context, ret,
1592 N_("PKINIT: failed to unwrap CI", ""));
1596 switch (rep.element) {
1597 case choice_PA_PK_AS_REP_dhInfo:
1598 ret = pk_rd_pa_reply_dh(context, &data, &oid, realm, ctx, etype, hi,
1600 rep.u.dhInfo.serverDHNonce,
1603 case choice_PA_PK_AS_REP_encKeyPack:
1604 ret = pk_rd_pa_reply_enckey(context, PKINIT_27, &data, &oid, realm,
1605 ctx, etype, hi, nonce, req_buffer, pa, key);
1608 krb5_abortx(context, "pk-init as-rep case not possible to happen");
1610 der_free_octet_string(&data);
1612 free_PA_PK_AS_REP(&rep);
1614 } else if (ctx->type == PKINIT_WIN2K) {
1615 PA_PK_AS_REP_Win2k w2krep;
1617 /* Check for Windows encoding of the AS-REP pa data */
1619 #if 0 /* should this be ? */
1620 if (pa->padata_type != KRB5_PADATA_PK_AS_REP) {
1621 krb5_set_error_message(context, EINVAL,
1622 "PKINIT: wrong padata recv");
1627 memset(&w2krep, 0, sizeof(w2krep));
1629 ret = decode_PA_PK_AS_REP_Win2k(pa->padata_value.data,
1630 pa->padata_value.length,
1634 krb5_set_error_message(context, ret,
1635 N_("PKINIT: Failed decoding windows "
1636 "pkinit reply %d", ""), (int)ret);
1640 krb5_clear_error_message(context);
1642 switch (w2krep.element) {
1643 case choice_PA_PK_AS_REP_Win2k_encKeyPack: {
1644 heim_octet_string data;
1647 ret = hx509_cms_unwrap_ContentInfo(&w2krep.u.encKeyPack,
1649 free_PA_PK_AS_REP_Win2k(&w2krep);
1651 krb5_set_error_message(context, ret,
1652 N_("PKINIT: failed to unwrap CI", ""));
1656 ret = pk_rd_pa_reply_enckey(context, PKINIT_WIN2K, &data, &oid, realm,
1657 ctx, etype, hi, nonce, req_buffer, pa, key);
1658 der_free_octet_string(&data);
1664 free_PA_PK_AS_REP_Win2k(&w2krep);
1666 krb5_set_error_message(context, ret,
1667 N_("PKINIT: win2k reply invalid "
1668 "content type", ""));
1674 krb5_set_error_message(context, ret,
1675 N_("PKINIT: unknown reply type", ""));
1682 krb5_context context;
1683 krb5_prompter_fct prompter;
1684 void *prompter_data;
1688 hx_pass_prompter(void *data, const hx509_prompt *prompter)
1690 krb5_error_code ret;
1692 krb5_data password_data;
1693 struct prompter *p = data;
1695 password_data.data = prompter->reply.data;
1696 password_data.length = prompter->reply.length;
1698 prompt.prompt = prompter->prompt;
1699 prompt.hidden = hx509_prompt_hidden(prompter->type);
1700 prompt.reply = &password_data;
1702 switch (prompter->type) {
1703 case HX509_PROMPT_TYPE_INFO:
1704 prompt.type = KRB5_PROMPT_TYPE_INFO;
1706 case HX509_PROMPT_TYPE_PASSWORD:
1707 case HX509_PROMPT_TYPE_QUESTION:
1709 prompt.type = KRB5_PROMPT_TYPE_PASSWORD;
1713 ret = (*p->prompter)(p->context, p->prompter_data, NULL, NULL, 1, &prompt);
1715 memset (prompter->reply.data, 0, prompter->reply.length);
1721 krb5_error_code KRB5_LIB_FUNCTION
1722 _krb5_pk_load_id(krb5_context context,
1723 struct krb5_pk_identity **ret_id,
1725 const char *user_id,
1726 const char *anchor_id,
1727 char * const *chain_list,
1728 char * const *revoke_list,
1729 krb5_prompter_fct prompter,
1730 void *prompter_data,
1733 struct krb5_pk_identity *id = NULL;
1734 hx509_lock lock = NULL;
1740 if (anchor_id == NULL) {
1741 krb5_set_error_message(context, HEIM_PKINIT_NO_VALID_CA,
1742 N_("PKINIT: No anchor given", ""));
1743 return HEIM_PKINIT_NO_VALID_CA;
1746 if (user_id == NULL && (flags & 4) == 0) {
1747 krb5_set_error_message(context, HEIM_PKINIT_NO_PRIVATE_KEY,
1748 N_("PKINIT: No user certificate given", ""));
1749 return HEIM_PKINIT_NO_PRIVATE_KEY;
1754 id = calloc(1, sizeof(*id));
1756 krb5_set_error_message(context, ENOMEM,
1757 N_("malloc: out of memory", ""));
1761 ret = hx509_context_init(&id->hx509ctx);
1765 ret = hx509_lock_init(id->hx509ctx, &lock);
1767 pk_copy_error(context, id->hx509ctx, ret, "Failed init lock");
1771 if (password && password[0])
1772 hx509_lock_add_password(lock, password);
1775 p.context = context;
1776 p.prompter = prompter;
1777 p.prompter_data = prompter_data;
1779 ret = hx509_lock_set_prompter(lock, hx_pass_prompter, &p);
1785 ret = hx509_certs_init(id->hx509ctx, user_id, 0, lock, &id->certs);
1787 pk_copy_error(context, id->hx509ctx, ret,
1788 "Failed to init cert certs");
1795 ret = hx509_certs_init(id->hx509ctx, anchor_id, 0, NULL, &id->anchors);
1797 pk_copy_error(context, id->hx509ctx, ret,
1798 "Failed to init anchors");
1802 ret = hx509_certs_init(id->hx509ctx, "MEMORY:pkinit-cert-chain",
1803 0, NULL, &id->certpool);
1805 pk_copy_error(context, id->hx509ctx, ret,
1806 "Failed to init chain");
1810 while (chain_list && *chain_list) {
1811 ret = hx509_certs_append(id->hx509ctx, id->certpool,
1814 pk_copy_error(context, id->hx509ctx, ret,
1815 "Failed to laod chain %s",
1823 ret = hx509_revoke_init(id->hx509ctx, &id->revokectx);
1825 pk_copy_error(context, id->hx509ctx, ret,
1826 "Failed init revoke list");
1830 while (*revoke_list) {
1831 ret = hx509_revoke_add_crl(id->hx509ctx,
1835 pk_copy_error(context, id->hx509ctx, ret,
1836 "Failed load revoke list");
1842 hx509_context_set_missing_revoke(id->hx509ctx, 1);
1844 ret = hx509_verify_init_ctx(id->hx509ctx, &id->verify_ctx);
1846 pk_copy_error(context, id->hx509ctx, ret,
1847 "Failed init verify context");
1851 hx509_verify_attach_anchors(id->verify_ctx, id->anchors);
1852 hx509_verify_attach_revoke(id->verify_ctx, id->revokectx);
1856 hx509_verify_destroy_ctx(id->verify_ctx);
1857 hx509_certs_free(&id->certs);
1858 hx509_certs_free(&id->anchors);
1859 hx509_certs_free(&id->certpool);
1860 hx509_revoke_free(&id->revokectx);
1861 hx509_context_free(&id->hx509ctx);
1867 hx509_lock_free(lock);
1877 pk_copy_error(krb5_context context,
1878 hx509_context hx509ctx,
1887 vasprintf(&f, fmt, va);
1890 krb5_clear_error_message(context);
1894 s = hx509_get_error_string(hx509ctx, hxret);
1896 krb5_clear_error_message(context);
1900 krb5_set_error_message(context, hxret, "%s: %s", f, s);
1906 parse_integer(krb5_context context, char **p, const char *file, int lineno,
1907 const char *name, heim_integer *integer)
1911 p1 = strsep(p, " \t");
1913 krb5_set_error_message(context, EINVAL,
1914 N_("moduli file %s missing %s on line %d", ""),
1915 file, name, lineno);
1918 ret = der_parse_hex_heim_integer(p1, integer);
1920 krb5_set_error_message(context, ret,
1921 N_("moduli file %s failed parsing %s "
1923 file, name, lineno);
1931 _krb5_parse_moduli_line(krb5_context context,
1935 struct krb5_dh_moduli **m)
1937 struct krb5_dh_moduli *m1;
1943 m1 = calloc(1, sizeof(*m1));
1945 krb5_set_error_message(context, ENOMEM,
1946 N_("malloc: out of memory", ""));
1950 while (isspace((unsigned char)*p))
1958 p1 = strsep(&p, " \t");
1960 krb5_set_error_message(context, ret,
1961 N_("moduli file %s missing name on line %d", ""),
1965 m1->name = strdup(p1);
1966 if (m1->name == NULL) {
1968 krb5_set_error_message(context, ret, N_("malloc: out of memeory", ""));
1972 p1 = strsep(&p, " \t");
1974 krb5_set_error_message(context, ret,
1975 N_("moduli file %s missing bits on line %d", ""),
1980 m1->bits = atoi(p1);
1981 if (m1->bits == 0) {
1982 krb5_set_error_message(context, ret,
1983 N_("moduli file %s have un-parsable "
1984 "bits on line %d", ""), file, lineno);
1988 ret = parse_integer(context, &p, file, lineno, "p", &m1->p);
1991 ret = parse_integer(context, &p, file, lineno, "g", &m1->g);
1994 ret = parse_integer(context, &p, file, lineno, "q", &m1->q);
2003 der_free_heim_integer(&m1->p);
2004 der_free_heim_integer(&m1->g);
2005 der_free_heim_integer(&m1->q);
2011 _krb5_free_moduli(struct krb5_dh_moduli **moduli)
2014 for (i = 0; moduli[i] != NULL; i++) {
2015 free(moduli[i]->name);
2016 der_free_heim_integer(&moduli[i]->p);
2017 der_free_heim_integer(&moduli[i]->g);
2018 der_free_heim_integer(&moduli[i]->q);
2024 static const char *default_moduli_RFC2412_MODP_group2 =
2026 "RFC2412-MODP-group2 "
2030 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
2031 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
2032 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
2033 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
2034 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
2035 "FFFFFFFF" "FFFFFFFF "
2039 "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68"
2040 "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E"
2041 "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122"
2042 "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6"
2043 "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F67329C0"
2044 "FFFFFFFF" "FFFFFFFF";
2046 static const char *default_moduli_rfc3526_MODP_group14 =
2048 "rfc3526-MODP-group14 "
2052 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
2053 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
2054 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
2055 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
2056 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D"
2057 "C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"
2058 "83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"
2059 "670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"
2060 "E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"
2061 "DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
2062 "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF "
2066 "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68"
2067 "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E"
2068 "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122"
2069 "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6"
2070 "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F6722D9E"
2071 "E1003E5C" "50B1DF82" "CC6D241B" "0E2AE9CD" "348B1FD4" "7E9267AF"
2072 "C1B2AE91" "EE51D6CB" "0E3179AB" "1042A95D" "CF6A9483" "B84B4B36"
2073 "B3861AA7" "255E4C02" "78BA3604" "650C10BE" "19482F23" "171B671D"
2074 "F1CF3B96" "0C074301" "CD93C1D1" "7603D147" "DAE2AEF8" "37A62964"
2075 "EF15E5FB" "4AAC0B8C" "1CCAA4BE" "754AB572" "8AE9130C" "4C7D0288"
2076 "0AB9472D" "45565534" "7FFFFFFF" "FFFFFFFF";
2079 _krb5_parse_moduli(krb5_context context, const char *file,
2080 struct krb5_dh_moduli ***moduli)
2082 /* name bits P G Q */
2083 krb5_error_code ret;
2084 struct krb5_dh_moduli **m = NULL, **m2;
2087 int lineno = 0, n = 0;
2091 m = calloc(1, sizeof(m[0]) * 3);
2093 krb5_set_error_message(context, ENOMEM,
2094 N_("malloc: out of memory", ""));
2098 strlcpy(buf, default_moduli_rfc3526_MODP_group14, sizeof(buf));
2099 ret = _krb5_parse_moduli_line(context, "builtin", 1, buf, &m[0]);
2101 _krb5_free_moduli(m);
2106 strlcpy(buf, default_moduli_RFC2412_MODP_group2, sizeof(buf));
2107 ret = _krb5_parse_moduli_line(context, "builtin", 1, buf, &m[1]);
2109 _krb5_free_moduli(m);
2118 f = fopen(file, "r");
2125 while(fgets(buf, sizeof(buf), f) != NULL) {
2126 struct krb5_dh_moduli *element;
2128 buf[strcspn(buf, "\n")] = '\0';
2131 m2 = realloc(m, (n + 2) * sizeof(m[0]));
2133 _krb5_free_moduli(m);
2134 krb5_set_error_message(context, ENOMEM,
2135 N_("malloc: out of memory", ""));
2142 ret = _krb5_parse_moduli_line(context, file, lineno, buf, &element);
2144 _krb5_free_moduli(m);
2147 if (element == NULL)
2159 _krb5_dh_group_ok(krb5_context context, unsigned long bits,
2160 heim_integer *p, heim_integer *g, heim_integer *q,
2161 struct krb5_dh_moduli **moduli,
2169 for (i = 0; moduli[i] != NULL; i++) {
2170 if (der_heim_integer_cmp(&moduli[i]->g, g) == 0 &&
2171 der_heim_integer_cmp(&moduli[i]->p, p) == 0 &&
2172 (q == NULL || der_heim_integer_cmp(&moduli[i]->q, q) == 0))
2174 if (bits && bits > moduli[i]->bits) {
2175 krb5_set_error_message(context,
2176 KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED,
2177 N_("PKINIT: DH group parameter %s "
2178 "no accepted, not enough bits "
2181 return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
2184 *name = strdup(moduli[i]->name);
2188 krb5_set_error_message(context,
2189 KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED,
2190 N_("PKINIT: DH group parameter no ok", ""));
2191 return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
2195 void KRB5_LIB_FUNCTION
2196 _krb5_get_init_creds_opt_free_pkinit(krb5_get_init_creds_opt *opt)
2199 krb5_pk_init_ctx ctx;
2201 if (opt->opt_private == NULL || opt->opt_private->pk_init_ctx == NULL)
2203 ctx = opt->opt_private->pk_init_ctx;
2204 switch (ctx->keyex) {
2212 EC_KEY_free(ctx->u.eckey);
2217 hx509_verify_destroy_ctx(ctx->id->verify_ctx);
2218 hx509_certs_free(&ctx->id->certs);
2219 hx509_cert_free(ctx->id->cert);
2220 hx509_certs_free(&ctx->id->anchors);
2221 hx509_certs_free(&ctx->id->certpool);
2222 hx509_context_free(&ctx->id->hx509ctx);
2224 if (ctx->clientDHNonce) {
2225 krb5_free_data(NULL, ctx->clientDHNonce);
2226 ctx->clientDHNonce = NULL;
2229 _krb5_free_moduli(ctx->m);
2233 free(opt->opt_private->pk_init_ctx);
2234 opt->opt_private->pk_init_ctx = NULL;
2238 krb5_error_code KRB5_LIB_FUNCTION
2239 krb5_get_init_creds_opt_set_pkinit(krb5_context context,
2240 krb5_get_init_creds_opt *opt,
2241 krb5_principal principal,
2242 const char *user_id,
2243 const char *x509_anchors,
2244 char * const * pool,
2245 char * const * pki_revoke,
2247 krb5_prompter_fct prompter,
2248 void *prompter_data,
2252 krb5_error_code ret;
2253 char *anchors = NULL;
2255 if (opt->opt_private == NULL) {
2256 krb5_set_error_message(context, EINVAL,
2257 N_("PKINIT: on non extendable opt", ""));
2261 opt->opt_private->pk_init_ctx =
2262 calloc(1, sizeof(*opt->opt_private->pk_init_ctx));
2263 if (opt->opt_private->pk_init_ctx == NULL) {
2264 krb5_set_error_message(context, ENOMEM,
2265 N_("malloc: out of memory", ""));
2268 opt->opt_private->pk_init_ctx->require_binding = 0;
2269 opt->opt_private->pk_init_ctx->require_eku = 1;
2270 opt->opt_private->pk_init_ctx->require_krbtgt_otherName = 1;
2271 opt->opt_private->pk_init_ctx->peer = NULL;
2273 /* XXX implement krb5_appdefault_strings */
2275 pool = krb5_config_get_strings(context, NULL,
2280 if (pki_revoke == NULL)
2281 pki_revoke = krb5_config_get_strings(context, NULL,
2286 if (x509_anchors == NULL) {
2287 krb5_appdefault_string(context, "kinit",
2288 krb5_principal_get_realm(context, principal),
2289 "pkinit_anchors", NULL, &anchors);
2290 x509_anchors = anchors;
2293 ret = _krb5_pk_load_id(context,
2294 &opt->opt_private->pk_init_ctx->id,
2304 free(opt->opt_private->pk_init_ctx);
2305 opt->opt_private->pk_init_ctx = NULL;
2309 if (opt->opt_private->pk_init_ctx->id->certs) {
2310 hx509_query *q = NULL;
2311 hx509_cert cert = NULL;
2312 hx509_context hx509ctx = opt->opt_private->pk_init_ctx->id->hx509ctx;
2314 ret = hx509_query_alloc(hx509ctx, &q);
2316 pk_copy_error(context, hx509ctx, ret,
2317 "Allocate query to find signing certificate");
2321 hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
2322 hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE);
2324 ret = find_cert(context, opt->opt_private->pk_init_ctx->id, q, &cert);
2325 hx509_query_free(hx509ctx, q);
2329 opt->opt_private->pk_init_ctx->id->cert = cert;
2331 opt->opt_private->pk_init_ctx->id->cert = NULL;
2333 if ((flags & 2) == 0) {
2334 hx509_context hx509ctx = opt->opt_private->pk_init_ctx->id->hx509ctx;
2335 hx509_cert cert = opt->opt_private->pk_init_ctx->id->cert;
2337 opt->opt_private->pk_init_ctx->keyex = USE_DH;
2340 * If its a ECDSA certs, lets select ECDSA as the keyex algorithm.
2343 AlgorithmIdentifier alg;
2345 ret = hx509_cert_get_SPKI_AlgorithmIdentifier(hx509ctx, cert, &alg);
2347 if (der_heim_oid_cmp(&alg.algorithm, &asn1_oid_id_ecPublicKey) == 0)
2348 opt->opt_private->pk_init_ctx->keyex = USE_ECDH;
2349 free_AlgorithmIdentifier(&alg);
2354 opt->opt_private->pk_init_ctx->keyex = USE_RSA;
2356 if (opt->opt_private->pk_init_ctx->id->certs == NULL) {
2357 krb5_set_error_message(context, EINVAL,
2358 N_("No anonymous pkinit support in RSA mode", ""));
2365 krb5_set_error_message(context, EINVAL,
2366 N_("no support for PKINIT compiled in", ""));
2374 get_ms_san(hx509_context context, hx509_cert cert, char **upn)
2376 hx509_octet_string_list list;
2381 ret = hx509_cert_find_subjectAltName_otherName(context,
2383 &asn1_oid_id_pkinit_ms_san,
2388 if (list.len > 0 && list.val[0].length > 0)
2389 ret = decode_MS_UPN_SAN(list.val[0].data, list.val[0].length,
2393 hx509_free_octet_string_list(&list);
2399 find_ms_san(hx509_context context, hx509_cert cert, void *ctx)
2404 ret = get_ms_san(context, cert, &upn);
2415 * Private since it need to be redesigned using krb5_get_init_creds()
2418 krb5_error_code KRB5_LIB_FUNCTION
2419 _krb5_pk_enterprise_cert(krb5_context context,
2420 const char *user_id,
2421 krb5_const_realm realm,
2422 krb5_principal *principal)
2425 krb5_error_code ret;
2426 hx509_context hx509ctx;
2427 hx509_certs certs, result;
2434 if (user_id == NULL)
2437 ret = hx509_context_init(&hx509ctx);
2441 ret = hx509_certs_init(hx509ctx, user_id, 0, NULL, &certs);
2443 pk_copy_error(context, hx509ctx, ret,
2444 "Failed to init cert certs");
2448 ret = hx509_query_alloc(hx509ctx, &q);
2450 hx509_certs_free(&certs);
2454 hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
2455 hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE);
2456 hx509_query_match_eku(q, &asn1_oid_id_pkinit_ms_eku);
2457 hx509_query_match_cmp_func(q, find_ms_san, NULL);
2459 ret = hx509_certs_filter(hx509ctx, certs, q, &result);
2460 hx509_query_free(hx509ctx, q);
2461 hx509_certs_free(&certs);
2465 ret = hx509_get_one_cert(hx509ctx, result, &cert);
2466 hx509_certs_free(&result);
2470 ret = get_ms_san(hx509ctx, cert, &name);
2474 ret = krb5_make_principal(context, principal, realm, name, NULL);
2476 hx509_context_free(&hx509ctx);
2480 krb5_principal_set_type(context, *principal, KRB5_NT_ENTERPRISE_PRINCIPAL);
2484 krb5_set_error_message(context, EINVAL,
2485 N_("no support for PKINIT compiled in", ""));