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 23450 2008-07-27 12:10:10Z lha $");
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;
64 krb5_data *clientDHNonce;
65 struct krb5_dh_moduli **m;
67 enum krb5_pk_type type;
68 unsigned int require_binding:1;
69 unsigned int require_eku:1;
70 unsigned int require_krbtgt_otherName:1;
71 unsigned int require_hostname_match:1;
72 unsigned int trustedCertifiers:1;
76 pk_copy_error(krb5_context context,
77 hx509_context hx509ctx,
81 __attribute__ ((format (printf, 4, 5)));
87 void KRB5_LIB_FUNCTION
88 _krb5_pk_cert_free(struct krb5_pk_cert *cert)
91 hx509_cert_free(cert->cert);
96 static krb5_error_code
97 BN_to_integer(krb5_context context, BIGNUM *bn, heim_integer *integer)
99 integer->length = BN_num_bytes(bn);
100 integer->data = malloc(integer->length);
101 if (integer->data == NULL) {
102 krb5_clear_error_string(context);
105 BN_bn2bin(bn, integer->data);
106 integer->negative = BN_is_negative(bn);
111 integer_to_BN(krb5_context context, const char *field, const heim_integer *f)
115 bn = BN_bin2bn((const unsigned char *)f->data, f->length, NULL);
117 krb5_set_error_message(context, ENOMEM, "PKINIT: parsing BN failed %s", field);
120 BN_set_negative(bn, f->negative);
130 * Try searchin the key by to use by first looking for for PK-INIT
131 * EKU, then the Microsoft smart card EKU and last, no special EKU at all.
134 static krb5_error_code
135 find_cert(krb5_context context, struct krb5_pk_identity *id,
136 hx509_query *q, hx509_cert *cert)
138 struct certfind cf[3] = {
145 cf[0].oid = oid_id_pkekuoid();
146 cf[1].oid = oid_id_pkinit_ms_eku();
149 for (i = 0; i < sizeof(cf)/sizeof(cf[0]); i++) {
150 ret = hx509_query_match_eku(q, cf[i].oid);
152 pk_copy_error(context, id->hx509ctx, ret,
153 "Failed setting %s OID", cf[i].type);
157 ret = hx509_certs_find(id->hx509ctx, id->certs, q, cert);
160 pk_copy_error(context, id->hx509ctx, ret,
161 "Failed cert for finding %s OID", cf[i].type);
167 static krb5_error_code
168 create_signature(krb5_context context,
169 const heim_oid *eContentType,
171 struct krb5_pk_identity *id,
172 hx509_peer_info peer,
175 hx509_cert cert = NULL;
176 hx509_query *q = NULL;
179 ret = hx509_query_alloc(id->hx509ctx, &q);
181 pk_copy_error(context, id->hx509ctx, ret,
182 "Allocate query to find signing certificate");
186 hx509_query_match_option(q, HX509_QUERY_OPTION_PRIVATE_KEY);
187 hx509_query_match_option(q, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE);
189 ret = find_cert(context, id, q, &cert);
190 hx509_query_free(id->hx509ctx, q);
194 ret = hx509_cms_create_signed_1(id->hx509ctx,
205 hx509_cert_free(cert);
207 pk_copy_error(context, id->hx509ctx, ret,
208 "Create CMS signedData");
216 cert2epi(hx509_context context, void *ctx, hx509_cert c)
218 ExternalPrincipalIdentifiers *ids = ctx;
219 ExternalPrincipalIdentifier id;
220 hx509_name subject = NULL;
224 memset(&id, 0, sizeof(id));
226 ret = hx509_cert_get_subject(c, &subject);
230 if (hx509_name_is_null_p(subject) != 0) {
232 id.subjectName = calloc(1, sizeof(*id.subjectName));
233 if (id.subjectName == NULL) {
234 hx509_name_free(&subject);
235 free_ExternalPrincipalIdentifier(&id);
239 ret = hx509_name_binary(subject, id.subjectName);
241 hx509_name_free(&subject);
242 free_ExternalPrincipalIdentifier(&id);
246 hx509_name_free(&subject);
249 id.issuerAndSerialNumber = calloc(1, sizeof(*id.issuerAndSerialNumber));
250 if (id.issuerAndSerialNumber == NULL) {
251 free_ExternalPrincipalIdentifier(&id);
256 IssuerAndSerialNumber iasn;
260 memset(&iasn, 0, sizeof(iasn));
262 ret = hx509_cert_get_issuer(c, &issuer);
264 free_ExternalPrincipalIdentifier(&id);
268 ret = hx509_name_to_Name(issuer, &iasn.issuer);
269 hx509_name_free(&issuer);
271 free_ExternalPrincipalIdentifier(&id);
275 ret = hx509_cert_get_serialnumber(c, &iasn.serialNumber);
277 free_IssuerAndSerialNumber(&iasn);
278 free_ExternalPrincipalIdentifier(&id);
282 ASN1_MALLOC_ENCODE(IssuerAndSerialNumber,
283 id.issuerAndSerialNumber->data,
284 id.issuerAndSerialNumber->length,
286 free_IssuerAndSerialNumber(&iasn);
289 if (id.issuerAndSerialNumber->length != size)
293 id.subjectKeyIdentifier = NULL;
295 p = realloc(ids->val, sizeof(ids->val[0]) * (ids->len + 1));
297 free_ExternalPrincipalIdentifier(&id);
302 ids->val[ids->len] = id;
308 static krb5_error_code
309 build_edi(krb5_context context,
310 hx509_context hx509ctx,
312 ExternalPrincipalIdentifiers *ids)
314 return hx509_certs_iter(hx509ctx, certs, cert2epi, ids);
317 static krb5_error_code
318 build_auth_pack(krb5_context context,
320 krb5_pk_init_ctx ctx,
322 const KDC_REQ_BODY *body,
325 size_t buf_size, len;
332 krb5_clear_error_string(context);
334 memset(&checksum, 0, sizeof(checksum));
336 krb5_us_timeofday(context, &sec, &usec);
337 a->pkAuthenticator.ctime = sec;
338 a->pkAuthenticator.nonce = nonce;
340 ASN1_MALLOC_ENCODE(KDC_REQ_BODY, buf, buf_size, body, &len, ret);
344 krb5_abortx(context, "internal error in ASN.1 encoder");
346 ret = krb5_create_checksum(context,
357 ALLOC(a->pkAuthenticator.paChecksum, 1);
358 if (a->pkAuthenticator.paChecksum == NULL) {
359 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
363 ret = krb5_data_copy(a->pkAuthenticator.paChecksum,
364 checksum.checksum.data, checksum.checksum.length);
365 free_Checksum(&checksum);
371 heim_integer dh_pub_key;
375 if (1 /* support_cached_dh */) {
376 ALLOC(a->clientDHNonce, 1);
377 if (a->clientDHNonce == NULL) {
378 krb5_clear_error_string(context);
381 ret = krb5_data_alloc(a->clientDHNonce, 40);
382 if (a->clientDHNonce == NULL) {
383 krb5_clear_error_string(context);
386 memset(a->clientDHNonce->data, 0, a->clientDHNonce->length);
387 ret = krb5_copy_data(context, a->clientDHNonce,
388 &ctx->clientDHNonce);
393 ALLOC(a->clientPublicValue, 1);
394 if (a->clientPublicValue == NULL)
396 ret = der_copy_oid(oid_id_dhpublicnumber(),
397 &a->clientPublicValue->algorithm.algorithm);
401 memset(&dp, 0, sizeof(dp));
403 ret = BN_to_integer(context, dh->p, &dp.p);
405 free_DomainParameters(&dp);
408 ret = BN_to_integer(context, dh->g, &dp.g);
410 free_DomainParameters(&dp);
413 ret = BN_to_integer(context, dh->q, &dp.q);
415 free_DomainParameters(&dp);
419 dp.validationParms = NULL;
421 a->clientPublicValue->algorithm.parameters =
422 malloc(sizeof(*a->clientPublicValue->algorithm.parameters));
423 if (a->clientPublicValue->algorithm.parameters == NULL) {
424 free_DomainParameters(&dp);
428 ASN1_MALLOC_ENCODE(DomainParameters,
429 a->clientPublicValue->algorithm.parameters->data,
430 a->clientPublicValue->algorithm.parameters->length,
432 free_DomainParameters(&dp);
435 if (size != a->clientPublicValue->algorithm.parameters->length)
436 krb5_abortx(context, "Internal ASN1 encoder error");
438 ret = BN_to_integer(context, dh->pub_key, &dh_pub_key);
442 ASN1_MALLOC_ENCODE(DHPublicKey, dhbuf.data, dhbuf.length,
443 &dh_pub_key, &size, ret);
444 der_free_heim_integer(&dh_pub_key);
447 if (size != dhbuf.length)
448 krb5_abortx(context, "asn1 internal error");
450 a->clientPublicValue->subjectPublicKey.length = dhbuf.length * 8;
451 a->clientPublicValue->subjectPublicKey.data = dhbuf.data;
455 a->supportedCMSTypes = calloc(1, sizeof(*a->supportedCMSTypes));
456 if (a->supportedCMSTypes == NULL)
459 ret = hx509_crypto_available(ctx->id->hx509ctx, HX509_SELECT_ALL, NULL,
460 &a->supportedCMSTypes->val,
461 &a->supportedCMSTypes->len);
469 krb5_error_code KRB5_LIB_FUNCTION
470 _krb5_pk_mk_ContentInfo(krb5_context context,
471 const krb5_data *buf,
473 struct ContentInfo *content_info)
477 ret = der_copy_oid(oid, &content_info->contentType);
480 ALLOC(content_info->content, 1);
481 if (content_info->content == NULL)
483 content_info->content->data = malloc(buf->length);
484 if (content_info->content->data == NULL)
486 memcpy(content_info->content->data, buf->data, buf->length);
487 content_info->content->length = buf->length;
491 static krb5_error_code
492 pk_mk_padata(krb5_context context,
493 krb5_pk_init_ctx ctx,
494 const KDC_REQ_BODY *req_body,
498 struct ContentInfo content_info;
502 krb5_data buf, sd_buf;
505 krb5_data_zero(&buf);
506 krb5_data_zero(&sd_buf);
507 memset(&content_info, 0, sizeof(content_info));
509 if (ctx->type == PKINIT_WIN2K) {
514 memset(&ap, 0, sizeof(ap));
516 /* fill in PKAuthenticator */
517 ret = copy_PrincipalName(req_body->sname, &ap.pkAuthenticator.kdcName);
519 free_AuthPack_Win2k(&ap);
520 krb5_clear_error_string(context);
523 ret = copy_Realm(&req_body->realm, &ap.pkAuthenticator.kdcRealm);
525 free_AuthPack_Win2k(&ap);
526 krb5_clear_error_string(context);
530 krb5_us_timeofday(context, &sec, &usec);
531 ap.pkAuthenticator.ctime = sec;
532 ap.pkAuthenticator.cusec = usec;
533 ap.pkAuthenticator.nonce = nonce;
535 ASN1_MALLOC_ENCODE(AuthPack_Win2k, buf.data, buf.length,
537 free_AuthPack_Win2k(&ap);
539 krb5_set_error_message(context, ret, "AuthPack_Win2k: %d",
543 if (buf.length != size)
544 krb5_abortx(context, "internal ASN1 encoder error");
546 oid = oid_id_pkcs7_data();
547 } else if (ctx->type == PKINIT_27) {
550 memset(&ap, 0, sizeof(ap));
552 ret = build_auth_pack(context, nonce, ctx, ctx->dh, req_body, &ap);
558 ASN1_MALLOC_ENCODE(AuthPack, buf.data, buf.length, &ap, &size, ret);
561 krb5_set_error_message(context, ret, "AuthPack: %d", (int)ret);
564 if (buf.length != size)
565 krb5_abortx(context, "internal ASN1 encoder error");
567 oid = oid_id_pkauthdata();
569 krb5_abortx(context, "internal pkinit error");
571 ret = create_signature(context, oid, &buf, ctx->id,
573 krb5_data_free(&buf);
577 ret = hx509_cms_wrap_ContentInfo(oid_id_pkcs7_signedData(), &sd_buf, &buf);
578 krb5_data_free(&sd_buf);
580 krb5_set_error_message(context, ret,
581 "ContentInfo wrapping of signedData failed");
585 if (ctx->type == PKINIT_WIN2K) {
586 PA_PK_AS_REQ_Win2k winreq;
588 pa_type = KRB5_PADATA_PK_AS_REQ_WIN;
590 memset(&winreq, 0, sizeof(winreq));
592 winreq.signed_auth_pack = buf;
594 ASN1_MALLOC_ENCODE(PA_PK_AS_REQ_Win2k, buf.data, buf.length,
595 &winreq, &size, ret);
596 free_PA_PK_AS_REQ_Win2k(&winreq);
598 } else if (ctx->type == PKINIT_27) {
601 pa_type = KRB5_PADATA_PK_AS_REQ;
603 memset(&req, 0, sizeof(req));
604 req.signedAuthPack = buf;
606 if (ctx->trustedCertifiers) {
608 req.trustedCertifiers = calloc(1, sizeof(*req.trustedCertifiers));
609 if (req.trustedCertifiers == NULL) {
611 krb5_set_error_message(context, ret, "malloc: out of memory");
612 free_PA_PK_AS_REQ(&req);
615 ret = build_edi(context, ctx->id->hx509ctx,
616 ctx->id->anchors, req.trustedCertifiers);
618 krb5_set_error_message(context, ret, "pk-init: failed to build trustedCertifiers");
619 free_PA_PK_AS_REQ(&req);
625 ASN1_MALLOC_ENCODE(PA_PK_AS_REQ, buf.data, buf.length,
628 free_PA_PK_AS_REQ(&req);
631 krb5_abortx(context, "internal pkinit error");
633 krb5_set_error_message(context, ret, "PA-PK-AS-REQ %d", (int)ret);
636 if (buf.length != size)
637 krb5_abortx(context, "Internal ASN1 encoder error");
639 ret = krb5_padata_add(context, md, pa_type, buf.data, buf.length);
643 if (ret == 0 && ctx->type == PKINIT_WIN2K)
644 krb5_padata_add(context, md, KRB5_PADATA_PK_AS_09_BINDING, NULL, 0);
647 free_ContentInfo(&content_info);
653 krb5_error_code KRB5_LIB_FUNCTION
654 _krb5_pk_mk_padata(krb5_context context,
656 const KDC_REQ_BODY *req_body,
660 krb5_pk_init_ctx ctx = c;
663 win2k_compat = krb5_config_get_bool_default(context, NULL,
671 ctx->require_binding =
672 krb5_config_get_bool_default(context, NULL,
676 "pkinit_win2k_require_binding",
678 ctx->type = PKINIT_WIN2K;
680 ctx->type = PKINIT_27;
683 krb5_config_get_bool_default(context, NULL,
687 "pkinit_require_eku",
689 ctx->require_krbtgt_otherName =
690 krb5_config_get_bool_default(context, NULL,
694 "pkinit_require_krbtgt_otherName",
697 ctx->require_hostname_match =
698 krb5_config_get_bool_default(context, NULL,
702 "pkinit_require_hostname_match",
705 ctx->trustedCertifiers =
706 krb5_config_get_bool_default(context, NULL,
710 "pkinit_trustedCertifiers",
713 return pk_mk_padata(context, ctx, req_body, nonce, md);
716 krb5_error_code KRB5_LIB_FUNCTION
717 _krb5_pk_verify_sign(krb5_context context,
720 struct krb5_pk_identity *id,
721 heim_oid *contentType,
723 struct krb5_pk_cert **signer)
725 hx509_certs signer_certs;
730 ret = hx509_cms_verify_signed(id->hx509ctx,
740 pk_copy_error(context, id->hx509ctx, ret,
741 "CMS verify signed failed");
745 *signer = calloc(1, sizeof(**signer));
746 if (*signer == NULL) {
747 krb5_clear_error_string(context);
752 ret = hx509_get_one_cert(id->hx509ctx, signer_certs, &(*signer)->cert);
754 pk_copy_error(context, id->hx509ctx, ret,
755 "Failed to get on of the signer certs");
760 hx509_certs_free(&signer_certs);
763 hx509_cert_free((*signer)->cert);
772 static krb5_error_code
773 get_reply_key_win(krb5_context context,
774 const krb5_data *content,
778 ReplyKeyPack_Win2k key_pack;
782 ret = decode_ReplyKeyPack_Win2k(content->data,
787 krb5_set_error_message(context, ret, "PKINIT decoding reply key failed");
788 free_ReplyKeyPack_Win2k(&key_pack);
792 if (key_pack.nonce != nonce) {
793 krb5_set_error_message(context, ret, "PKINIT enckey nonce is wrong");
794 free_ReplyKeyPack_Win2k(&key_pack);
795 return KRB5KRB_AP_ERR_MODIFIED;
798 *key = malloc (sizeof (**key));
800 free_ReplyKeyPack_Win2k(&key_pack);
801 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
805 ret = copy_EncryptionKey(&key_pack.replyKey, *key);
806 free_ReplyKeyPack_Win2k(&key_pack);
808 krb5_set_error_message(context, ret, "PKINIT failed copying reply key");
816 static krb5_error_code
817 get_reply_key(krb5_context context,
818 const krb5_data *content,
819 const krb5_data *req_buffer,
822 ReplyKeyPack key_pack;
826 ret = decode_ReplyKeyPack(content->data,
831 krb5_set_error_message(context, ret, "PKINIT decoding reply key failed");
832 free_ReplyKeyPack(&key_pack);
840 * XXX Verify kp.replyKey is a allowed enctype in the
844 ret = krb5_crypto_init(context, &key_pack.replyKey, 0, &crypto);
846 free_ReplyKeyPack(&key_pack);
850 ret = krb5_verify_checksum(context, crypto, 6,
851 req_buffer->data, req_buffer->length,
852 &key_pack.asChecksum);
853 krb5_crypto_destroy(context, crypto);
855 free_ReplyKeyPack(&key_pack);
860 *key = malloc (sizeof (**key));
862 free_ReplyKeyPack(&key_pack);
863 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
867 ret = copy_EncryptionKey(&key_pack.replyKey, *key);
868 free_ReplyKeyPack(&key_pack);
870 krb5_set_error_message(context, ret, "PKINIT failed copying reply key");
879 static krb5_error_code
880 pk_verify_host(krb5_context context,
882 const krb5_krbhst_info *hi,
883 struct krb5_pk_init_ctx_data *ctx,
884 struct krb5_pk_cert *host)
886 krb5_error_code ret = 0;
888 if (ctx->require_eku) {
889 ret = hx509_cert_check_eku(ctx->id->hx509ctx, host->cert,
890 oid_id_pkkdcekuoid(), 0);
892 krb5_set_error_message(context, ret, "No PK-INIT KDC EKU in kdc certificate");
896 if (ctx->require_krbtgt_otherName) {
897 hx509_octet_string_list list;
900 ret = hx509_cert_find_subjectAltName_otherName(ctx->id->hx509ctx,
905 krb5_set_error_message(context, ret, "Failed to find the PK-INIT "
906 "subjectAltName in the KDC certificate");
911 for (i = 0; i < list.len; i++) {
914 ret = decode_KRB5PrincipalName(list.val[i].data,
919 krb5_set_error_message(context, ret, "Failed to decode the PK-INIT "
920 "subjectAltName in the KDC certificate");
925 if (r.principalName.name_string.len != 2 ||
926 strcmp(r.principalName.name_string.val[0], KRB5_TGS_NAME) != 0 ||
927 strcmp(r.principalName.name_string.val[1], realm) != 0 ||
928 strcmp(r.realm, realm) != 0)
930 ret = KRB5_KDC_ERR_INVALID_CERTIFICATE;
931 krb5_set_error_message(context, ret, "KDC have wrong realm name in "
935 free_KRB5PrincipalName(&r);
939 hx509_free_octet_string_list(&list);
945 ret = hx509_verify_hostname(ctx->id->hx509ctx, host->cert,
946 ctx->require_hostname_match,
949 hi->ai->ai_addr, hi->ai->ai_addrlen);
952 krb5_set_error_message(context, ret, "Address mismatch in "
953 "the KDC certificate");
958 static krb5_error_code
959 pk_rd_pa_reply_enckey(krb5_context context,
961 const heim_octet_string *indata,
962 const heim_oid *dataType,
964 krb5_pk_init_ctx ctx,
966 const krb5_krbhst_info *hi,
968 const krb5_data *req_buffer,
973 struct krb5_pk_cert *host = NULL;
975 heim_oid contentType = { 0, NULL };
977 if (der_heim_oid_cmp(oid_id_pkcs7_envelopedData(), dataType)) {
978 krb5_set_error_message(context, EINVAL, "PKINIT: Invalid content type");
982 ret = hx509_cms_unenvelope(ctx->id->hx509ctx,
984 HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT,
992 pk_copy_error(context, ctx->id->hx509ctx, ret,
993 "Failed to unenvelope CMS data in PK-INIT reply");
996 der_free_oid(&contentType);
998 #if 0 /* windows LH with interesting CMS packets, leaks memory */
1000 size_t ph = 1 + der_length_len (length);
1001 unsigned char *ptr = malloc(length + ph);
1004 memcpy(ptr + ph, p, length);
1006 ret = der_put_length_and_tag (ptr + ph - 1, ph, length,
1007 ASN1_C_UNIV, CONS, UT_Sequence, &l);
1016 /* win2k uses ContentInfo */
1017 if (type == PKINIT_WIN2K) {
1019 heim_octet_string out;
1021 ret = hx509_cms_unwrap_ContentInfo(&content, &type, &out, NULL);
1022 if (der_heim_oid_cmp(&type, oid_id_pkcs7_signedData())) {
1023 ret = EINVAL; /* XXX */
1024 krb5_set_error_message(context, ret, "PKINIT: Invalid content type");
1025 der_free_oid(&type);
1026 der_free_octet_string(&out);
1029 der_free_oid(&type);
1030 krb5_data_free(&content);
1031 ret = krb5_data_copy(&content, out.data, out.length);
1032 der_free_octet_string(&out);
1034 krb5_set_error_message(context, ret, "PKINIT: out of memory");
1039 ret = _krb5_pk_verify_sign(context,
1049 /* make sure that it is the kdc's certificate */
1050 ret = pk_verify_host(context, realm, hi, ctx, host);
1056 if (type == PKINIT_WIN2K) {
1057 if (der_heim_oid_cmp(&contentType, oid_id_pkcs7_data()) != 0) {
1058 ret = KRB5KRB_AP_ERR_MSG_TYPE;
1059 krb5_set_error_message(context, ret, "PKINIT: reply key, wrong oid");
1063 if (der_heim_oid_cmp(&contentType, oid_id_pkrkeydata()) != 0) {
1064 ret = KRB5KRB_AP_ERR_MSG_TYPE;
1065 krb5_set_error_message(context, ret, "PKINIT: reply key, wrong oid");
1073 ret = get_reply_key(context, &content, req_buffer, key);
1074 if (ret != 0 && ctx->require_binding == 0)
1075 ret = get_reply_key_win(context, &content, nonce, key);
1078 ret = get_reply_key(context, &content, req_buffer, key);
1084 /* XXX compare given etype with key->etype */
1088 _krb5_pk_cert_free(host);
1089 der_free_oid(&contentType);
1090 krb5_data_free(&content);
1095 static krb5_error_code
1096 pk_rd_pa_reply_dh(krb5_context context,
1097 const heim_octet_string *indata,
1098 const heim_oid *dataType,
1100 krb5_pk_init_ctx ctx,
1102 const krb5_krbhst_info *hi,
1107 krb5_keyblock **key)
1109 unsigned char *p, *dh_gen_key = NULL;
1110 struct krb5_pk_cert *host = NULL;
1111 BIGNUM *kdc_dh_pubkey = NULL;
1112 KDCDHKeyInfo kdc_dh_info;
1113 heim_oid contentType = { 0, NULL };
1115 krb5_error_code ret;
1119 krb5_data_zero(&content);
1120 memset(&kdc_dh_info, 0, sizeof(kdc_dh_info));
1122 if (der_heim_oid_cmp(oid_id_pkcs7_signedData(), dataType)) {
1123 krb5_set_error_message(context, EINVAL, "PKINIT: Invalid content type");
1127 ret = _krb5_pk_verify_sign(context,
1137 /* make sure that it is the kdc's certificate */
1138 ret = pk_verify_host(context, realm, hi, ctx, host);
1142 if (der_heim_oid_cmp(&contentType, oid_id_pkdhkeydata())) {
1143 ret = KRB5KRB_AP_ERR_MSG_TYPE;
1144 krb5_set_error_message(context, ret, "pkinit - dh reply contains wrong oid");
1148 ret = decode_KDCDHKeyInfo(content.data,
1154 krb5_set_error_message(context, ret, "pkinit - "
1155 "failed to decode KDC DH Key Info");
1159 if (kdc_dh_info.nonce != nonce) {
1160 ret = KRB5KRB_AP_ERR_MODIFIED;
1161 krb5_set_error_message(context, ret, "PKINIT: DH nonce is wrong");
1165 if (kdc_dh_info.dhKeyExpiration) {
1167 ret = KRB5KRB_ERR_GENERIC;
1168 krb5_set_error_message(context, ret, "pkinit; got key expiration "
1169 "without server nonce");
1173 ret = KRB5KRB_ERR_GENERIC;
1174 krb5_set_error_message(context, ret, "pkinit; got DH reuse but no "
1180 ret = KRB5KRB_ERR_GENERIC;
1181 krb5_set_error_message(context, ret, "pkinit: got server nonce "
1182 "without key expiration");
1189 p = kdc_dh_info.subjectPublicKey.data;
1190 size = (kdc_dh_info.subjectPublicKey.length + 7) / 8;
1194 ret = decode_DHPublicKey(p, size, &k, NULL);
1196 krb5_set_error_message(context, ret, "pkinit: can't decode "
1197 "without key expiration");
1201 kdc_dh_pubkey = integer_to_BN(context, "DHPublicKey", &k);
1202 free_DHPublicKey(&k);
1203 if (kdc_dh_pubkey == NULL) {
1209 dh_gen_keylen = DH_size(ctx->dh);
1210 size = BN_num_bytes(ctx->dh->p);
1211 if (size < dh_gen_keylen)
1212 size = dh_gen_keylen;
1214 dh_gen_key = malloc(size);
1215 if (dh_gen_key == NULL) {
1217 krb5_set_error_message(context, ret, "malloc: out of memory");
1220 memset(dh_gen_key, 0, size - dh_gen_keylen);
1222 dh_gen_keylen = DH_compute_key(dh_gen_key + (size - dh_gen_keylen),
1223 kdc_dh_pubkey, ctx->dh);
1224 if (dh_gen_keylen == -1) {
1225 ret = KRB5KRB_ERR_GENERIC;
1226 krb5_set_error_message(context, ret,
1227 "PKINIT: Can't compute Diffie-Hellman key");
1231 *key = malloc (sizeof (**key));
1234 krb5_set_error_message(context, ret, "malloc: out of memory");
1238 ret = _krb5_pk_octetstring2key(context,
1240 dh_gen_key, dh_gen_keylen,
1244 krb5_set_error_message(context, ret,
1245 "PKINIT: can't create key from DH key");
1253 BN_free(kdc_dh_pubkey);
1255 memset(dh_gen_key, 0, DH_size(ctx->dh));
1259 _krb5_pk_cert_free(host);
1261 krb5_data_free(&content);
1262 der_free_oid(&contentType);
1263 free_KDCDHKeyInfo(&kdc_dh_info);
1268 krb5_error_code KRB5_LIB_FUNCTION
1269 _krb5_pk_rd_pa_reply(krb5_context context,
1273 const krb5_krbhst_info *hi,
1275 const krb5_data *req_buffer,
1277 krb5_keyblock **key)
1279 krb5_pk_init_ctx ctx = c;
1280 krb5_error_code ret;
1283 /* Check for IETF PK-INIT first */
1284 if (ctx->type == PKINIT_27) {
1286 heim_octet_string os, data;
1289 if (pa->padata_type != KRB5_PADATA_PK_AS_REP) {
1290 krb5_set_error_message(context, EINVAL, "PKINIT: wrong padata recv");
1294 ret = decode_PA_PK_AS_REP(pa->padata_value.data,
1295 pa->padata_value.length,
1299 krb5_set_error_message(context, ret, "Failed to decode pkinit AS rep");
1303 switch (rep.element) {
1304 case choice_PA_PK_AS_REP_dhInfo:
1305 os = rep.u.dhInfo.dhSignedData;
1307 case choice_PA_PK_AS_REP_encKeyPack:
1308 os = rep.u.encKeyPack;
1311 free_PA_PK_AS_REP(&rep);
1312 krb5_set_error_message(context, EINVAL, "PKINIT: -27 reply "
1313 "invalid content type");
1317 ret = hx509_cms_unwrap_ContentInfo(&os, &oid, &data, NULL);
1319 free_PA_PK_AS_REP(&rep);
1320 krb5_set_error_message(context, ret, "PKINIT: failed to unwrap CI");
1324 switch (rep.element) {
1325 case choice_PA_PK_AS_REP_dhInfo:
1326 ret = pk_rd_pa_reply_dh(context, &data, &oid, realm, ctx, etype, hi,
1328 rep.u.dhInfo.serverDHNonce,
1331 case choice_PA_PK_AS_REP_encKeyPack:
1332 ret = pk_rd_pa_reply_enckey(context, PKINIT_27, &data, &oid, realm,
1333 ctx, etype, hi, nonce, req_buffer, pa, key);
1336 krb5_abortx(context, "pk-init as-rep case not possible to happen");
1338 der_free_octet_string(&data);
1340 free_PA_PK_AS_REP(&rep);
1342 } else if (ctx->type == PKINIT_WIN2K) {
1343 PA_PK_AS_REP_Win2k w2krep;
1345 /* Check for Windows encoding of the AS-REP pa data */
1347 #if 0 /* should this be ? */
1348 if (pa->padata_type != KRB5_PADATA_PK_AS_REP) {
1349 krb5_set_error_message(context, EINVAL, "PKINIT: wrong padata recv");
1354 memset(&w2krep, 0, sizeof(w2krep));
1356 ret = decode_PA_PK_AS_REP_Win2k(pa->padata_value.data,
1357 pa->padata_value.length,
1361 krb5_set_error_message(context, ret, "PKINIT: Failed decoding windows "
1362 "pkinit reply %d", (int)ret);
1366 krb5_clear_error_string(context);
1368 switch (w2krep.element) {
1369 case choice_PA_PK_AS_REP_Win2k_encKeyPack: {
1370 heim_octet_string data;
1373 ret = hx509_cms_unwrap_ContentInfo(&w2krep.u.encKeyPack,
1375 free_PA_PK_AS_REP_Win2k(&w2krep);
1377 krb5_set_error_message(context, ret, "PKINIT: failed to unwrap CI");
1381 ret = pk_rd_pa_reply_enckey(context, PKINIT_WIN2K, &data, &oid, realm,
1382 ctx, etype, hi, nonce, req_buffer, pa, key);
1383 der_free_octet_string(&data);
1389 free_PA_PK_AS_REP_Win2k(&w2krep);
1391 krb5_set_error_message(context, ret, "PKINIT: win2k reply invalid "
1398 krb5_set_error_message(context, ret, "PKINIT: unknown reply type");
1405 krb5_context context;
1406 krb5_prompter_fct prompter;
1407 void *prompter_data;
1411 hx_pass_prompter(void *data, const hx509_prompt *prompter)
1413 krb5_error_code ret;
1415 krb5_data password_data;
1416 struct prompter *p = data;
1418 password_data.data = prompter->reply.data;
1419 password_data.length = prompter->reply.length;
1421 prompt.prompt = prompter->prompt;
1422 prompt.hidden = hx509_prompt_hidden(prompter->type);
1423 prompt.reply = &password_data;
1425 switch (prompter->type) {
1426 case HX509_PROMPT_TYPE_INFO:
1427 prompt.type = KRB5_PROMPT_TYPE_INFO;
1429 case HX509_PROMPT_TYPE_PASSWORD:
1430 case HX509_PROMPT_TYPE_QUESTION:
1432 prompt.type = KRB5_PROMPT_TYPE_PASSWORD;
1436 ret = (*p->prompter)(p->context, p->prompter_data, NULL, NULL, 1, &prompt);
1438 memset (prompter->reply.data, 0, prompter->reply.length);
1445 void KRB5_LIB_FUNCTION
1446 _krb5_pk_allow_proxy_certificate(struct krb5_pk_identity *id,
1449 hx509_verify_set_proxy_certificate(id->verify_ctx, boolean);
1453 krb5_error_code KRB5_LIB_FUNCTION
1454 _krb5_pk_load_id(krb5_context context,
1455 struct krb5_pk_identity **ret_id,
1456 const char *user_id,
1457 const char *anchor_id,
1458 char * const *chain_list,
1459 char * const *revoke_list,
1460 krb5_prompter_fct prompter,
1461 void *prompter_data,
1464 struct krb5_pk_identity *id = NULL;
1465 hx509_lock lock = NULL;
1471 if (anchor_id == NULL) {
1472 krb5_set_error_message(context, HEIM_PKINIT_NO_VALID_CA,
1473 "PKINIT: No anchor given");
1474 return HEIM_PKINIT_NO_VALID_CA;
1477 if (user_id == NULL) {
1478 krb5_set_error_message(context, HEIM_PKINIT_NO_PRIVATE_KEY,
1479 "PKINIT: No user certificate given");
1480 return HEIM_PKINIT_NO_PRIVATE_KEY;
1485 id = calloc(1, sizeof(*id));
1487 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1491 ret = hx509_context_init(&id->hx509ctx);
1495 ret = hx509_lock_init(id->hx509ctx, &lock);
1496 if (password && password[0])
1497 hx509_lock_add_password(lock, password);
1500 p.context = context;
1501 p.prompter = prompter;
1502 p.prompter_data = prompter_data;
1504 ret = hx509_lock_set_prompter(lock, hx_pass_prompter, &p);
1509 ret = hx509_certs_init(id->hx509ctx, user_id, 0, lock, &id->certs);
1511 pk_copy_error(context, id->hx509ctx, ret,
1512 "Failed to init cert certs");
1516 ret = hx509_certs_init(id->hx509ctx, anchor_id, 0, NULL, &id->anchors);
1518 pk_copy_error(context, id->hx509ctx, ret,
1519 "Failed to init anchors");
1523 ret = hx509_certs_init(id->hx509ctx, "MEMORY:pkinit-cert-chain",
1524 0, NULL, &id->certpool);
1526 pk_copy_error(context, id->hx509ctx, ret,
1527 "Failed to init chain");
1531 while (chain_list && *chain_list) {
1532 ret = hx509_certs_append(id->hx509ctx, id->certpool,
1535 pk_copy_error(context, id->hx509ctx, ret,
1536 "Failed to laod chain %s",
1544 ret = hx509_revoke_init(id->hx509ctx, &id->revokectx);
1546 pk_copy_error(context, id->hx509ctx, ret,
1547 "Failed init revoke list");
1551 while (*revoke_list) {
1552 ret = hx509_revoke_add_crl(id->hx509ctx,
1556 pk_copy_error(context, id->hx509ctx, ret,
1557 "Failed load revoke list");
1563 hx509_context_set_missing_revoke(id->hx509ctx, 1);
1565 ret = hx509_verify_init_ctx(id->hx509ctx, &id->verify_ctx);
1567 pk_copy_error(context, id->hx509ctx, ret,
1568 "Failed init verify context");
1572 hx509_verify_attach_anchors(id->verify_ctx, id->anchors);
1573 hx509_verify_attach_revoke(id->verify_ctx, id->revokectx);
1577 hx509_verify_destroy_ctx(id->verify_ctx);
1578 hx509_certs_free(&id->certs);
1579 hx509_certs_free(&id->anchors);
1580 hx509_certs_free(&id->certpool);
1581 hx509_revoke_free(&id->revokectx);
1582 hx509_context_free(&id->hx509ctx);
1587 hx509_lock_free(lock);
1592 static krb5_error_code
1593 select_dh_group(krb5_context context, DH *dh, unsigned long bits,
1594 struct krb5_dh_moduli **moduli)
1596 const struct krb5_dh_moduli *m;
1599 m = moduli[1]; /* XXX */
1601 m = moduli[0]; /* XXX */
1604 for (i = 0; moduli[i] != NULL; i++) {
1605 if (bits < moduli[i]->bits)
1608 if (moduli[i] == NULL) {
1609 krb5_set_error_message(context, EINVAL,
1610 "Did not find a DH group parameter "
1611 "matching requirement of %lu bits",
1618 dh->p = integer_to_BN(context, "p", &m->p);
1621 dh->g = integer_to_BN(context, "g", &m->g);
1624 dh->q = integer_to_BN(context, "q", &m->q);
1636 pk_copy_error(krb5_context context,
1637 hx509_context hx509ctx,
1646 vasprintf(&f, fmt, va);
1649 krb5_clear_error_string(context);
1653 s = hx509_get_error_string(hx509ctx, hxret);
1655 krb5_clear_error_string(context);
1659 krb5_set_error_message(context, hxret, "%s: %s", f, s);
1667 parse_integer(krb5_context context, char **p, const char *file, int lineno,
1668 const char *name, heim_integer *integer)
1672 p1 = strsep(p, " \t");
1674 krb5_set_error_message(context, EINVAL, "moduli file %s missing %s on line %d",
1675 file, name, lineno);
1678 ret = der_parse_hex_heim_integer(p1, integer);
1680 krb5_set_error_message(context, ret, "moduli file %s failed parsing %s "
1682 file, name, lineno);
1690 _krb5_parse_moduli_line(krb5_context context,
1694 struct krb5_dh_moduli **m)
1696 struct krb5_dh_moduli *m1;
1702 m1 = calloc(1, sizeof(*m1));
1704 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1708 while (isspace((unsigned char)*p))
1714 p1 = strsep(&p, " \t");
1716 krb5_set_error_message(context, ret, "moduli file %s missing name "
1717 "on line %d", file, lineno);
1720 m1->name = strdup(p1);
1723 krb5_set_error_message(context, ret, "malloc - out of memeory");
1727 p1 = strsep(&p, " \t");
1729 krb5_set_error_message(context, ret, "moduli file %s missing bits on line %d",
1734 m1->bits = atoi(p1);
1735 if (m1->bits == 0) {
1736 krb5_set_error_message(context, ret, "moduli file %s have un-parsable "
1737 "bits on line %d", file, lineno);
1741 ret = parse_integer(context, &p, file, lineno, "p", &m1->p);
1744 ret = parse_integer(context, &p, file, lineno, "g", &m1->g);
1747 ret = parse_integer(context, &p, file, lineno, "q", &m1->q);
1756 der_free_heim_integer(&m1->p);
1757 der_free_heim_integer(&m1->g);
1758 der_free_heim_integer(&m1->q);
1764 _krb5_free_moduli(struct krb5_dh_moduli **moduli)
1767 for (i = 0; moduli[i] != NULL; i++) {
1768 free(moduli[i]->name);
1769 der_free_heim_integer(&moduli[i]->p);
1770 der_free_heim_integer(&moduli[i]->g);
1771 der_free_heim_integer(&moduli[i]->q);
1777 static const char *default_moduli_RFC2412_MODP_group2 =
1779 "RFC2412-MODP-group2 "
1783 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
1784 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
1785 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
1786 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
1787 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
1788 "FFFFFFFF" "FFFFFFFF "
1792 "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68"
1793 "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E"
1794 "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122"
1795 "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6"
1796 "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F67329C0"
1797 "FFFFFFFF" "FFFFFFFF";
1799 static const char *default_moduli_rfc3526_MODP_group14 =
1801 "rfc3526-MODP-group14 "
1805 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
1806 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
1807 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
1808 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
1809 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D"
1810 "C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"
1811 "83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"
1812 "670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"
1813 "E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"
1814 "DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
1815 "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF "
1819 "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68"
1820 "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E"
1821 "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122"
1822 "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6"
1823 "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F6722D9E"
1824 "E1003E5C" "50B1DF82" "CC6D241B" "0E2AE9CD" "348B1FD4" "7E9267AF"
1825 "C1B2AE91" "EE51D6CB" "0E3179AB" "1042A95D" "CF6A9483" "B84B4B36"
1826 "B3861AA7" "255E4C02" "78BA3604" "650C10BE" "19482F23" "171B671D"
1827 "F1CF3B96" "0C074301" "CD93C1D1" "7603D147" "DAE2AEF8" "37A62964"
1828 "EF15E5FB" "4AAC0B8C" "1CCAA4BE" "754AB572" "8AE9130C" "4C7D0288"
1829 "0AB9472D" "45565534" "7FFFFFFF" "FFFFFFFF";
1832 _krb5_parse_moduli(krb5_context context, const char *file,
1833 struct krb5_dh_moduli ***moduli)
1835 /* name bits P G Q */
1836 krb5_error_code ret;
1837 struct krb5_dh_moduli **m = NULL, **m2;
1840 int lineno = 0, n = 0;
1844 m = calloc(1, sizeof(m[0]) * 3);
1846 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1850 strlcpy(buf, default_moduli_rfc3526_MODP_group14, sizeof(buf));
1851 ret = _krb5_parse_moduli_line(context, "builtin", 1, buf, &m[0]);
1853 _krb5_free_moduli(m);
1858 strlcpy(buf, default_moduli_RFC2412_MODP_group2, sizeof(buf));
1859 ret = _krb5_parse_moduli_line(context, "builtin", 1, buf, &m[1]);
1861 _krb5_free_moduli(m);
1870 f = fopen(file, "r");
1877 while(fgets(buf, sizeof(buf), f) != NULL) {
1878 struct krb5_dh_moduli *element;
1880 buf[strcspn(buf, "\n")] = '\0';
1883 m2 = realloc(m, (n + 2) * sizeof(m[0]));
1885 _krb5_free_moduli(m);
1886 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1893 ret = _krb5_parse_moduli_line(context, file, lineno, buf, &element);
1895 _krb5_free_moduli(m);
1898 if (element == NULL)
1910 _krb5_dh_group_ok(krb5_context context, unsigned long bits,
1911 heim_integer *p, heim_integer *g, heim_integer *q,
1912 struct krb5_dh_moduli **moduli,
1920 for (i = 0; moduli[i] != NULL; i++) {
1921 if (der_heim_integer_cmp(&moduli[i]->g, g) == 0 &&
1922 der_heim_integer_cmp(&moduli[i]->p, p) == 0 &&
1923 (q == NULL || der_heim_integer_cmp(&moduli[i]->q, q) == 0))
1925 if (bits && bits > moduli[i]->bits) {
1926 krb5_set_error_message(context,
1927 KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED,
1928 "PKINIT: DH group parameter %s "
1929 "no accepted, not enough bits generated",
1931 return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
1934 *name = strdup(moduli[i]->name);
1938 krb5_set_error_message(context,
1939 KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED,
1940 "PKINIT: DH group parameter no ok");
1941 return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
1944 void KRB5_LIB_FUNCTION
1945 _krb5_get_init_creds_opt_free_pkinit(krb5_get_init_creds_opt *opt)
1948 krb5_pk_init_ctx ctx;
1950 if (opt->opt_private == NULL || opt->opt_private->pk_init_ctx == NULL)
1952 ctx = opt->opt_private->pk_init_ctx;
1957 hx509_verify_destroy_ctx(ctx->id->verify_ctx);
1958 hx509_certs_free(&ctx->id->certs);
1959 hx509_certs_free(&ctx->id->anchors);
1960 hx509_certs_free(&ctx->id->certpool);
1961 hx509_context_free(&ctx->id->hx509ctx);
1963 if (ctx->clientDHNonce) {
1964 krb5_free_data(NULL, ctx->clientDHNonce);
1965 ctx->clientDHNonce = NULL;
1968 _krb5_free_moduli(ctx->m);
1972 free(opt->opt_private->pk_init_ctx);
1973 opt->opt_private->pk_init_ctx = NULL;
1977 krb5_error_code KRB5_LIB_FUNCTION
1978 krb5_get_init_creds_opt_set_pkinit(krb5_context context,
1979 krb5_get_init_creds_opt *opt,
1980 krb5_principal principal,
1981 const char *user_id,
1982 const char *x509_anchors,
1983 char * const * pool,
1984 char * const * pki_revoke,
1986 krb5_prompter_fct prompter,
1987 void *prompter_data,
1991 krb5_error_code ret;
1992 char *anchors = NULL;
1994 if (opt->opt_private == NULL) {
1995 krb5_set_error_message(context, EINVAL, "PKINIT: on non extendable opt");
1999 opt->opt_private->pk_init_ctx =
2000 calloc(1, sizeof(*opt->opt_private->pk_init_ctx));
2001 if (opt->opt_private->pk_init_ctx == NULL) {
2002 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
2005 opt->opt_private->pk_init_ctx->dh = NULL;
2006 opt->opt_private->pk_init_ctx->id = NULL;
2007 opt->opt_private->pk_init_ctx->clientDHNonce = NULL;
2008 opt->opt_private->pk_init_ctx->require_binding = 0;
2009 opt->opt_private->pk_init_ctx->require_eku = 1;
2010 opt->opt_private->pk_init_ctx->require_krbtgt_otherName = 1;
2011 opt->opt_private->pk_init_ctx->peer = NULL;
2013 /* XXX implement krb5_appdefault_strings */
2015 pool = krb5_config_get_strings(context, NULL,
2020 if (pki_revoke == NULL)
2021 pki_revoke = krb5_config_get_strings(context, NULL,
2026 if (x509_anchors == NULL) {
2027 krb5_appdefault_string(context, "kinit",
2028 krb5_principal_get_realm(context, principal),
2029 "pkinit_anchors", NULL, &anchors);
2030 x509_anchors = anchors;
2033 ret = _krb5_pk_load_id(context,
2034 &opt->opt_private->pk_init_ctx->id,
2043 free(opt->opt_private->pk_init_ctx);
2044 opt->opt_private->pk_init_ctx = NULL;
2048 if ((flags & 2) == 0) {
2049 const char *moduli_file;
2050 unsigned long dh_min_bits;
2052 moduli_file = krb5_config_get_string(context, NULL,
2058 krb5_config_get_int_default(context, NULL, 0,
2060 "pkinit_dh_min_bits",
2063 ret = _krb5_parse_moduli(context, moduli_file,
2064 &opt->opt_private->pk_init_ctx->m);
2066 _krb5_get_init_creds_opt_free_pkinit(opt);
2070 opt->opt_private->pk_init_ctx->dh = DH_new();
2071 if (opt->opt_private->pk_init_ctx->dh == NULL) {
2072 _krb5_get_init_creds_opt_free_pkinit(opt);
2073 krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
2077 ret = select_dh_group(context, opt->opt_private->pk_init_ctx->dh,
2079 opt->opt_private->pk_init_ctx->m);
2081 _krb5_get_init_creds_opt_free_pkinit(opt);
2085 if (DH_generate_key(opt->opt_private->pk_init_ctx->dh) != 1) {
2086 _krb5_get_init_creds_opt_free_pkinit(opt);
2087 krb5_set_error_message(context, ENOMEM, "pkinit: failed to generate DH key");
2094 krb5_set_error_message(context, EINVAL, "no support for PKINIT compiled in");