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("$Heimdal: pkinit.c 22433 2008-01-13 14:11:46Z lha $"
39 struct krb5_dh_moduli
{
49 #include <heim_asn1.h>
50 #include <rfc2459_asn1.h>
52 #include <pkcs8_asn1.h>
53 #include <pkcs9_asn1.h>
54 #include <pkcs12_asn1.h>
55 #include <pkinit_asn1.h>
67 struct krb5_pk_identity
{
68 hx509_context hx509ctx
;
69 hx509_verify_ctx verify_ctx
;
73 hx509_revoke_ctx revokectx
;
80 struct krb5_pk_init_ctx_data
{
81 struct krb5_pk_identity
*id
;
83 krb5_data
*clientDHNonce
;
84 struct krb5_dh_moduli
**m
;
87 unsigned int require_binding
:1;
88 unsigned int require_eku
:1;
89 unsigned int require_krbtgt_otherName
:1;
90 unsigned int require_hostname_match
:1;
91 unsigned int trustedCertifiers
:1;
95 _krb5_pk_copy_error(krb5_context context
,
96 hx509_context hx509ctx
,
100 __attribute__ ((format (printf
, 4, 5)));
106 void KRB5_LIB_FUNCTION
107 _krb5_pk_cert_free(struct krb5_pk_cert
*cert
)
110 hx509_cert_free(cert
->cert
);
115 static krb5_error_code
116 BN_to_integer(krb5_context context
, BIGNUM
*bn
, heim_integer
*integer
)
118 integer
->length
= BN_num_bytes(bn
);
119 integer
->data
= malloc(integer
->length
);
120 if (integer
->data
== NULL
) {
121 krb5_clear_error_string(context
);
124 BN_bn2bin(bn
, integer
->data
);
125 integer
->negative
= BN_is_negative(bn
);
130 integer_to_BN(krb5_context context
, const char *field
, const heim_integer
*f
)
134 bn
= BN_bin2bn((const unsigned char *)f
->data
, f
->length
, NULL
);
136 krb5_set_error_string(context
, "PKINIT: parsing BN failed %s", field
);
139 BN_set_negative(bn
, f
->negative
);
144 static krb5_error_code
145 _krb5_pk_create_sign(krb5_context context
,
146 const heim_oid
*eContentType
,
148 struct krb5_pk_identity
*id
,
149 hx509_peer_info peer
,
156 ret
= hx509_query_alloc(id
->hx509ctx
, &q
);
158 _krb5_pk_copy_error(context
, id
->hx509ctx
, ret
,
159 "Allocate query to find signing certificate");
163 hx509_query_match_option(q
, HX509_QUERY_OPTION_PRIVATE_KEY
);
164 hx509_query_match_option(q
, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE
);
166 ret
= hx509_certs_find(id
->hx509ctx
, id
->certs
, q
, &cert
);
167 hx509_query_free(id
->hx509ctx
, q
);
169 _krb5_pk_copy_error(context
, id
->hx509ctx
, ret
,
170 "Find certificate to signed CMS data");
174 ret
= hx509_cms_create_signed_1(id
->hx509ctx
,
186 _krb5_pk_copy_error(context
, id
->hx509ctx
, ret
, "create CMS signedData");
187 hx509_cert_free(cert
);
193 cert2epi(hx509_context context
, void *ctx
, hx509_cert c
)
195 ExternalPrincipalIdentifiers
*ids
= ctx
;
196 ExternalPrincipalIdentifier id
;
197 hx509_name subject
= NULL
;
201 memset(&id
, 0, sizeof(id
));
203 ret
= hx509_cert_get_subject(c
, &subject
);
207 if (hx509_name_is_null_p(subject
) != 0) {
209 id
.subjectName
= calloc(1, sizeof(*id
.subjectName
));
210 if (id
.subjectName
== NULL
) {
211 hx509_name_free(&subject
);
212 free_ExternalPrincipalIdentifier(&id
);
216 ret
= hx509_name_binary(subject
, id
.subjectName
);
218 hx509_name_free(&subject
);
219 free_ExternalPrincipalIdentifier(&id
);
223 hx509_name_free(&subject
);
226 id
.issuerAndSerialNumber
= calloc(1, sizeof(*id
.issuerAndSerialNumber
));
227 if (id
.issuerAndSerialNumber
== NULL
) {
228 free_ExternalPrincipalIdentifier(&id
);
233 IssuerAndSerialNumber iasn
;
237 memset(&iasn
, 0, sizeof(iasn
));
239 ret
= hx509_cert_get_issuer(c
, &issuer
);
241 free_ExternalPrincipalIdentifier(&id
);
245 ret
= hx509_name_to_Name(issuer
, &iasn
.issuer
);
246 hx509_name_free(&issuer
);
248 free_ExternalPrincipalIdentifier(&id
);
252 ret
= hx509_cert_get_serialnumber(c
, &iasn
.serialNumber
);
254 free_IssuerAndSerialNumber(&iasn
);
255 free_ExternalPrincipalIdentifier(&id
);
259 ASN1_MALLOC_ENCODE(IssuerAndSerialNumber
,
260 id
.issuerAndSerialNumber
->data
,
261 id
.issuerAndSerialNumber
->length
,
263 free_IssuerAndSerialNumber(&iasn
);
266 if (id
.issuerAndSerialNumber
->length
!= size
)
270 id
.subjectKeyIdentifier
= NULL
;
272 p
= realloc(ids
->val
, sizeof(ids
->val
[0]) * (ids
->len
+ 1));
274 free_ExternalPrincipalIdentifier(&id
);
279 ids
->val
[ids
->len
] = id
;
285 static krb5_error_code
286 build_edi(krb5_context context
,
287 hx509_context hx509ctx
,
289 ExternalPrincipalIdentifiers
*ids
)
291 return hx509_certs_iter(hx509ctx
, certs
, cert2epi
, ids
);
294 static krb5_error_code
295 build_auth_pack(krb5_context context
,
297 krb5_pk_init_ctx ctx
,
299 const KDC_REQ_BODY
*body
,
302 size_t buf_size
, len
;
309 krb5_clear_error_string(context
);
311 memset(&checksum
, 0, sizeof(checksum
));
313 krb5_us_timeofday(context
, &sec
, &usec
);
314 a
->pkAuthenticator
.ctime
= sec
;
315 a
->pkAuthenticator
.nonce
= nonce
;
317 ASN1_MALLOC_ENCODE(KDC_REQ_BODY
, buf
, buf_size
, body
, &len
, ret
);
321 krb5_abortx(context
, "internal error in ASN.1 encoder");
323 ret
= krb5_create_checksum(context
,
334 ALLOC(a
->pkAuthenticator
.paChecksum
, 1);
335 if (a
->pkAuthenticator
.paChecksum
== NULL
) {
336 krb5_set_error_string(context
, "malloc: out of memory");
340 ret
= krb5_data_copy(a
->pkAuthenticator
.paChecksum
,
341 checksum
.checksum
.data
, checksum
.checksum
.length
);
342 free_Checksum(&checksum
);
348 heim_integer dh_pub_key
;
352 if (1 /* support_cached_dh */) {
353 ALLOC(a
->clientDHNonce
, 1);
354 if (a
->clientDHNonce
== NULL
) {
355 krb5_clear_error_string(context
);
358 ret
= krb5_data_alloc(a
->clientDHNonce
, 40);
359 if (a
->clientDHNonce
== NULL
) {
360 krb5_clear_error_string(context
);
363 memset(a
->clientDHNonce
->data
, 0, a
->clientDHNonce
->length
);
364 ret
= krb5_copy_data(context
, a
->clientDHNonce
,
365 &ctx
->clientDHNonce
);
370 ALLOC(a
->clientPublicValue
, 1);
371 if (a
->clientPublicValue
== NULL
)
373 ret
= der_copy_oid(oid_id_dhpublicnumber(),
374 &a
->clientPublicValue
->algorithm
.algorithm
);
378 memset(&dp
, 0, sizeof(dp
));
380 ret
= BN_to_integer(context
, dh
->p
, &dp
.p
);
382 free_DomainParameters(&dp
);
385 ret
= BN_to_integer(context
, dh
->g
, &dp
.g
);
387 free_DomainParameters(&dp
);
390 ret
= BN_to_integer(context
, dh
->q
, &dp
.q
);
392 free_DomainParameters(&dp
);
396 dp
.validationParms
= NULL
;
398 a
->clientPublicValue
->algorithm
.parameters
=
399 malloc(sizeof(*a
->clientPublicValue
->algorithm
.parameters
));
400 if (a
->clientPublicValue
->algorithm
.parameters
== NULL
) {
401 free_DomainParameters(&dp
);
405 ASN1_MALLOC_ENCODE(DomainParameters
,
406 a
->clientPublicValue
->algorithm
.parameters
->data
,
407 a
->clientPublicValue
->algorithm
.parameters
->length
,
409 free_DomainParameters(&dp
);
412 if (size
!= a
->clientPublicValue
->algorithm
.parameters
->length
)
413 krb5_abortx(context
, "Internal ASN1 encoder error");
415 ret
= BN_to_integer(context
, dh
->pub_key
, &dh_pub_key
);
419 ASN1_MALLOC_ENCODE(DHPublicKey
, dhbuf
.data
, dhbuf
.length
,
420 &dh_pub_key
, &size
, ret
);
421 der_free_heim_integer(&dh_pub_key
);
424 if (size
!= dhbuf
.length
)
425 krb5_abortx(context
, "asn1 internal error");
427 a
->clientPublicValue
->subjectPublicKey
.length
= dhbuf
.length
* 8;
428 a
->clientPublicValue
->subjectPublicKey
.data
= dhbuf
.data
;
432 a
->supportedCMSTypes
= calloc(1, sizeof(*a
->supportedCMSTypes
));
433 if (a
->supportedCMSTypes
== NULL
)
436 ret
= hx509_crypto_available(ctx
->id
->hx509ctx
, HX509_SELECT_ALL
, NULL
,
437 &a
->supportedCMSTypes
->val
,
438 &a
->supportedCMSTypes
->len
);
446 krb5_error_code KRB5_LIB_FUNCTION
447 _krb5_pk_mk_ContentInfo(krb5_context context
,
448 const krb5_data
*buf
,
450 struct ContentInfo
*content_info
)
454 ret
= der_copy_oid(oid
, &content_info
->contentType
);
457 ALLOC(content_info
->content
, 1);
458 if (content_info
->content
== NULL
)
460 content_info
->content
->data
= malloc(buf
->length
);
461 if (content_info
->content
->data
== NULL
)
463 memcpy(content_info
->content
->data
, buf
->data
, buf
->length
);
464 content_info
->content
->length
= buf
->length
;
468 static krb5_error_code
469 pk_mk_padata(krb5_context context
,
470 krb5_pk_init_ctx ctx
,
471 const KDC_REQ_BODY
*req_body
,
475 struct ContentInfo content_info
;
479 krb5_data buf
, sd_buf
;
482 krb5_data_zero(&buf
);
483 krb5_data_zero(&sd_buf
);
484 memset(&content_info
, 0, sizeof(content_info
));
486 if (ctx
->type
== COMPAT_WIN2K
) {
491 memset(&ap
, 0, sizeof(ap
));
493 /* fill in PKAuthenticator */
494 ret
= copy_PrincipalName(req_body
->sname
, &ap
.pkAuthenticator
.kdcName
);
496 free_AuthPack_Win2k(&ap
);
497 krb5_clear_error_string(context
);
500 ret
= copy_Realm(&req_body
->realm
, &ap
.pkAuthenticator
.kdcRealm
);
502 free_AuthPack_Win2k(&ap
);
503 krb5_clear_error_string(context
);
507 krb5_us_timeofday(context
, &sec
, &usec
);
508 ap
.pkAuthenticator
.ctime
= sec
;
509 ap
.pkAuthenticator
.cusec
= usec
;
510 ap
.pkAuthenticator
.nonce
= nonce
;
512 ASN1_MALLOC_ENCODE(AuthPack_Win2k
, buf
.data
, buf
.length
,
514 free_AuthPack_Win2k(&ap
);
516 krb5_set_error_string(context
, "AuthPack_Win2k: %d", ret
);
519 if (buf
.length
!= size
)
520 krb5_abortx(context
, "internal ASN1 encoder error");
522 oid
= oid_id_pkcs7_data();
523 } else if (ctx
->type
== COMPAT_IETF
) {
526 memset(&ap
, 0, sizeof(ap
));
528 ret
= build_auth_pack(context
, nonce
, ctx
, ctx
->dh
, req_body
, &ap
);
534 ASN1_MALLOC_ENCODE(AuthPack
, buf
.data
, buf
.length
, &ap
, &size
, ret
);
537 krb5_set_error_string(context
, "AuthPack: %d", ret
);
540 if (buf
.length
!= size
)
541 krb5_abortx(context
, "internal ASN1 encoder error");
543 oid
= oid_id_pkauthdata();
545 krb5_abortx(context
, "internal pkinit error");
547 ret
= _krb5_pk_create_sign(context
,
553 krb5_data_free(&buf
);
557 ret
= hx509_cms_wrap_ContentInfo(oid_id_pkcs7_signedData(), &sd_buf
, &buf
);
558 krb5_data_free(&sd_buf
);
560 krb5_set_error_string(context
,
561 "ContentInfo wrapping of signedData failed");
565 if (ctx
->type
== COMPAT_WIN2K
) {
566 PA_PK_AS_REQ_Win2k winreq
;
568 pa_type
= KRB5_PADATA_PK_AS_REQ_WIN
;
570 memset(&winreq
, 0, sizeof(winreq
));
572 winreq
.signed_auth_pack
= buf
;
574 ASN1_MALLOC_ENCODE(PA_PK_AS_REQ_Win2k
, buf
.data
, buf
.length
,
575 &winreq
, &size
, ret
);
576 free_PA_PK_AS_REQ_Win2k(&winreq
);
578 } else if (ctx
->type
== COMPAT_IETF
) {
581 pa_type
= KRB5_PADATA_PK_AS_REQ
;
583 memset(&req
, 0, sizeof(req
));
584 req
.signedAuthPack
= buf
;
586 if (ctx
->trustedCertifiers
) {
588 req
.trustedCertifiers
= calloc(1, sizeof(*req
.trustedCertifiers
));
589 if (req
.trustedCertifiers
== NULL
) {
590 krb5_set_error_string(context
, "malloc: out of memory");
591 free_PA_PK_AS_REQ(&req
);
594 ret
= build_edi(context
, ctx
->id
->hx509ctx
,
595 ctx
->id
->anchors
, req
.trustedCertifiers
);
597 krb5_set_error_string(context
, "pk-init: failed to build trustedCertifiers");
598 free_PA_PK_AS_REQ(&req
);
604 ASN1_MALLOC_ENCODE(PA_PK_AS_REQ
, buf
.data
, buf
.length
,
607 free_PA_PK_AS_REQ(&req
);
610 krb5_abortx(context
, "internal pkinit error");
612 krb5_set_error_string(context
, "PA-PK-AS-REQ %d", ret
);
615 if (buf
.length
!= size
)
616 krb5_abortx(context
, "Internal ASN1 encoder error");
618 ret
= krb5_padata_add(context
, md
, pa_type
, buf
.data
, buf
.length
);
622 if (ret
== 0 && ctx
->type
== COMPAT_WIN2K
)
623 krb5_padata_add(context
, md
, KRB5_PADATA_PK_AS_09_BINDING
, NULL
, 0);
626 free_ContentInfo(&content_info
);
632 krb5_error_code KRB5_LIB_FUNCTION
633 _krb5_pk_mk_padata(krb5_context context
,
635 const KDC_REQ_BODY
*req_body
,
639 krb5_pk_init_ctx ctx
= c
;
642 win2k_compat
= krb5_config_get_bool_default(context
, NULL
,
650 ctx
->require_binding
=
651 krb5_config_get_bool_default(context
, NULL
,
655 "pkinit_win2k_require_binding",
657 ctx
->type
= COMPAT_WIN2K
;
659 ctx
->type
= COMPAT_IETF
;
662 krb5_config_get_bool_default(context
, NULL
,
666 "pkinit_require_eku",
668 ctx
->require_krbtgt_otherName
=
669 krb5_config_get_bool_default(context
, NULL
,
673 "pkinit_require_krbtgt_otherName",
676 ctx
->require_hostname_match
=
677 krb5_config_get_bool_default(context
, NULL
,
681 "pkinit_require_hostname_match",
684 ctx
->trustedCertifiers
=
685 krb5_config_get_bool_default(context
, NULL
,
689 "pkinit_trustedCertifiers",
692 return pk_mk_padata(context
, ctx
, req_body
, nonce
, md
);
695 krb5_error_code KRB5_LIB_FUNCTION
696 _krb5_pk_verify_sign(krb5_context context
,
699 struct krb5_pk_identity
*id
,
700 heim_oid
*contentType
,
702 struct krb5_pk_cert
**signer
)
704 hx509_certs signer_certs
;
709 ret
= hx509_cms_verify_signed(id
->hx509ctx
,
719 _krb5_pk_copy_error(context
, id
->hx509ctx
, ret
,
720 "CMS verify signed failed");
724 *signer
= calloc(1, sizeof(**signer
));
725 if (*signer
== NULL
) {
726 krb5_clear_error_string(context
);
731 ret
= hx509_get_one_cert(id
->hx509ctx
, signer_certs
, &(*signer
)->cert
);
733 _krb5_pk_copy_error(context
, id
->hx509ctx
, ret
,
734 "Failed to get on of the signer certs");
739 hx509_certs_free(&signer_certs
);
742 hx509_cert_free((*signer
)->cert
);
751 static krb5_error_code
752 get_reply_key_win(krb5_context context
,
753 const krb5_data
*content
,
757 ReplyKeyPack_Win2k key_pack
;
761 ret
= decode_ReplyKeyPack_Win2k(content
->data
,
766 krb5_set_error_string(context
, "PKINIT decoding reply key failed");
767 free_ReplyKeyPack_Win2k(&key_pack
);
771 if (key_pack
.nonce
!= nonce
) {
772 krb5_set_error_string(context
, "PKINIT enckey nonce is wrong");
773 free_ReplyKeyPack_Win2k(&key_pack
);
774 return KRB5KRB_AP_ERR_MODIFIED
;
777 *key
= malloc (sizeof (**key
));
779 krb5_set_error_string(context
, "PKINIT failed allocating reply key");
780 free_ReplyKeyPack_Win2k(&key_pack
);
781 krb5_set_error_string(context
, "malloc: out of memory");
785 ret
= copy_EncryptionKey(&key_pack
.replyKey
, *key
);
786 free_ReplyKeyPack_Win2k(&key_pack
);
788 krb5_set_error_string(context
, "PKINIT failed copying reply key");
796 static krb5_error_code
797 get_reply_key(krb5_context context
,
798 const krb5_data
*content
,
799 const krb5_data
*req_buffer
,
802 ReplyKeyPack key_pack
;
806 ret
= decode_ReplyKeyPack(content
->data
,
811 krb5_set_error_string(context
, "PKINIT decoding reply key failed");
812 free_ReplyKeyPack(&key_pack
);
820 * XXX Verify kp.replyKey is a allowed enctype in the
824 ret
= krb5_crypto_init(context
, &key_pack
.replyKey
, 0, &crypto
);
826 free_ReplyKeyPack(&key_pack
);
830 ret
= krb5_verify_checksum(context
, crypto
, 6,
831 req_buffer
->data
, req_buffer
->length
,
832 &key_pack
.asChecksum
);
833 krb5_crypto_destroy(context
, crypto
);
835 free_ReplyKeyPack(&key_pack
);
840 *key
= malloc (sizeof (**key
));
842 krb5_set_error_string(context
, "PKINIT failed allocating reply key");
843 free_ReplyKeyPack(&key_pack
);
844 krb5_set_error_string(context
, "malloc: out of memory");
848 ret
= copy_EncryptionKey(&key_pack
.replyKey
, *key
);
849 free_ReplyKeyPack(&key_pack
);
851 krb5_set_error_string(context
, "PKINIT failed copying reply key");
860 static krb5_error_code
861 pk_verify_host(krb5_context context
,
863 const krb5_krbhst_info
*hi
,
864 struct krb5_pk_init_ctx_data
*ctx
,
865 struct krb5_pk_cert
*host
)
867 krb5_error_code ret
= 0;
869 if (ctx
->require_eku
) {
870 ret
= hx509_cert_check_eku(ctx
->id
->hx509ctx
, host
->cert
,
871 oid_id_pkkdcekuoid(), 0);
873 krb5_set_error_string(context
, "No PK-INIT KDC EKU in kdc certificate");
877 if (ctx
->require_krbtgt_otherName
) {
878 hx509_octet_string_list list
;
881 ret
= hx509_cert_find_subjectAltName_otherName(ctx
->id
->hx509ctx
,
886 krb5_set_error_string(context
, "Failed to find the PK-INIT "
887 "subjectAltName in the KDC certificate");
892 for (i
= 0; i
< list
.len
; i
++) {
895 ret
= decode_KRB5PrincipalName(list
.val
[i
].data
,
900 krb5_set_error_string(context
, "Failed to decode the PK-INIT "
901 "subjectAltName in the KDC certificate");
906 if (r
.principalName
.name_string
.len
!= 2 ||
907 strcmp(r
.principalName
.name_string
.val
[0], KRB5_TGS_NAME
) != 0 ||
908 strcmp(r
.principalName
.name_string
.val
[1], realm
) != 0 ||
909 strcmp(r
.realm
, realm
) != 0)
911 krb5_set_error_string(context
, "KDC have wrong realm name in "
913 ret
= KRB5_KDC_ERR_INVALID_CERTIFICATE
;
916 free_KRB5PrincipalName(&r
);
920 hx509_free_octet_string_list(&list
);
926 ret
= hx509_verify_hostname(ctx
->id
->hx509ctx
, host
->cert
,
927 ctx
->require_hostname_match
,
930 hi
->ai
->ai_addr
, hi
->ai
->ai_addrlen
);
933 krb5_set_error_string(context
, "Address mismatch in "
934 "the KDC certificate");
939 static krb5_error_code
940 pk_rd_pa_reply_enckey(krb5_context context
,
942 const heim_octet_string
*indata
,
943 const heim_oid
*dataType
,
945 krb5_pk_init_ctx ctx
,
947 const krb5_krbhst_info
*hi
,
949 const krb5_data
*req_buffer
,
954 struct krb5_pk_cert
*host
= NULL
;
956 heim_oid contentType
= { 0, NULL
};
958 if (der_heim_oid_cmp(oid_id_pkcs7_envelopedData(), dataType
)) {
959 krb5_set_error_string(context
, "PKINIT: Invalid content type");
963 ret
= hx509_cms_unenvelope(ctx
->id
->hx509ctx
,
965 HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT
,
972 _krb5_pk_copy_error(context
, ctx
->id
->hx509ctx
, ret
,
973 "Failed to unenvelope CMS data in PK-INIT reply");
976 der_free_oid(&contentType
);
978 #if 0 /* windows LH with interesting CMS packets, leaks memory */
980 size_t ph
= 1 + der_length_len (length
);
981 unsigned char *ptr
= malloc(length
+ ph
);
984 memcpy(ptr
+ ph
, p
, length
);
986 ret
= der_put_length_and_tag (ptr
+ ph
- 1, ph
, length
,
987 ASN1_C_UNIV
, CONS
, UT_Sequence
, &l
);
996 /* win2k uses ContentInfo */
997 if (type
== COMPAT_WIN2K
) {
999 heim_octet_string out
;
1001 ret
= hx509_cms_unwrap_ContentInfo(&content
, &type
, &out
, NULL
);
1002 if (der_heim_oid_cmp(&type
, oid_id_pkcs7_signedData())) {
1003 ret
= EINVAL
; /* XXX */
1004 krb5_set_error_string(context
, "PKINIT: Invalid content type");
1005 der_free_oid(&type
);
1006 der_free_octet_string(&out
);
1009 der_free_oid(&type
);
1010 krb5_data_free(&content
);
1011 ret
= krb5_data_copy(&content
, out
.data
, out
.length
);
1012 der_free_octet_string(&out
);
1014 krb5_set_error_string(context
, "PKINIT: out of memory");
1019 ret
= _krb5_pk_verify_sign(context
,
1029 /* make sure that it is the kdc's certificate */
1030 ret
= pk_verify_host(context
, realm
, hi
, ctx
, host
);
1036 if (type
== COMPAT_WIN2K
) {
1037 if (der_heim_oid_cmp(&contentType
, oid_id_pkcs7_data()) != 0) {
1038 krb5_set_error_string(context
, "PKINIT: reply key, wrong oid");
1039 ret
= KRB5KRB_AP_ERR_MSG_TYPE
;
1043 if (der_heim_oid_cmp(&contentType
, oid_id_pkrkeydata()) != 0) {
1044 krb5_set_error_string(context
, "PKINIT: reply key, wrong oid");
1045 ret
= KRB5KRB_AP_ERR_MSG_TYPE
;
1053 ret
= get_reply_key(context
, &content
, req_buffer
, key
);
1054 if (ret
!= 0 && ctx
->require_binding
== 0)
1055 ret
= get_reply_key_win(context
, &content
, nonce
, key
);
1058 ret
= get_reply_key(context
, &content
, req_buffer
, key
);
1064 /* XXX compare given etype with key->etype */
1068 _krb5_pk_cert_free(host
);
1069 der_free_oid(&contentType
);
1070 krb5_data_free(&content
);
1075 static krb5_error_code
1076 pk_rd_pa_reply_dh(krb5_context context
,
1077 const heim_octet_string
*indata
,
1078 const heim_oid
*dataType
,
1080 krb5_pk_init_ctx ctx
,
1082 const krb5_krbhst_info
*hi
,
1087 krb5_keyblock
**key
)
1089 unsigned char *p
, *dh_gen_key
= NULL
;
1090 struct krb5_pk_cert
*host
= NULL
;
1091 BIGNUM
*kdc_dh_pubkey
= NULL
;
1092 KDCDHKeyInfo kdc_dh_info
;
1093 heim_oid contentType
= { 0, NULL
};
1095 krb5_error_code ret
;
1099 krb5_data_zero(&content
);
1100 memset(&kdc_dh_info
, 0, sizeof(kdc_dh_info
));
1102 if (der_heim_oid_cmp(oid_id_pkcs7_signedData(), dataType
)) {
1103 krb5_set_error_string(context
, "PKINIT: Invalid content type");
1107 ret
= _krb5_pk_verify_sign(context
,
1117 /* make sure that it is the kdc's certificate */
1118 ret
= pk_verify_host(context
, realm
, hi
, ctx
, host
);
1122 if (der_heim_oid_cmp(&contentType
, oid_id_pkdhkeydata())) {
1123 krb5_set_error_string(context
, "pkinit - dh reply contains wrong oid");
1124 ret
= KRB5KRB_AP_ERR_MSG_TYPE
;
1128 ret
= decode_KDCDHKeyInfo(content
.data
,
1134 krb5_set_error_string(context
, "pkinit - "
1135 "failed to decode KDC DH Key Info");
1139 if (kdc_dh_info
.nonce
!= nonce
) {
1140 krb5_set_error_string(context
, "PKINIT: DH nonce is wrong");
1141 ret
= KRB5KRB_AP_ERR_MODIFIED
;
1145 if (kdc_dh_info
.dhKeyExpiration
) {
1147 krb5_set_error_string(context
, "pkinit; got key expiration "
1148 "without server nonce");
1149 ret
= KRB5KRB_ERR_GENERIC
;
1153 krb5_set_error_string(context
, "pkinit; got DH reuse but no "
1155 ret
= KRB5KRB_ERR_GENERIC
;
1160 krb5_set_error_string(context
, "pkinit: got server nonce "
1161 "without key expiration");
1162 ret
= KRB5KRB_ERR_GENERIC
;
1169 p
= kdc_dh_info
.subjectPublicKey
.data
;
1170 size
= (kdc_dh_info
.subjectPublicKey
.length
+ 7) / 8;
1174 ret
= decode_DHPublicKey(p
, size
, &k
, NULL
);
1176 krb5_set_error_string(context
, "pkinit: can't decode "
1177 "without key expiration");
1181 kdc_dh_pubkey
= integer_to_BN(context
, "DHPublicKey", &k
);
1182 free_DHPublicKey(&k
);
1183 if (kdc_dh_pubkey
== NULL
) {
1184 ret
= KRB5KRB_ERR_GENERIC
;
1189 dh_gen_keylen
= DH_size(ctx
->dh
);
1190 size
= BN_num_bytes(ctx
->dh
->p
);
1191 if (size
< dh_gen_keylen
)
1192 size
= dh_gen_keylen
;
1194 dh_gen_key
= malloc(size
);
1195 if (dh_gen_key
== NULL
) {
1196 krb5_set_error_string(context
, "malloc: out of memory");
1200 memset(dh_gen_key
, 0, size
- dh_gen_keylen
);
1202 dh_gen_keylen
= DH_compute_key(dh_gen_key
+ (size
- dh_gen_keylen
),
1203 kdc_dh_pubkey
, ctx
->dh
);
1204 if (dh_gen_keylen
== -1) {
1205 krb5_set_error_string(context
,
1206 "PKINIT: Can't compute Diffie-Hellman key");
1207 ret
= KRB5KRB_ERR_GENERIC
;
1211 *key
= malloc (sizeof (**key
));
1213 krb5_set_error_string(context
, "malloc: out of memory");
1218 ret
= _krb5_pk_octetstring2key(context
,
1220 dh_gen_key
, dh_gen_keylen
,
1224 krb5_set_error_string(context
,
1225 "PKINIT: can't create key from DH key");
1233 BN_free(kdc_dh_pubkey
);
1235 memset(dh_gen_key
, 0, DH_size(ctx
->dh
));
1239 _krb5_pk_cert_free(host
);
1241 krb5_data_free(&content
);
1242 der_free_oid(&contentType
);
1243 free_KDCDHKeyInfo(&kdc_dh_info
);
1248 krb5_error_code KRB5_LIB_FUNCTION
1249 _krb5_pk_rd_pa_reply(krb5_context context
,
1253 const krb5_krbhst_info
*hi
,
1255 const krb5_data
*req_buffer
,
1257 krb5_keyblock
**key
)
1259 krb5_pk_init_ctx ctx
= c
;
1260 krb5_error_code ret
;
1263 /* Check for IETF PK-INIT first */
1264 if (ctx
->type
== COMPAT_IETF
) {
1266 heim_octet_string os
, data
;
1269 if (pa
->padata_type
!= KRB5_PADATA_PK_AS_REP
) {
1270 krb5_set_error_string(context
, "PKINIT: wrong padata recv");
1274 ret
= decode_PA_PK_AS_REP(pa
->padata_value
.data
,
1275 pa
->padata_value
.length
,
1279 krb5_set_error_string(context
, "Failed to decode pkinit AS rep");
1283 switch (rep
.element
) {
1284 case choice_PA_PK_AS_REP_dhInfo
:
1285 os
= rep
.u
.dhInfo
.dhSignedData
;
1287 case choice_PA_PK_AS_REP_encKeyPack
:
1288 os
= rep
.u
.encKeyPack
;
1291 free_PA_PK_AS_REP(&rep
);
1292 krb5_set_error_string(context
, "PKINIT: -27 reply "
1293 "invalid content type");
1297 ret
= hx509_cms_unwrap_ContentInfo(&os
, &oid
, &data
, NULL
);
1299 free_PA_PK_AS_REP(&rep
);
1300 krb5_set_error_string(context
, "PKINIT: failed to unwrap CI");
1304 switch (rep
.element
) {
1305 case choice_PA_PK_AS_REP_dhInfo
:
1306 ret
= pk_rd_pa_reply_dh(context
, &data
, &oid
, realm
, ctx
, etype
, hi
,
1308 rep
.u
.dhInfo
.serverDHNonce
,
1311 case choice_PA_PK_AS_REP_encKeyPack
:
1312 ret
= pk_rd_pa_reply_enckey(context
, COMPAT_IETF
, &data
, &oid
, realm
,
1313 ctx
, etype
, hi
, nonce
, req_buffer
, pa
, key
);
1316 krb5_abortx(context
, "pk-init as-rep case not possible to happen");
1318 der_free_octet_string(&data
);
1320 free_PA_PK_AS_REP(&rep
);
1322 } else if (ctx
->type
== COMPAT_WIN2K
) {
1323 PA_PK_AS_REP_Win2k w2krep
;
1325 /* Check for Windows encoding of the AS-REP pa data */
1327 #if 0 /* should this be ? */
1328 if (pa
->padata_type
!= KRB5_PADATA_PK_AS_REP
) {
1329 krb5_set_error_string(context
, "PKINIT: wrong padata recv");
1334 memset(&w2krep
, 0, sizeof(w2krep
));
1336 ret
= decode_PA_PK_AS_REP_Win2k(pa
->padata_value
.data
,
1337 pa
->padata_value
.length
,
1341 krb5_set_error_string(context
, "PKINIT: Failed decoding windows "
1342 "pkinit reply %d", ret
);
1346 krb5_clear_error_string(context
);
1348 switch (w2krep
.element
) {
1349 case choice_PA_PK_AS_REP_Win2k_encKeyPack
: {
1350 heim_octet_string data
;
1353 ret
= hx509_cms_unwrap_ContentInfo(&w2krep
.u
.encKeyPack
,
1355 free_PA_PK_AS_REP_Win2k(&w2krep
);
1357 krb5_set_error_string(context
, "PKINIT: failed to unwrap CI");
1361 ret
= pk_rd_pa_reply_enckey(context
, COMPAT_WIN2K
, &data
, &oid
, realm
,
1362 ctx
, etype
, hi
, nonce
, req_buffer
, pa
, key
);
1363 der_free_octet_string(&data
);
1369 free_PA_PK_AS_REP_Win2k(&w2krep
);
1370 krb5_set_error_string(context
, "PKINIT: win2k reply invalid "
1377 krb5_set_error_string(context
, "PKINIT: unknown reply type");
1385 krb5_context context
;
1386 krb5_prompter_fct prompter
;
1387 void *prompter_data
;
1391 hx_pass_prompter(void *data
, const hx509_prompt
*prompter
)
1393 krb5_error_code ret
;
1395 krb5_data password_data
;
1396 struct prompter
*p
= data
;
1398 password_data
.data
= prompter
->reply
.data
;
1399 password_data
.length
= prompter
->reply
.length
;
1401 prompt
.prompt
= prompter
->prompt
;
1402 prompt
.hidden
= hx509_prompt_hidden(prompter
->type
);
1403 prompt
.reply
= &password_data
;
1405 switch (prompter
->type
) {
1406 case HX509_PROMPT_TYPE_INFO
:
1407 prompt
.type
= KRB5_PROMPT_TYPE_INFO
;
1409 case HX509_PROMPT_TYPE_PASSWORD
:
1410 case HX509_PROMPT_TYPE_QUESTION
:
1412 prompt
.type
= KRB5_PROMPT_TYPE_PASSWORD
;
1416 ret
= (*p
->prompter
)(p
->context
, p
->prompter_data
, NULL
, NULL
, 1, &prompt
);
1418 memset (prompter
->reply
.data
, 0, prompter
->reply
.length
);
1425 void KRB5_LIB_FUNCTION
1426 _krb5_pk_allow_proxy_certificate(struct krb5_pk_identity
*id
,
1429 hx509_verify_set_proxy_certificate(id
->verify_ctx
, boolean
);
1433 krb5_error_code KRB5_LIB_FUNCTION
1434 _krb5_pk_load_id(krb5_context context
,
1435 struct krb5_pk_identity
**ret_id
,
1436 const char *user_id
,
1437 const char *anchor_id
,
1438 char * const *chain_list
,
1439 char * const *revoke_list
,
1440 krb5_prompter_fct prompter
,
1441 void *prompter_data
,
1444 struct krb5_pk_identity
*id
= NULL
;
1445 hx509_lock lock
= NULL
;
1451 if (anchor_id
== NULL
) {
1452 krb5_set_error_string(context
, "PKINIT: No anchor given");
1453 return HEIM_PKINIT_NO_VALID_CA
;
1456 if (user_id
== NULL
) {
1457 krb5_set_error_string(context
,
1458 "PKINIT: No user certificate given");
1459 return HEIM_PKINIT_NO_PRIVATE_KEY
;
1464 id
= calloc(1, sizeof(*id
));
1466 krb5_set_error_string(context
, "malloc: out of memory");
1470 ret
= hx509_context_init(&id
->hx509ctx
);
1474 ret
= hx509_lock_init(id
->hx509ctx
, &lock
);
1475 if (password
&& password
[0])
1476 hx509_lock_add_password(lock
, password
);
1479 p
.context
= context
;
1480 p
.prompter
= prompter
;
1481 p
.prompter_data
= prompter_data
;
1483 ret
= hx509_lock_set_prompter(lock
, hx_pass_prompter
, &p
);
1488 ret
= hx509_certs_init(id
->hx509ctx
, user_id
, 0, lock
, &id
->certs
);
1490 _krb5_pk_copy_error(context
, id
->hx509ctx
, ret
,
1491 "Failed to init cert certs");
1495 ret
= hx509_certs_init(id
->hx509ctx
, anchor_id
, 0, NULL
, &id
->anchors
);
1497 _krb5_pk_copy_error(context
, id
->hx509ctx
, ret
,
1498 "Failed to init anchors");
1502 ret
= hx509_certs_init(id
->hx509ctx
, "MEMORY:pkinit-cert-chain",
1503 0, NULL
, &id
->certpool
);
1505 _krb5_pk_copy_error(context
, id
->hx509ctx
, ret
,
1506 "Failed to init chain");
1510 while (chain_list
&& *chain_list
) {
1511 ret
= hx509_certs_append(id
->hx509ctx
, id
->certpool
,
1514 _krb5_pk_copy_error(context
, id
->hx509ctx
, ret
,
1515 "Failed to laod chain %s",
1523 ret
= hx509_revoke_init(id
->hx509ctx
, &id
->revokectx
);
1525 _krb5_pk_copy_error(context
, id
->hx509ctx
, ret
,
1526 "Failed init revoke list");
1530 while (*revoke_list
) {
1531 ret
= hx509_revoke_add_crl(id
->hx509ctx
,
1535 _krb5_pk_copy_error(context
, id
->hx509ctx
, ret
,
1536 "Failed load revoke list");
1542 hx509_context_set_missing_revoke(id
->hx509ctx
, 1);
1544 ret
= hx509_verify_init_ctx(id
->hx509ctx
, &id
->verify_ctx
);
1546 _krb5_pk_copy_error(context
, id
->hx509ctx
, ret
,
1547 "Failed init verify context");
1551 hx509_verify_attach_anchors(id
->verify_ctx
, id
->anchors
);
1552 hx509_verify_attach_revoke(id
->verify_ctx
, id
->revokectx
);
1556 hx509_verify_destroy_ctx(id
->verify_ctx
);
1557 hx509_certs_free(&id
->certs
);
1558 hx509_certs_free(&id
->anchors
);
1559 hx509_certs_free(&id
->certpool
);
1560 hx509_revoke_free(&id
->revokectx
);
1561 hx509_context_free(&id
->hx509ctx
);
1566 hx509_lock_free(lock
);
1571 static krb5_error_code
1572 select_dh_group(krb5_context context
, DH
*dh
, unsigned long bits
,
1573 struct krb5_dh_moduli
**moduli
)
1575 const struct krb5_dh_moduli
*m
;
1578 m
= moduli
[1]; /* XXX */
1580 m
= moduli
[0]; /* XXX */
1583 for (i
= 0; moduli
[i
] != NULL
; i
++) {
1584 if (bits
< moduli
[i
]->bits
)
1587 if (moduli
[i
] == NULL
) {
1588 krb5_set_error_string(context
,
1589 "Did not find a DH group parameter "
1590 "matching requirement of %lu bits",
1597 dh
->p
= integer_to_BN(context
, "p", &m
->p
);
1600 dh
->g
= integer_to_BN(context
, "g", &m
->g
);
1603 dh
->q
= integer_to_BN(context
, "q", &m
->q
);
1613 parse_integer(krb5_context context
, char **p
, const char *file
, int lineno
,
1614 const char *name
, heim_integer
*integer
)
1618 p1
= strsep(p
, " \t");
1620 krb5_set_error_string(context
, "moduli file %s missing %s on line %d",
1621 file
, name
, lineno
);
1624 ret
= der_parse_hex_heim_integer(p1
, integer
);
1626 krb5_set_error_string(context
, "moduli file %s failed parsing %s "
1628 file
, name
, lineno
);
1636 _krb5_parse_moduli_line(krb5_context context
,
1640 struct krb5_dh_moduli
**m
)
1642 struct krb5_dh_moduli
*m1
;
1648 m1
= calloc(1, sizeof(*m1
));
1650 krb5_set_error_string(context
, "malloc - out of memory");
1654 while (isspace((unsigned char)*p
))
1660 p1
= strsep(&p
, " \t");
1662 krb5_set_error_string(context
, "moduli file %s missing name "
1663 "on line %d", file
, lineno
);
1666 m1
->name
= strdup(p1
);
1668 krb5_set_error_string(context
, "malloc - out of memeory");
1673 p1
= strsep(&p
, " \t");
1675 krb5_set_error_string(context
, "moduli file %s missing bits on line %d",
1680 m1
->bits
= atoi(p1
);
1681 if (m1
->bits
== 0) {
1682 krb5_set_error_string(context
, "moduli file %s have un-parsable "
1683 "bits on line %d", file
, lineno
);
1687 ret
= parse_integer(context
, &p
, file
, lineno
, "p", &m1
->p
);
1690 ret
= parse_integer(context
, &p
, file
, lineno
, "g", &m1
->g
);
1693 ret
= parse_integer(context
, &p
, file
, lineno
, "q", &m1
->q
);
1702 der_free_heim_integer(&m1
->p
);
1703 der_free_heim_integer(&m1
->g
);
1704 der_free_heim_integer(&m1
->q
);
1710 _krb5_free_moduli(struct krb5_dh_moduli
**moduli
)
1713 for (i
= 0; moduli
[i
] != NULL
; i
++) {
1714 free(moduli
[i
]->name
);
1715 der_free_heim_integer(&moduli
[i
]->p
);
1716 der_free_heim_integer(&moduli
[i
]->g
);
1717 der_free_heim_integer(&moduli
[i
]->q
);
1723 static const char *default_moduli_RFC2412_MODP_group2
=
1725 "RFC2412-MODP-group2 "
1729 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
1730 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
1731 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
1732 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
1733 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
1734 "FFFFFFFF" "FFFFFFFF "
1738 "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68"
1739 "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E"
1740 "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122"
1741 "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6"
1742 "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F67329C0"
1743 "FFFFFFFF" "FFFFFFFF";
1745 static const char *default_moduli_rfc3526_MODP_group14
=
1747 "rfc3526-MODP-group14 "
1751 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
1752 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
1753 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
1754 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
1755 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D"
1756 "C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"
1757 "83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"
1758 "670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"
1759 "E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"
1760 "DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
1761 "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF "
1765 "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68"
1766 "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E"
1767 "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122"
1768 "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6"
1769 "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F6722D9E"
1770 "E1003E5C" "50B1DF82" "CC6D241B" "0E2AE9CD" "348B1FD4" "7E9267AF"
1771 "C1B2AE91" "EE51D6CB" "0E3179AB" "1042A95D" "CF6A9483" "B84B4B36"
1772 "B3861AA7" "255E4C02" "78BA3604" "650C10BE" "19482F23" "171B671D"
1773 "F1CF3B96" "0C074301" "CD93C1D1" "7603D147" "DAE2AEF8" "37A62964"
1774 "EF15E5FB" "4AAC0B8C" "1CCAA4BE" "754AB572" "8AE9130C" "4C7D0288"
1775 "0AB9472D" "45565534" "7FFFFFFF" "FFFFFFFF";
1778 _krb5_parse_moduli(krb5_context context
, const char *file
,
1779 struct krb5_dh_moduli
***moduli
)
1781 /* name bits P G Q */
1782 krb5_error_code ret
;
1783 struct krb5_dh_moduli
**m
= NULL
, **m2
;
1786 int lineno
= 0, n
= 0;
1790 m
= calloc(1, sizeof(m
[0]) * 3);
1792 krb5_set_error_string(context
, "malloc: out of memory");
1796 strlcpy(buf
, default_moduli_rfc3526_MODP_group14
, sizeof(buf
));
1797 ret
= _krb5_parse_moduli_line(context
, "builtin", 1, buf
, &m
[0]);
1799 _krb5_free_moduli(m
);
1804 strlcpy(buf
, default_moduli_RFC2412_MODP_group2
, sizeof(buf
));
1805 ret
= _krb5_parse_moduli_line(context
, "builtin", 1, buf
, &m
[1]);
1807 _krb5_free_moduli(m
);
1816 f
= fopen(file
, "r");
1822 while(fgets(buf
, sizeof(buf
), f
) != NULL
) {
1823 struct krb5_dh_moduli
*element
;
1825 buf
[strcspn(buf
, "\n")] = '\0';
1828 m2
= realloc(m
, (n
+ 2) * sizeof(m
[0]));
1830 krb5_set_error_string(context
, "malloc: out of memory");
1831 _krb5_free_moduli(m
);
1838 ret
= _krb5_parse_moduli_line(context
, file
, lineno
, buf
, &element
);
1840 _krb5_free_moduli(m
);
1843 if (element
== NULL
)
1855 _krb5_dh_group_ok(krb5_context context
, unsigned long bits
,
1856 heim_integer
*p
, heim_integer
*g
, heim_integer
*q
,
1857 struct krb5_dh_moduli
**moduli
,
1865 for (i
= 0; moduli
[i
] != NULL
; i
++) {
1866 if (der_heim_integer_cmp(&moduli
[i
]->g
, g
) == 0 &&
1867 der_heim_integer_cmp(&moduli
[i
]->p
, p
) == 0 &&
1868 (q
== NULL
|| der_heim_integer_cmp(&moduli
[i
]->q
, q
) == 0))
1870 if (bits
&& bits
> moduli
[i
]->bits
) {
1871 krb5_set_error_string(context
, "PKINIT: DH group parameter %s "
1872 "no accepted, not enough bits generated",
1874 return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED
;
1877 *name
= strdup(moduli
[i
]->name
);
1881 krb5_set_error_string(context
, "PKINIT: DH group parameter no ok");
1882 return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED
;
1885 void KRB5_LIB_FUNCTION
1886 _krb5_get_init_creds_opt_free_pkinit(krb5_get_init_creds_opt
*opt
)
1889 krb5_pk_init_ctx ctx
;
1891 if (opt
->opt_private
== NULL
|| opt
->opt_private
->pk_init_ctx
== NULL
)
1893 ctx
= opt
->opt_private
->pk_init_ctx
;
1898 hx509_verify_destroy_ctx(ctx
->id
->verify_ctx
);
1899 hx509_certs_free(&ctx
->id
->certs
);
1900 hx509_certs_free(&ctx
->id
->anchors
);
1901 hx509_certs_free(&ctx
->id
->certpool
);
1902 hx509_context_free(&ctx
->id
->hx509ctx
);
1904 if (ctx
->clientDHNonce
) {
1905 krb5_free_data(NULL
, ctx
->clientDHNonce
);
1906 ctx
->clientDHNonce
= NULL
;
1909 _krb5_free_moduli(ctx
->m
);
1913 free(opt
->opt_private
->pk_init_ctx
);
1914 opt
->opt_private
->pk_init_ctx
= NULL
;
1918 krb5_error_code KRB5_LIB_FUNCTION
1919 krb5_get_init_creds_opt_set_pkinit(krb5_context context
,
1920 krb5_get_init_creds_opt
*opt
,
1921 krb5_principal principal
,
1922 const char *user_id
,
1923 const char *x509_anchors
,
1924 char * const * pool
,
1925 char * const * pki_revoke
,
1927 krb5_prompter_fct prompter
,
1928 void *prompter_data
,
1932 krb5_error_code ret
;
1933 char *anchors
= NULL
;
1935 if (opt
->opt_private
== NULL
) {
1936 krb5_set_error_string(context
, "PKINIT: on non extendable opt");
1940 opt
->opt_private
->pk_init_ctx
=
1941 calloc(1, sizeof(*opt
->opt_private
->pk_init_ctx
));
1942 if (opt
->opt_private
->pk_init_ctx
== NULL
) {
1943 krb5_set_error_string(context
, "malloc: out of memory");
1946 opt
->opt_private
->pk_init_ctx
->dh
= NULL
;
1947 opt
->opt_private
->pk_init_ctx
->id
= NULL
;
1948 opt
->opt_private
->pk_init_ctx
->clientDHNonce
= NULL
;
1949 opt
->opt_private
->pk_init_ctx
->require_binding
= 0;
1950 opt
->opt_private
->pk_init_ctx
->require_eku
= 1;
1951 opt
->opt_private
->pk_init_ctx
->require_krbtgt_otherName
= 1;
1952 opt
->opt_private
->pk_init_ctx
->peer
= NULL
;
1954 /* XXX implement krb5_appdefault_strings */
1956 pool
= krb5_config_get_strings(context
, NULL
,
1961 if (pki_revoke
== NULL
)
1962 pki_revoke
= krb5_config_get_strings(context
, NULL
,
1967 if (x509_anchors
== NULL
) {
1968 krb5_appdefault_string(context
, "kinit",
1969 krb5_principal_get_realm(context
, principal
),
1970 "pkinit_anchors", NULL
, &anchors
);
1971 x509_anchors
= anchors
;
1974 ret
= _krb5_pk_load_id(context
,
1975 &opt
->opt_private
->pk_init_ctx
->id
,
1984 free(opt
->opt_private
->pk_init_ctx
);
1985 opt
->opt_private
->pk_init_ctx
= NULL
;
1989 if ((flags
& 2) == 0) {
1990 const char *moduli_file
;
1991 unsigned long dh_min_bits
;
1993 moduli_file
= krb5_config_get_string(context
, NULL
,
1999 krb5_config_get_int_default(context
, NULL
, 0,
2001 "pkinit_dh_min_bits",
2004 ret
= _krb5_parse_moduli(context
, moduli_file
,
2005 &opt
->opt_private
->pk_init_ctx
->m
);
2007 _krb5_get_init_creds_opt_free_pkinit(opt
);
2011 opt
->opt_private
->pk_init_ctx
->dh
= DH_new();
2012 if (opt
->opt_private
->pk_init_ctx
->dh
== NULL
) {
2013 krb5_set_error_string(context
, "malloc: out of memory");
2014 _krb5_get_init_creds_opt_free_pkinit(opt
);
2018 ret
= select_dh_group(context
, opt
->opt_private
->pk_init_ctx
->dh
,
2020 opt
->opt_private
->pk_init_ctx
->m
);
2022 _krb5_get_init_creds_opt_free_pkinit(opt
);
2026 if (DH_generate_key(opt
->opt_private
->pk_init_ctx
->dh
) != 1) {
2027 krb5_set_error_string(context
, "pkinit: failed to generate DH key");
2028 _krb5_get_init_creds_opt_free_pkinit(opt
);
2035 krb5_set_error_string(context
, "no support for PKINIT compiled in");
2045 _krb5_pk_copy_error(krb5_context context
,
2046 hx509_context hx509ctx
,
2055 vasprintf(&f
, fmt
, va
);
2058 krb5_clear_error_string(context
);
2062 s
= hx509_get_error_string(hx509ctx
, hxret
);
2064 krb5_clear_error_string(context
);
2068 krb5_set_error_string(context
, "%s: %s", f
, s
);