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 RCSID("$Id: pkinit.c 22673 2008-03-10 15:00:05Z lha $");
38 struct krb5_dh_moduli {
48 #include <heim_asn1.h>
49 #include <rfc2459_asn1.h>
51 #include <pkcs8_asn1.h>
52 #include <pkcs9_asn1.h>
53 #include <pkcs12_asn1.h>
54 #include <pkinit_asn1.h>
66 struct krb5_pk_identity {
67 hx509_context hx509ctx;
68 hx509_verify_ctx verify_ctx;
72 hx509_revoke_ctx revokectx;
79 struct krb5_pk_init_ctx_data {
80 struct krb5_pk_identity *id;
82 krb5_data *clientDHNonce;
83 struct krb5_dh_moduli **m;
86 unsigned int require_binding:1;
87 unsigned int require_eku:1;
88 unsigned int require_krbtgt_otherName:1;
89 unsigned int require_hostname_match:1;
90 unsigned int trustedCertifiers:1;
94 _krb5_pk_copy_error(krb5_context context,
95 hx509_context hx509ctx,
99 __attribute__ ((format (printf, 4, 5)));
105 void KRB5_LIB_FUNCTION
106 _krb5_pk_cert_free(struct krb5_pk_cert *cert)
109 hx509_cert_free(cert->cert);
114 static krb5_error_code
115 BN_to_integer(krb5_context context, BIGNUM *bn, heim_integer *integer)
117 integer->length = BN_num_bytes(bn);
118 integer->data = malloc(integer->length);
119 if (integer->data == NULL) {
120 krb5_clear_error_string(context);
123 BN_bn2bin(bn, integer->data);
124 integer->negative = BN_is_negative(bn);
129 integer_to_BN(krb5_context context, const char *field, const heim_integer *f)
133 bn = BN_bin2bn((const unsigned char *)f->data, f->length, NULL);
135 krb5_set_error_string(context, "PKINIT: parsing BN failed %s", field);
138 BN_set_negative(bn, f->negative);
148 * Try searchin the key by to use by first looking for for PK-INIT
149 * EKU, then the Microsoft smart card EKU and last, no special EKU at all.
152 static krb5_error_code
153 find_cert(krb5_context context, struct krb5_pk_identity *id,
154 hx509_query *q, hx509_cert *cert)
156 struct certfind cf[3] = {
163 cf[0].oid = oid_id_pkekuoid();
164 cf[1].oid = oid_id_pkinit_ms_eku();
167 for (i = 0; i < sizeof(cf)/sizeof(cf[0]); i++) {
168 ret = hx509_query_match_eku(q, cf[i].oid);
170 _krb5_pk_copy_error(context, id->hx509ctx, ret,
171 "Failed setting %s OID", cf[i].type);
175 ret = hx509_certs_find(id->hx509ctx, id->certs, q, cert);
178 _krb5_pk_copy_error(context, id->hx509ctx, ret,
179 "Failed cert for finding %s OID", cf[i].type);
185 static krb5_error_code
186 create_signature(krb5_context context,
187 const heim_oid *eContentType,
189 struct krb5_pk_identity *id,
190 hx509_peer_info peer,
193 hx509_cert cert = NULL;
194 hx509_query *q = NULL;
197 ret = hx509_query_alloc(id->hx509ctx, &q);
199 _krb5_pk_copy_error(context, id->hx509ctx, ret,
200 "Allocate query to find signing certificate");
204 hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
205 hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE);
207 ret = find_cert(context, id, q, &cert);
208 hx509_query_free(id->hx509ctx, q);
212 ret = hx509_cms_create_signed_1(id->hx509ctx,
223 hx509_cert_free(cert);
225 _krb5_pk_copy_error(context, id->hx509ctx, ret,
226 "Create CMS signedData");
234 cert2epi(hx509_context context, void *ctx, hx509_cert c)
236 ExternalPrincipalIdentifiers *ids = ctx;
237 ExternalPrincipalIdentifier id;
238 hx509_name subject = NULL;
242 memset(&id, 0, sizeof(id));
244 ret = hx509_cert_get_subject(c, &subject);
248 if (hx509_name_is_null_p(subject) != 0) {
250 id.subjectName = calloc(1, sizeof(*id.subjectName));
251 if (id.subjectName == NULL) {
252 hx509_name_free(&subject);
253 free_ExternalPrincipalIdentifier(&id);
257 ret = hx509_name_binary(subject, id.subjectName);
259 hx509_name_free(&subject);
260 free_ExternalPrincipalIdentifier(&id);
264 hx509_name_free(&subject);
267 id.issuerAndSerialNumber = calloc(1, sizeof(*id.issuerAndSerialNumber));
268 if (id.issuerAndSerialNumber == NULL) {
269 free_ExternalPrincipalIdentifier(&id);
274 IssuerAndSerialNumber iasn;
278 memset(&iasn, 0, sizeof(iasn));
280 ret = hx509_cert_get_issuer(c, &issuer);
282 free_ExternalPrincipalIdentifier(&id);
286 ret = hx509_name_to_Name(issuer, &iasn.issuer);
287 hx509_name_free(&issuer);
289 free_ExternalPrincipalIdentifier(&id);
293 ret = hx509_cert_get_serialnumber(c, &iasn.serialNumber);
295 free_IssuerAndSerialNumber(&iasn);
296 free_ExternalPrincipalIdentifier(&id);
300 ASN1_MALLOC_ENCODE(IssuerAndSerialNumber,
301 id.issuerAndSerialNumber->data,
302 id.issuerAndSerialNumber->length,
304 free_IssuerAndSerialNumber(&iasn);
307 if (id.issuerAndSerialNumber->length != size)
311 id.subjectKeyIdentifier = NULL;
313 p = realloc(ids->val, sizeof(ids->val[0]) * (ids->len + 1));
315 free_ExternalPrincipalIdentifier(&id);
320 ids->val[ids->len] = id;
326 static krb5_error_code
327 build_edi(krb5_context context,
328 hx509_context hx509ctx,
330 ExternalPrincipalIdentifiers *ids)
332 return hx509_certs_iter(hx509ctx, certs, cert2epi, ids);
335 static krb5_error_code
336 build_auth_pack(krb5_context context,
338 krb5_pk_init_ctx ctx,
340 const KDC_REQ_BODY *body,
343 size_t buf_size, len;
350 krb5_clear_error_string(context);
352 memset(&checksum, 0, sizeof(checksum));
354 krb5_us_timeofday(context, &sec, &usec);
355 a->pkAuthenticator.ctime = sec;
356 a->pkAuthenticator.nonce = nonce;
358 ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, body, &len, ret);
362 krb5_abortx(context, "internal error in ASN.1 encoder");
364 ret = krb5_create_checksum(context,
375 ALLOC(a->pkAuthenticator.paChecksum, 1);
376 if (a->pkAuthenticator.paChecksum == NULL) {
377 krb5_set_error_string(context, "malloc: out of memory");
381 ret = krb5_data_copy(a->pkAuthenticator.paChecksum,
382 checksum.checksum.data, checksum.checksum.length);
383 free_Checksum(&checksum);
389 heim_integer dh_pub_key;
393 if (1 /* support_cached_dh */) {
394 ALLOC(a->clientDHNonce, 1);
395 if (a->clientDHNonce == NULL) {
396 krb5_clear_error_string(context);
399 ret = krb5_data_alloc(a->clientDHNonce, 40);
400 if (a->clientDHNonce == NULL) {
401 krb5_clear_error_string(context);
404 memset(a->clientDHNonce->data, 0, a->clientDHNonce->length);
405 ret = krb5_copy_data(context, a->clientDHNonce,
406 &ctx->clientDHNonce);
411 ALLOC(a->clientPublicValue, 1);
412 if (a->clientPublicValue == NULL)
414 ret = der_copy_oid(oid_id_dhpublicnumber(),
415 &a->clientPublicValue->algorithm.algorithm);
419 memset(&dp, 0, sizeof(dp));
421 ret = BN_to_integer(context, dh->p, &dp.p);
423 free_DomainParameters(&dp);
426 ret = BN_to_integer(context, dh->g, &dp.g);
428 free_DomainParameters(&dp);
431 ret = BN_to_integer(context, dh->q, &dp.q);
433 free_DomainParameters(&dp);
437 dp.validationParms = NULL;
439 a->clientPublicValue->algorithm.parameters =
440 malloc(sizeof(*a->clientPublicValue->algorithm.parameters));
441 if (a->clientPublicValue->algorithm.parameters == NULL) {
442 free_DomainParameters(&dp);
446 ASN1_MALLOC_ENCODE(DomainParameters,
447 a->clientPublicValue->algorithm.parameters->data,
448 a->clientPublicValue->algorithm.parameters->length,
450 free_DomainParameters(&dp);
453 if (size != a->clientPublicValue->algorithm.parameters->length)
454 krb5_abortx(context, "Internal ASN1 encoder error");
456 ret = BN_to_integer(context, dh->pub_key, &dh_pub_key);
460 ASN1_MALLOC_ENCODE(DHPublicKey, dhbuf.data, dhbuf.length,
461 &dh_pub_key, &size, ret);
462 der_free_heim_integer(&dh_pub_key);
465 if (size != dhbuf.length)
466 krb5_abortx(context, "asn1 internal error");
468 a->clientPublicValue->subjectPublicKey.length = dhbuf.length * 8;
469 a->clientPublicValue->subjectPublicKey.data = dhbuf.data;
473 a->supportedCMSTypes = calloc(1, sizeof(*a->supportedCMSTypes));
474 if (a->supportedCMSTypes == NULL)
477 ret = hx509_crypto_available(ctx->id->hx509ctx, HX509_SELECT_ALL, NULL,
478 &a->supportedCMSTypes->val,
479 &a->supportedCMSTypes->len);
487 krb5_error_code KRB5_LIB_FUNCTION
488 _krb5_pk_mk_ContentInfo(krb5_context context,
489 const krb5_data *buf,
491 struct ContentInfo *content_info)
495 ret = der_copy_oid(oid, &content_info->contentType);
498 ALLOC(content_info->content, 1);
499 if (content_info->content == NULL)
501 content_info->content->data = malloc(buf->length);
502 if (content_info->content->data == NULL)
504 memcpy(content_info->content->data, buf->data, buf->length);
505 content_info->content->length = buf->length;
509 static krb5_error_code
510 pk_mk_padata(krb5_context context,
511 krb5_pk_init_ctx ctx,
512 const KDC_REQ_BODY *req_body,
516 struct ContentInfo content_info;
520 krb5_data buf, sd_buf;
523 krb5_data_zero(&buf);
524 krb5_data_zero(&sd_buf);
525 memset(&content_info, 0, sizeof(content_info));
527 if (ctx->type == COMPAT_WIN2K) {
532 memset(&ap, 0, sizeof(ap));
534 /* fill in PKAuthenticator */
535 ret = copy_PrincipalName(req_body->sname, &ap.pkAuthenticator.kdcName);
537 free_AuthPack_Win2k(&ap);
538 krb5_clear_error_string(context);
541 ret = copy_Realm(&req_body->realm, &ap.pkAuthenticator.kdcRealm);
543 free_AuthPack_Win2k(&ap);
544 krb5_clear_error_string(context);
548 krb5_us_timeofday(context, &sec, &usec);
549 ap.pkAuthenticator.ctime = sec;
550 ap.pkAuthenticator.cusec = usec;
551 ap.pkAuthenticator.nonce = nonce;
553 ASN1_MALLOC_ENCODE(AuthPack_Win2k, buf.data, buf.length,
555 free_AuthPack_Win2k(&ap);
557 krb5_set_error_string(context, "AuthPack_Win2k: %d", ret);
560 if (buf.length != size)
561 krb5_abortx(context, "internal ASN1 encoder error");
563 oid = oid_id_pkcs7_data();
564 } else if (ctx->type == COMPAT_IETF) {
567 memset(&ap, 0, sizeof(ap));
569 ret = build_auth_pack(context, nonce, ctx, ctx->dh, req_body, &ap);
575 ASN1_MALLOC_ENCODE(AuthPack, buf.data, buf.length, &ap, &size, ret);
578 krb5_set_error_string(context, "AuthPack: %d", ret);
581 if (buf.length != size)
582 krb5_abortx(context, "internal ASN1 encoder error");
584 oid = oid_id_pkauthdata();
586 krb5_abortx(context, "internal pkinit error");
588 ret = create_signature(context, oid, &buf, ctx->id,
590 krb5_data_free(&buf);
594 ret = hx509_cms_wrap_ContentInfo(oid_id_pkcs7_signedData(), &sd_buf, &buf);
595 krb5_data_free(&sd_buf);
597 krb5_set_error_string(context,
598 "ContentInfo wrapping of signedData failed");
602 if (ctx->type == COMPAT_WIN2K) {
603 PA_PK_AS_REQ_Win2k winreq;
605 pa_type = KRB5_PADATA_PK_AS_REQ_WIN;
607 memset(&winreq, 0, sizeof(winreq));
609 winreq.signed_auth_pack = buf;
611 ASN1_MALLOC_ENCODE(PA_PK_AS_REQ_Win2k, buf.data, buf.length,
612 &winreq, &size, ret);
613 free_PA_PK_AS_REQ_Win2k(&winreq);
615 } else if (ctx->type == COMPAT_IETF) {
618 pa_type = KRB5_PADATA_PK_AS_REQ;
620 memset(&req, 0, sizeof(req));
621 req.signedAuthPack = buf;
623 if (ctx->trustedCertifiers) {
625 req.trustedCertifiers = calloc(1, sizeof(*req.trustedCertifiers));
626 if (req.trustedCertifiers == NULL) {
627 krb5_set_error_string(context, "malloc: out of memory");
628 free_PA_PK_AS_REQ(&req);
631 ret = build_edi(context, ctx->id->hx509ctx,
632 ctx->id->anchors, req.trustedCertifiers);
634 krb5_set_error_string(context, "pk-init: failed to build trustedCertifiers");
635 free_PA_PK_AS_REQ(&req);
641 ASN1_MALLOC_ENCODE(PA_PK_AS_REQ, buf.data, buf.length,
644 free_PA_PK_AS_REQ(&req);
647 krb5_abortx(context, "internal pkinit error");
649 krb5_set_error_string(context, "PA-PK-AS-REQ %d", ret);
652 if (buf.length != size)
653 krb5_abortx(context, "Internal ASN1 encoder error");
655 ret = krb5_padata_add(context, md, pa_type, buf.data, buf.length);
659 if (ret == 0 && ctx->type == COMPAT_WIN2K)
660 krb5_padata_add(context, md, KRB5_PADATA_PK_AS_09_BINDING, NULL, 0);
663 free_ContentInfo(&content_info);
669 krb5_error_code KRB5_LIB_FUNCTION
670 _krb5_pk_mk_padata(krb5_context context,
672 const KDC_REQ_BODY *req_body,
676 krb5_pk_init_ctx ctx = c;
679 win2k_compat = krb5_config_get_bool_default(context, NULL,
687 ctx->require_binding =
688 krb5_config_get_bool_default(context, NULL,
692 "pkinit_win2k_require_binding",
694 ctx->type = COMPAT_WIN2K;
696 ctx->type = COMPAT_IETF;
699 krb5_config_get_bool_default(context, NULL,
703 "pkinit_require_eku",
705 ctx->require_krbtgt_otherName =
706 krb5_config_get_bool_default(context, NULL,
710 "pkinit_require_krbtgt_otherName",
713 ctx->require_hostname_match =
714 krb5_config_get_bool_default(context, NULL,
718 "pkinit_require_hostname_match",
721 ctx->trustedCertifiers =
722 krb5_config_get_bool_default(context, NULL,
726 "pkinit_trustedCertifiers",
729 return pk_mk_padata(context, ctx, req_body, nonce, md);
732 krb5_error_code KRB5_LIB_FUNCTION
733 _krb5_pk_verify_sign(krb5_context context,
736 struct krb5_pk_identity *id,
737 heim_oid *contentType,
739 struct krb5_pk_cert **signer)
741 hx509_certs signer_certs;
746 ret = hx509_cms_verify_signed(id->hx509ctx,
756 _krb5_pk_copy_error(context, id->hx509ctx, ret,
757 "CMS verify signed failed");
761 *signer = calloc(1, sizeof(**signer));
762 if (*signer == NULL) {
763 krb5_clear_error_string(context);
768 ret = hx509_get_one_cert(id->hx509ctx, signer_certs, &(*signer)->cert);
770 _krb5_pk_copy_error(context, id->hx509ctx, ret,
771 "Failed to get on of the signer certs");
776 hx509_certs_free(&signer_certs);
779 hx509_cert_free((*signer)->cert);
788 static krb5_error_code
789 get_reply_key_win(krb5_context context,
790 const krb5_data *content,
794 ReplyKeyPack_Win2k key_pack;
798 ret = decode_ReplyKeyPack_Win2k(content->data,
803 krb5_set_error_string(context, "PKINIT decoding reply key failed");
804 free_ReplyKeyPack_Win2k(&key_pack);
808 if (key_pack.nonce != nonce) {
809 krb5_set_error_string(context, "PKINIT enckey nonce is wrong");
810 free_ReplyKeyPack_Win2k(&key_pack);
811 return KRB5KRB_AP_ERR_MODIFIED;
814 *key = malloc (sizeof (**key));
816 krb5_set_error_string(context, "PKINIT failed allocating reply key");
817 free_ReplyKeyPack_Win2k(&key_pack);
818 krb5_set_error_string(context, "malloc: out of memory");
822 ret = copy_EncryptionKey(&key_pack.replyKey, *key);
823 free_ReplyKeyPack_Win2k(&key_pack);
825 krb5_set_error_string(context, "PKINIT failed copying reply key");
833 static krb5_error_code
834 get_reply_key(krb5_context context,
835 const krb5_data *content,
836 const krb5_data *req_buffer,
839 ReplyKeyPack key_pack;
843 ret = decode_ReplyKeyPack(content->data,
848 krb5_set_error_string(context, "PKINIT decoding reply key failed");
849 free_ReplyKeyPack(&key_pack);
857 * XXX Verify kp.replyKey is a allowed enctype in the
861 ret = krb5_crypto_init(context, &key_pack.replyKey, 0, &crypto);
863 free_ReplyKeyPack(&key_pack);
867 ret = krb5_verify_checksum(context, crypto, 6,
868 req_buffer->data, req_buffer->length,
869 &key_pack.asChecksum);
870 krb5_crypto_destroy(context, crypto);
872 free_ReplyKeyPack(&key_pack);
877 *key = malloc (sizeof (**key));
879 krb5_set_error_string(context, "PKINIT failed allocating reply key");
880 free_ReplyKeyPack(&key_pack);
881 krb5_set_error_string(context, "malloc: out of memory");
885 ret = copy_EncryptionKey(&key_pack.replyKey, *key);
886 free_ReplyKeyPack(&key_pack);
888 krb5_set_error_string(context, "PKINIT failed copying reply key");
897 static krb5_error_code
898 pk_verify_host(krb5_context context,
900 const krb5_krbhst_info *hi,
901 struct krb5_pk_init_ctx_data *ctx,
902 struct krb5_pk_cert *host)
904 krb5_error_code ret = 0;
906 if (ctx->require_eku) {
907 ret = hx509_cert_check_eku(ctx->id->hx509ctx, host->cert,
908 oid_id_pkkdcekuoid(), 0);
910 krb5_set_error_string(context, "No PK-INIT KDC EKU in kdc certificate");
914 if (ctx->require_krbtgt_otherName) {
915 hx509_octet_string_list list;
918 ret = hx509_cert_find_subjectAltName_otherName(ctx->id->hx509ctx,
923 krb5_set_error_string(context, "Failed to find the PK-INIT "
924 "subjectAltName in the KDC certificate");
929 for (i = 0; i < list.len; i++) {
932 ret = decode_KRB5PrincipalName(list.val[i].data,
937 krb5_set_error_string(context, "Failed to decode the PK-INIT "
938 "subjectAltName in the KDC certificate");
943 if (r.principalName.name_string.len != 2 ||
944 strcmp(r.principalName.name_string.val[0], KRB5_TGS_NAME) != 0 ||
945 strcmp(r.principalName.name_string.val[1], realm) != 0 ||
946 strcmp(r.realm, realm) != 0)
948 krb5_set_error_string(context, "KDC have wrong realm name in "
950 ret = KRB5_KDC_ERR_INVALID_CERTIFICATE;
953 free_KRB5PrincipalName(&r);
957 hx509_free_octet_string_list(&list);
963 ret = hx509_verify_hostname(ctx->id->hx509ctx, host->cert,
964 ctx->require_hostname_match,
967 hi->ai->ai_addr, hi->ai->ai_addrlen);
970 krb5_set_error_string(context, "Address mismatch in "
971 "the KDC certificate");
976 static krb5_error_code
977 pk_rd_pa_reply_enckey(krb5_context context,
979 const heim_octet_string *indata,
980 const heim_oid *dataType,
982 krb5_pk_init_ctx ctx,
984 const krb5_krbhst_info *hi,
986 const krb5_data *req_buffer,
991 struct krb5_pk_cert *host = NULL;
993 heim_oid contentType = { 0, NULL };
995 if (der_heim_oid_cmp(oid_id_pkcs7_envelopedData(), dataType)) {
996 krb5_set_error_string(context, "PKINIT: Invalid content type");
1000 ret = hx509_cms_unenvelope(ctx->id->hx509ctx,
1002 HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT,
1009 _krb5_pk_copy_error(context, ctx->id->hx509ctx, ret,
1010 "Failed to unenvelope CMS data in PK-INIT reply");
1013 der_free_oid(&contentType);
1015 #if 0 /* windows LH with interesting CMS packets, leaks memory */
1017 size_t ph = 1 + der_length_len (length);
1018 unsigned char *ptr = malloc(length + ph);
1021 memcpy(ptr + ph, p, length);
1023 ret = der_put_length_and_tag (ptr + ph - 1, ph, length,
1024 ASN1_C_UNIV, CONS, UT_Sequence, &l);
1033 /* win2k uses ContentInfo */
1034 if (type == COMPAT_WIN2K) {
1036 heim_octet_string out;
1038 ret = hx509_cms_unwrap_ContentInfo(&content, &type, &out, NULL);
1039 if (der_heim_oid_cmp(&type, oid_id_pkcs7_signedData())) {
1040 ret = EINVAL; /* XXX */
1041 krb5_set_error_string(context, "PKINIT: Invalid content type");
1042 der_free_oid(&type);
1043 der_free_octet_string(&out);
1046 der_free_oid(&type);
1047 krb5_data_free(&content);
1048 ret = krb5_data_copy(&content, out.data, out.length);
1049 der_free_octet_string(&out);
1051 krb5_set_error_string(context, "PKINIT: out of memory");
1056 ret = _krb5_pk_verify_sign(context,
1066 /* make sure that it is the kdc's certificate */
1067 ret = pk_verify_host(context, realm, hi, ctx, host);
1073 if (type == COMPAT_WIN2K) {
1074 if (der_heim_oid_cmp(&contentType, oid_id_pkcs7_data()) != 0) {
1075 krb5_set_error_string(context, "PKINIT: reply key, wrong oid");
1076 ret = KRB5KRB_AP_ERR_MSG_TYPE;
1080 if (der_heim_oid_cmp(&contentType, oid_id_pkrkeydata()) != 0) {
1081 krb5_set_error_string(context, "PKINIT: reply key, wrong oid");
1082 ret = KRB5KRB_AP_ERR_MSG_TYPE;
1090 ret = get_reply_key(context, &content, req_buffer, key);
1091 if (ret != 0 && ctx->require_binding == 0)
1092 ret = get_reply_key_win(context, &content, nonce, key);
1095 ret = get_reply_key(context, &content, req_buffer, key);
1101 /* XXX compare given etype with key->etype */
1105 _krb5_pk_cert_free(host);
1106 der_free_oid(&contentType);
1107 krb5_data_free(&content);
1112 static krb5_error_code
1113 pk_rd_pa_reply_dh(krb5_context context,
1114 const heim_octet_string *indata,
1115 const heim_oid *dataType,
1117 krb5_pk_init_ctx ctx,
1119 const krb5_krbhst_info *hi,
1124 krb5_keyblock **key)
1126 unsigned char *p, *dh_gen_key = NULL;
1127 struct krb5_pk_cert *host = NULL;
1128 BIGNUM *kdc_dh_pubkey = NULL;
1129 KDCDHKeyInfo kdc_dh_info;
1130 heim_oid contentType = { 0, NULL };
1132 krb5_error_code ret;
1136 krb5_data_zero(&content);
1137 memset(&kdc_dh_info, 0, sizeof(kdc_dh_info));
1139 if (der_heim_oid_cmp(oid_id_pkcs7_signedData(), dataType)) {
1140 krb5_set_error_string(context, "PKINIT: Invalid content type");
1144 ret = _krb5_pk_verify_sign(context,
1154 /* make sure that it is the kdc's certificate */
1155 ret = pk_verify_host(context, realm, hi, ctx, host);
1159 if (der_heim_oid_cmp(&contentType, oid_id_pkdhkeydata())) {
1160 krb5_set_error_string(context, "pkinit - dh reply contains wrong oid");
1161 ret = KRB5KRB_AP_ERR_MSG_TYPE;
1165 ret = decode_KDCDHKeyInfo(content.data,
1171 krb5_set_error_string(context, "pkinit - "
1172 "failed to decode KDC DH Key Info");
1176 if (kdc_dh_info.nonce != nonce) {
1177 krb5_set_error_string(context, "PKINIT: DH nonce is wrong");
1178 ret = KRB5KRB_AP_ERR_MODIFIED;
1182 if (kdc_dh_info.dhKeyExpiration) {
1184 krb5_set_error_string(context, "pkinit; got key expiration "
1185 "without server nonce");
1186 ret = KRB5KRB_ERR_GENERIC;
1190 krb5_set_error_string(context, "pkinit; got DH reuse but no "
1192 ret = KRB5KRB_ERR_GENERIC;
1197 krb5_set_error_string(context, "pkinit: got server nonce "
1198 "without key expiration");
1199 ret = KRB5KRB_ERR_GENERIC;
1206 p = kdc_dh_info.subjectPublicKey.data;
1207 size = (kdc_dh_info.subjectPublicKey.length + 7) / 8;
1211 ret = decode_DHPublicKey(p, size, &k, NULL);
1213 krb5_set_error_string(context, "pkinit: can't decode "
1214 "without key expiration");
1218 kdc_dh_pubkey = integer_to_BN(context, "DHPublicKey", &k);
1219 free_DHPublicKey(&k);
1220 if (kdc_dh_pubkey == NULL) {
1221 ret = KRB5KRB_ERR_GENERIC;
1226 dh_gen_keylen = DH_size(ctx->dh);
1227 size = BN_num_bytes(ctx->dh->p);
1228 if (size < dh_gen_keylen)
1229 size = dh_gen_keylen;
1231 dh_gen_key = malloc(size);
1232 if (dh_gen_key == NULL) {
1233 krb5_set_error_string(context, "malloc: out of memory");
1237 memset(dh_gen_key, 0, size - dh_gen_keylen);
1239 dh_gen_keylen = DH_compute_key(dh_gen_key + (size - dh_gen_keylen),
1240 kdc_dh_pubkey, ctx->dh);
1241 if (dh_gen_keylen == -1) {
1242 krb5_set_error_string(context,
1243 "PKINIT: Can't compute Diffie-Hellman key");
1244 ret = KRB5KRB_ERR_GENERIC;
1248 *key = malloc (sizeof (**key));
1250 krb5_set_error_string(context, "malloc: out of memory");
1255 ret = _krb5_pk_octetstring2key(context,
1257 dh_gen_key, dh_gen_keylen,
1261 krb5_set_error_string(context,
1262 "PKINIT: can't create key from DH key");
1270 BN_free(kdc_dh_pubkey);
1272 memset(dh_gen_key, 0, DH_size(ctx->dh));
1276 _krb5_pk_cert_free(host);
1278 krb5_data_free(&content);
1279 der_free_oid(&contentType);
1280 free_KDCDHKeyInfo(&kdc_dh_info);
1285 krb5_error_code KRB5_LIB_FUNCTION
1286 _krb5_pk_rd_pa_reply(krb5_context context,
1290 const krb5_krbhst_info *hi,
1292 const krb5_data *req_buffer,
1294 krb5_keyblock **key)
1296 krb5_pk_init_ctx ctx = c;
1297 krb5_error_code ret;
1300 /* Check for IETF PK-INIT first */
1301 if (ctx->type == COMPAT_IETF) {
1303 heim_octet_string os, data;
1306 if (pa->padata_type != KRB5_PADATA_PK_AS_REP) {
1307 krb5_set_error_string(context, "PKINIT: wrong padata recv");
1311 ret = decode_PA_PK_AS_REP(pa->padata_value.data,
1312 pa->padata_value.length,
1316 krb5_set_error_string(context, "Failed to decode pkinit AS rep");
1320 switch (rep.element) {
1321 case choice_PA_PK_AS_REP_dhInfo:
1322 os = rep.u.dhInfo.dhSignedData;
1324 case choice_PA_PK_AS_REP_encKeyPack:
1325 os = rep.u.encKeyPack;
1328 free_PA_PK_AS_REP(&rep);
1329 krb5_set_error_string(context, "PKINIT: -27 reply "
1330 "invalid content type");
1334 ret = hx509_cms_unwrap_ContentInfo(&os, &oid, &data, NULL);
1336 free_PA_PK_AS_REP(&rep);
1337 krb5_set_error_string(context, "PKINIT: failed to unwrap CI");
1341 switch (rep.element) {
1342 case choice_PA_PK_AS_REP_dhInfo:
1343 ret = pk_rd_pa_reply_dh(context, &data, &oid, realm, ctx, etype, hi,
1345 rep.u.dhInfo.serverDHNonce,
1348 case choice_PA_PK_AS_REP_encKeyPack:
1349 ret = pk_rd_pa_reply_enckey(context, COMPAT_IETF, &data, &oid, realm,
1350 ctx, etype, hi, nonce, req_buffer, pa, key);
1353 krb5_abortx(context, "pk-init as-rep case not possible to happen");
1355 der_free_octet_string(&data);
1357 free_PA_PK_AS_REP(&rep);
1359 } else if (ctx->type == COMPAT_WIN2K) {
1360 PA_PK_AS_REP_Win2k w2krep;
1362 /* Check for Windows encoding of the AS-REP pa data */
1364 #if 0 /* should this be ? */
1365 if (pa->padata_type != KRB5_PADATA_PK_AS_REP) {
1366 krb5_set_error_string(context, "PKINIT: wrong padata recv");
1371 memset(&w2krep, 0, sizeof(w2krep));
1373 ret = decode_PA_PK_AS_REP_Win2k(pa->padata_value.data,
1374 pa->padata_value.length,
1378 krb5_set_error_string(context, "PKINIT: Failed decoding windows "
1379 "pkinit reply %d", ret);
1383 krb5_clear_error_string(context);
1385 switch (w2krep.element) {
1386 case choice_PA_PK_AS_REP_Win2k_encKeyPack: {
1387 heim_octet_string data;
1390 ret = hx509_cms_unwrap_ContentInfo(&w2krep.u.encKeyPack,
1392 free_PA_PK_AS_REP_Win2k(&w2krep);
1394 krb5_set_error_string(context, "PKINIT: failed to unwrap CI");
1398 ret = pk_rd_pa_reply_enckey(context, COMPAT_WIN2K, &data, &oid, realm,
1399 ctx, etype, hi, nonce, req_buffer, pa, key);
1400 der_free_octet_string(&data);
1406 free_PA_PK_AS_REP_Win2k(&w2krep);
1407 krb5_set_error_string(context, "PKINIT: win2k reply invalid "
1414 krb5_set_error_string(context, "PKINIT: unknown reply type");
1422 krb5_context context;
1423 krb5_prompter_fct prompter;
1424 void *prompter_data;
1428 hx_pass_prompter(void *data, const hx509_prompt *prompter)
1430 krb5_error_code ret;
1432 krb5_data password_data;
1433 struct prompter *p = data;
1435 password_data.data = prompter->reply.data;
1436 password_data.length = prompter->reply.length;
1438 prompt.prompt = prompter->prompt;
1439 prompt.hidden = hx509_prompt_hidden(prompter->type);
1440 prompt.reply = &password_data;
1442 switch (prompter->type) {
1443 case HX509_PROMPT_TYPE_INFO:
1444 prompt.type = KRB5_PROMPT_TYPE_INFO;
1446 case HX509_PROMPT_TYPE_PASSWORD:
1447 case HX509_PROMPT_TYPE_QUESTION:
1449 prompt.type = KRB5_PROMPT_TYPE_PASSWORD;
1453 ret = (*p->prompter)(p->context, p->prompter_data, NULL, NULL, 1, &prompt);
1455 memset (prompter->reply.data, 0, prompter->reply.length);
1462 void KRB5_LIB_FUNCTION
1463 _krb5_pk_allow_proxy_certificate(struct krb5_pk_identity *id,
1466 hx509_verify_set_proxy_certificate(id->verify_ctx, boolean);
1470 krb5_error_code KRB5_LIB_FUNCTION
1471 _krb5_pk_load_id(krb5_context context,
1472 struct krb5_pk_identity **ret_id,
1473 const char *user_id,
1474 const char *anchor_id,
1475 char * const *chain_list,
1476 char * const *revoke_list,
1477 krb5_prompter_fct prompter,
1478 void *prompter_data,
1481 struct krb5_pk_identity *id = NULL;
1482 hx509_lock lock = NULL;
1488 if (anchor_id == NULL) {
1489 krb5_set_error_string(context, "PKINIT: No anchor given");
1490 return HEIM_PKINIT_NO_VALID_CA;
1493 if (user_id == NULL) {
1494 krb5_set_error_string(context,
1495 "PKINIT: No user certificate given");
1496 return HEIM_PKINIT_NO_PRIVATE_KEY;
1501 id = calloc(1, sizeof(*id));
1503 krb5_set_error_string(context, "malloc: out of memory");
1507 ret = hx509_context_init(&id->hx509ctx);
1511 ret = hx509_lock_init(id->hx509ctx, &lock);
1512 if (password && password[0])
1513 hx509_lock_add_password(lock, password);
1516 p.context = context;
1517 p.prompter = prompter;
1518 p.prompter_data = prompter_data;
1520 ret = hx509_lock_set_prompter(lock, hx_pass_prompter, &p);
1525 ret = hx509_certs_init(id->hx509ctx, user_id, 0, lock, &id->certs);
1527 _krb5_pk_copy_error(context, id->hx509ctx, ret,
1528 "Failed to init cert certs");
1532 ret = hx509_certs_init(id->hx509ctx, anchor_id, 0, NULL, &id->anchors);
1534 _krb5_pk_copy_error(context, id->hx509ctx, ret,
1535 "Failed to init anchors");
1539 ret = hx509_certs_init(id->hx509ctx, "MEMORY:pkinit-cert-chain",
1540 0, NULL, &id->certpool);
1542 _krb5_pk_copy_error(context, id->hx509ctx, ret,
1543 "Failed to init chain");
1547 while (chain_list && *chain_list) {
1548 ret = hx509_certs_append(id->hx509ctx, id->certpool,
1551 _krb5_pk_copy_error(context, id->hx509ctx, ret,
1552 "Failed to laod chain %s",
1560 ret = hx509_revoke_init(id->hx509ctx, &id->revokectx);
1562 _krb5_pk_copy_error(context, id->hx509ctx, ret,
1563 "Failed init revoke list");
1567 while (*revoke_list) {
1568 ret = hx509_revoke_add_crl(id->hx509ctx,
1572 _krb5_pk_copy_error(context, id->hx509ctx, ret,
1573 "Failed load revoke list");
1579 hx509_context_set_missing_revoke(id->hx509ctx, 1);
1581 ret = hx509_verify_init_ctx(id->hx509ctx, &id->verify_ctx);
1583 _krb5_pk_copy_error(context, id->hx509ctx, ret,
1584 "Failed init verify context");
1588 hx509_verify_attach_anchors(id->verify_ctx, id->anchors);
1589 hx509_verify_attach_revoke(id->verify_ctx, id->revokectx);
1593 hx509_verify_destroy_ctx(id->verify_ctx);
1594 hx509_certs_free(&id->certs);
1595 hx509_certs_free(&id->anchors);
1596 hx509_certs_free(&id->certpool);
1597 hx509_revoke_free(&id->revokectx);
1598 hx509_context_free(&id->hx509ctx);
1603 hx509_lock_free(lock);
1608 static krb5_error_code
1609 select_dh_group(krb5_context context, DH *dh, unsigned long bits,
1610 struct krb5_dh_moduli **moduli)
1612 const struct krb5_dh_moduli *m;
1615 m = moduli[1]; /* XXX */
1617 m = moduli[0]; /* XXX */
1620 for (i = 0; moduli[i] != NULL; i++) {
1621 if (bits < moduli[i]->bits)
1624 if (moduli[i] == NULL) {
1625 krb5_set_error_string(context,
1626 "Did not find a DH group parameter "
1627 "matching requirement of %lu bits",
1634 dh->p = integer_to_BN(context, "p", &m->p);
1637 dh->g = integer_to_BN(context, "g", &m->g);
1640 dh->q = integer_to_BN(context, "q", &m->q);
1650 parse_integer(krb5_context context, char **p, const char *file, int lineno,
1651 const char *name, heim_integer *integer)
1655 p1 = strsep(p, " \t");
1657 krb5_set_error_string(context, "moduli file %s missing %s on line %d",
1658 file, name, lineno);
1661 ret = der_parse_hex_heim_integer(p1, integer);
1663 krb5_set_error_string(context, "moduli file %s failed parsing %s "
1665 file, name, lineno);
1673 _krb5_parse_moduli_line(krb5_context context,
1677 struct krb5_dh_moduli **m)
1679 struct krb5_dh_moduli *m1;
1685 m1 = calloc(1, sizeof(*m1));
1687 krb5_set_error_string(context, "malloc - out of memory");
1691 while (isspace((unsigned char)*p))
1697 p1 = strsep(&p, " \t");
1699 krb5_set_error_string(context, "moduli file %s missing name "
1700 "on line %d", file, lineno);
1703 m1->name = strdup(p1);
1705 krb5_set_error_string(context, "malloc - out of memeory");
1710 p1 = strsep(&p, " \t");
1712 krb5_set_error_string(context, "moduli file %s missing bits on line %d",
1717 m1->bits = atoi(p1);
1718 if (m1->bits == 0) {
1719 krb5_set_error_string(context, "moduli file %s have un-parsable "
1720 "bits on line %d", file, lineno);
1724 ret = parse_integer(context, &p, file, lineno, "p", &m1->p);
1727 ret = parse_integer(context, &p, file, lineno, "g", &m1->g);
1730 ret = parse_integer(context, &p, file, lineno, "q", &m1->q);
1739 der_free_heim_integer(&m1->p);
1740 der_free_heim_integer(&m1->g);
1741 der_free_heim_integer(&m1->q);
1747 _krb5_free_moduli(struct krb5_dh_moduli **moduli)
1750 for (i = 0; moduli[i] != NULL; i++) {
1751 free(moduli[i]->name);
1752 der_free_heim_integer(&moduli[i]->p);
1753 der_free_heim_integer(&moduli[i]->g);
1754 der_free_heim_integer(&moduli[i]->q);
1760 static const char *default_moduli_RFC2412_MODP_group2 =
1762 "RFC2412-MODP-group2 "
1766 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
1767 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
1768 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
1769 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
1770 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
1771 "FFFFFFFF" "FFFFFFFF "
1775 "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68"
1776 "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E"
1777 "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122"
1778 "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6"
1779 "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F67329C0"
1780 "FFFFFFFF" "FFFFFFFF";
1782 static const char *default_moduli_rfc3526_MODP_group14 =
1784 "rfc3526-MODP-group14 "
1788 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
1789 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
1790 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
1791 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
1792 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D"
1793 "C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"
1794 "83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"
1795 "670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"
1796 "E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"
1797 "DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
1798 "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF "
1802 "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68"
1803 "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E"
1804 "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122"
1805 "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6"
1806 "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F6722D9E"
1807 "E1003E5C" "50B1DF82" "CC6D241B" "0E2AE9CD" "348B1FD4" "7E9267AF"
1808 "C1B2AE91" "EE51D6CB" "0E3179AB" "1042A95D" "CF6A9483" "B84B4B36"
1809 "B3861AA7" "255E4C02" "78BA3604" "650C10BE" "19482F23" "171B671D"
1810 "F1CF3B96" "0C074301" "CD93C1D1" "7603D147" "DAE2AEF8" "37A62964"
1811 "EF15E5FB" "4AAC0B8C" "1CCAA4BE" "754AB572" "8AE9130C" "4C7D0288"
1812 "0AB9472D" "45565534" "7FFFFFFF" "FFFFFFFF";
1815 _krb5_parse_moduli(krb5_context context, const char *file,
1816 struct krb5_dh_moduli ***moduli)
1818 /* name bits P G Q */
1819 krb5_error_code ret;
1820 struct krb5_dh_moduli **m = NULL, **m2;
1823 int lineno = 0, n = 0;
1827 m = calloc(1, sizeof(m[0]) * 3);
1829 krb5_set_error_string(context, "malloc: out of memory");
1833 strlcpy(buf, default_moduli_rfc3526_MODP_group14, sizeof(buf));
1834 ret = _krb5_parse_moduli_line(context, "builtin", 1, buf, &m[0]);
1836 _krb5_free_moduli(m);
1841 strlcpy(buf, default_moduli_RFC2412_MODP_group2, sizeof(buf));
1842 ret = _krb5_parse_moduli_line(context, "builtin", 1, buf, &m[1]);
1844 _krb5_free_moduli(m);
1853 f = fopen(file, "r");
1859 while(fgets(buf, sizeof(buf), f) != NULL) {
1860 struct krb5_dh_moduli *element;
1862 buf[strcspn(buf, "\n")] = '\0';
1865 m2 = realloc(m, (n + 2) * sizeof(m[0]));
1867 krb5_set_error_string(context, "malloc: out of memory");
1868 _krb5_free_moduli(m);
1875 ret = _krb5_parse_moduli_line(context, file, lineno, buf, &element);
1877 _krb5_free_moduli(m);
1880 if (element == NULL)
1892 _krb5_dh_group_ok(krb5_context context, unsigned long bits,
1893 heim_integer *p, heim_integer *g, heim_integer *q,
1894 struct krb5_dh_moduli **moduli,
1902 for (i = 0; moduli[i] != NULL; i++) {
1903 if (der_heim_integer_cmp(&moduli[i]->g, g) == 0 &&
1904 der_heim_integer_cmp(&moduli[i]->p, p) == 0 &&
1905 (q == NULL || der_heim_integer_cmp(&moduli[i]->q, q) == 0))
1907 if (bits && bits > moduli[i]->bits) {
1908 krb5_set_error_string(context, "PKINIT: DH group parameter %s "
1909 "no accepted, not enough bits generated",
1911 return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
1914 *name = strdup(moduli[i]->name);
1918 krb5_set_error_string(context, "PKINIT: DH group parameter no ok");
1919 return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
1922 void KRB5_LIB_FUNCTION
1923 _krb5_get_init_creds_opt_free_pkinit(krb5_get_init_creds_opt *opt)
1926 krb5_pk_init_ctx ctx;
1928 if (opt->opt_private == NULL || opt->opt_private->pk_init_ctx == NULL)
1930 ctx = opt->opt_private->pk_init_ctx;
1935 hx509_verify_destroy_ctx(ctx->id->verify_ctx);
1936 hx509_certs_free(&ctx->id->certs);
1937 hx509_certs_free(&ctx->id->anchors);
1938 hx509_certs_free(&ctx->id->certpool);
1939 hx509_context_free(&ctx->id->hx509ctx);
1941 if (ctx->clientDHNonce) {
1942 krb5_free_data(NULL, ctx->clientDHNonce);
1943 ctx->clientDHNonce = NULL;
1946 _krb5_free_moduli(ctx->m);
1950 free(opt->opt_private->pk_init_ctx);
1951 opt->opt_private->pk_init_ctx = NULL;
1955 krb5_error_code KRB5_LIB_FUNCTION
1956 krb5_get_init_creds_opt_set_pkinit(krb5_context context,
1957 krb5_get_init_creds_opt *opt,
1958 krb5_principal principal,
1959 const char *user_id,
1960 const char *x509_anchors,
1961 char * const * pool,
1962 char * const * pki_revoke,
1964 krb5_prompter_fct prompter,
1965 void *prompter_data,
1969 krb5_error_code ret;
1970 char *anchors = NULL;
1972 if (opt->opt_private == NULL) {
1973 krb5_set_error_string(context, "PKINIT: on non extendable opt");
1977 opt->opt_private->pk_init_ctx =
1978 calloc(1, sizeof(*opt->opt_private->pk_init_ctx));
1979 if (opt->opt_private->pk_init_ctx == NULL) {
1980 krb5_set_error_string(context, "malloc: out of memory");
1983 opt->opt_private->pk_init_ctx->dh = NULL;
1984 opt->opt_private->pk_init_ctx->id = NULL;
1985 opt->opt_private->pk_init_ctx->clientDHNonce = NULL;
1986 opt->opt_private->pk_init_ctx->require_binding = 0;
1987 opt->opt_private->pk_init_ctx->require_eku = 1;
1988 opt->opt_private->pk_init_ctx->require_krbtgt_otherName = 1;
1989 opt->opt_private->pk_init_ctx->peer = NULL;
1991 /* XXX implement krb5_appdefault_strings */
1993 pool = krb5_config_get_strings(context, NULL,
1998 if (pki_revoke == NULL)
1999 pki_revoke = krb5_config_get_strings(context, NULL,
2004 if (x509_anchors == NULL) {
2005 krb5_appdefault_string(context, "kinit",
2006 krb5_principal_get_realm(context, principal),
2007 "pkinit_anchors", NULL, &anchors);
2008 x509_anchors = anchors;
2011 ret = _krb5_pk_load_id(context,
2012 &opt->opt_private->pk_init_ctx->id,
2021 free(opt->opt_private->pk_init_ctx);
2022 opt->opt_private->pk_init_ctx = NULL;
2026 if ((flags & 2) == 0) {
2027 const char *moduli_file;
2028 unsigned long dh_min_bits;
2030 moduli_file = krb5_config_get_string(context, NULL,
2036 krb5_config_get_int_default(context, NULL, 0,
2038 "pkinit_dh_min_bits",
2041 ret = _krb5_parse_moduli(context, moduli_file,
2042 &opt->opt_private->pk_init_ctx->m);
2044 _krb5_get_init_creds_opt_free_pkinit(opt);
2048 opt->opt_private->pk_init_ctx->dh = DH_new();
2049 if (opt->opt_private->pk_init_ctx->dh == NULL) {
2050 krb5_set_error_string(context, "malloc: out of memory");
2051 _krb5_get_init_creds_opt_free_pkinit(opt);
2055 ret = select_dh_group(context, opt->opt_private->pk_init_ctx->dh,
2057 opt->opt_private->pk_init_ctx->m);
2059 _krb5_get_init_creds_opt_free_pkinit(opt);
2063 if (DH_generate_key(opt->opt_private->pk_init_ctx->dh) != 1) {
2064 krb5_set_error_string(context, "pkinit: failed to generate DH key");
2065 _krb5_get_init_creds_opt_free_pkinit(opt);
2072 krb5_set_error_string(context, "no support for PKINIT compiled in");
2082 _krb5_pk_copy_error(krb5_context context,
2083 hx509_context hx509ctx,
2092 vasprintf(&f, fmt, va);
2095 krb5_clear_error_string(context);
2099 s = hx509_get_error_string(hx509ctx, hxret);
2101 krb5_clear_error_string(context);
2105 krb5_set_error_string(context, "%s: %s", f, s);