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"
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_string(context
, "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_string(context
, "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_string(context
, "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_string(context
, "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_string(context
,
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
) {
610 krb5_set_error_string(context
, "malloc: out of memory");
611 free_PA_PK_AS_REQ(&req
);
614 ret
= build_edi(context
, ctx
->id
->hx509ctx
,
615 ctx
->id
->anchors
, req
.trustedCertifiers
);
617 krb5_set_error_string(context
, "pk-init: failed to build trustedCertifiers");
618 free_PA_PK_AS_REQ(&req
);
624 ASN1_MALLOC_ENCODE(PA_PK_AS_REQ
, buf
.data
, buf
.length
,
627 free_PA_PK_AS_REQ(&req
);
630 krb5_abortx(context
, "internal pkinit error");
632 krb5_set_error_string(context
, "PA-PK-AS-REQ %d", (int)ret
);
635 if (buf
.length
!= size
)
636 krb5_abortx(context
, "Internal ASN1 encoder error");
638 ret
= krb5_padata_add(context
, md
, pa_type
, buf
.data
, buf
.length
);
642 if (ret
== 0 && ctx
->type
== PKINIT_WIN2K
)
643 krb5_padata_add(context
, md
, KRB5_PADATA_PK_AS_09_BINDING
, NULL
, 0);
646 free_ContentInfo(&content_info
);
652 krb5_error_code KRB5_LIB_FUNCTION
653 _krb5_pk_mk_padata(krb5_context context
,
655 const KDC_REQ_BODY
*req_body
,
659 krb5_pk_init_ctx ctx
= c
;
662 win2k_compat
= krb5_config_get_bool_default(context
, NULL
,
670 ctx
->require_binding
=
671 krb5_config_get_bool_default(context
, NULL
,
675 "pkinit_win2k_require_binding",
677 ctx
->type
= PKINIT_WIN2K
;
679 ctx
->type
= PKINIT_27
;
682 krb5_config_get_bool_default(context
, NULL
,
686 "pkinit_require_eku",
688 ctx
->require_krbtgt_otherName
=
689 krb5_config_get_bool_default(context
, NULL
,
693 "pkinit_require_krbtgt_otherName",
696 ctx
->require_hostname_match
=
697 krb5_config_get_bool_default(context
, NULL
,
701 "pkinit_require_hostname_match",
704 ctx
->trustedCertifiers
=
705 krb5_config_get_bool_default(context
, NULL
,
709 "pkinit_trustedCertifiers",
712 return pk_mk_padata(context
, ctx
, req_body
, nonce
, md
);
715 krb5_error_code KRB5_LIB_FUNCTION
716 _krb5_pk_verify_sign(krb5_context context
,
719 struct krb5_pk_identity
*id
,
720 heim_oid
*contentType
,
722 struct krb5_pk_cert
**signer
)
724 hx509_certs signer_certs
;
729 ret
= hx509_cms_verify_signed(id
->hx509ctx
,
739 pk_copy_error(context
, id
->hx509ctx
, ret
,
740 "CMS verify signed failed");
744 *signer
= calloc(1, sizeof(**signer
));
745 if (*signer
== NULL
) {
746 krb5_clear_error_string(context
);
751 ret
= hx509_get_one_cert(id
->hx509ctx
, signer_certs
, &(*signer
)->cert
);
753 pk_copy_error(context
, id
->hx509ctx
, ret
,
754 "Failed to get on of the signer certs");
759 hx509_certs_free(&signer_certs
);
762 hx509_cert_free((*signer
)->cert
);
771 static krb5_error_code
772 get_reply_key_win(krb5_context context
,
773 const krb5_data
*content
,
777 ReplyKeyPack_Win2k key_pack
;
781 ret
= decode_ReplyKeyPack_Win2k(content
->data
,
786 krb5_set_error_string(context
, "PKINIT decoding reply key failed");
787 free_ReplyKeyPack_Win2k(&key_pack
);
791 if (key_pack
.nonce
!= nonce
) {
792 krb5_set_error_string(context
, "PKINIT enckey nonce is wrong");
793 free_ReplyKeyPack_Win2k(&key_pack
);
794 return KRB5KRB_AP_ERR_MODIFIED
;
797 *key
= malloc (sizeof (**key
));
799 krb5_set_error_string(context
, "PKINIT failed allocating reply key");
800 free_ReplyKeyPack_Win2k(&key_pack
);
801 krb5_set_error_string(context
, "malloc: out of memory");
805 ret
= copy_EncryptionKey(&key_pack
.replyKey
, *key
);
806 free_ReplyKeyPack_Win2k(&key_pack
);
808 krb5_set_error_string(context
, "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_string(context
, "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 krb5_set_error_string(context
, "PKINIT failed allocating reply key");
863 free_ReplyKeyPack(&key_pack
);
864 krb5_set_error_string(context
, "malloc: out of memory");
868 ret
= copy_EncryptionKey(&key_pack
.replyKey
, *key
);
869 free_ReplyKeyPack(&key_pack
);
871 krb5_set_error_string(context
, "PKINIT failed copying reply key");
880 static krb5_error_code
881 pk_verify_host(krb5_context context
,
883 const krb5_krbhst_info
*hi
,
884 struct krb5_pk_init_ctx_data
*ctx
,
885 struct krb5_pk_cert
*host
)
887 krb5_error_code ret
= 0;
889 if (ctx
->require_eku
) {
890 ret
= hx509_cert_check_eku(ctx
->id
->hx509ctx
, host
->cert
,
891 oid_id_pkkdcekuoid(), 0);
893 krb5_set_error_string(context
, "No PK-INIT KDC EKU in kdc certificate");
897 if (ctx
->require_krbtgt_otherName
) {
898 hx509_octet_string_list list
;
901 ret
= hx509_cert_find_subjectAltName_otherName(ctx
->id
->hx509ctx
,
906 krb5_set_error_string(context
, "Failed to find the PK-INIT "
907 "subjectAltName in the KDC certificate");
912 for (i
= 0; i
< list
.len
; i
++) {
915 ret
= decode_KRB5PrincipalName(list
.val
[i
].data
,
920 krb5_set_error_string(context
, "Failed to decode the PK-INIT "
921 "subjectAltName in the KDC certificate");
926 if (r
.principalName
.name_string
.len
!= 2 ||
927 strcmp(r
.principalName
.name_string
.val
[0], KRB5_TGS_NAME
) != 0 ||
928 strcmp(r
.principalName
.name_string
.val
[1], realm
) != 0 ||
929 strcmp(r
.realm
, realm
) != 0)
931 krb5_set_error_string(context
, "KDC have wrong realm name in "
933 ret
= KRB5_KDC_ERR_INVALID_CERTIFICATE
;
936 free_KRB5PrincipalName(&r
);
940 hx509_free_octet_string_list(&list
);
946 ret
= hx509_verify_hostname(ctx
->id
->hx509ctx
, host
->cert
,
947 ctx
->require_hostname_match
,
950 hi
->ai
->ai_addr
, hi
->ai
->ai_addrlen
);
953 krb5_set_error_string(context
, "Address mismatch in "
954 "the KDC certificate");
959 static krb5_error_code
960 pk_rd_pa_reply_enckey(krb5_context context
,
962 const heim_octet_string
*indata
,
963 const heim_oid
*dataType
,
965 krb5_pk_init_ctx ctx
,
967 const krb5_krbhst_info
*hi
,
969 const krb5_data
*req_buffer
,
974 struct krb5_pk_cert
*host
= NULL
;
976 heim_oid contentType
= { 0, NULL
};
978 if (der_heim_oid_cmp(oid_id_pkcs7_envelopedData(), dataType
)) {
979 krb5_set_error_string(context
, "PKINIT: Invalid content type");
983 ret
= hx509_cms_unenvelope(ctx
->id
->hx509ctx
,
985 HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT
,
993 pk_copy_error(context
, ctx
->id
->hx509ctx
, ret
,
994 "Failed to unenvelope CMS data in PK-INIT reply");
997 der_free_oid(&contentType
);
999 #if 0 /* windows LH with interesting CMS packets, leaks memory */
1001 size_t ph
= 1 + der_length_len (length
);
1002 unsigned char *ptr
= malloc(length
+ ph
);
1005 memcpy(ptr
+ ph
, p
, length
);
1007 ret
= der_put_length_and_tag (ptr
+ ph
- 1, ph
, length
,
1008 ASN1_C_UNIV
, CONS
, UT_Sequence
, &l
);
1017 /* win2k uses ContentInfo */
1018 if (type
== PKINIT_WIN2K
) {
1020 heim_octet_string out
;
1022 ret
= hx509_cms_unwrap_ContentInfo(&content
, &type
, &out
, NULL
);
1023 if (der_heim_oid_cmp(&type
, oid_id_pkcs7_signedData())) {
1024 ret
= EINVAL
; /* XXX */
1025 krb5_set_error_string(context
, "PKINIT: Invalid content type");
1026 der_free_oid(&type
);
1027 der_free_octet_string(&out
);
1030 der_free_oid(&type
);
1031 krb5_data_free(&content
);
1032 ret
= krb5_data_copy(&content
, out
.data
, out
.length
);
1033 der_free_octet_string(&out
);
1035 krb5_set_error_string(context
, "PKINIT: out of memory");
1040 ret
= _krb5_pk_verify_sign(context
,
1050 /* make sure that it is the kdc's certificate */
1051 ret
= pk_verify_host(context
, realm
, hi
, ctx
, host
);
1057 if (type
== PKINIT_WIN2K
) {
1058 if (der_heim_oid_cmp(&contentType
, oid_id_pkcs7_data()) != 0) {
1059 krb5_set_error_string(context
, "PKINIT: reply key, wrong oid");
1060 ret
= KRB5KRB_AP_ERR_MSG_TYPE
;
1064 if (der_heim_oid_cmp(&contentType
, oid_id_pkrkeydata()) != 0) {
1065 krb5_set_error_string(context
, "PKINIT: reply key, wrong oid");
1066 ret
= KRB5KRB_AP_ERR_MSG_TYPE
;
1074 ret
= get_reply_key(context
, &content
, req_buffer
, key
);
1075 if (ret
!= 0 && ctx
->require_binding
== 0)
1076 ret
= get_reply_key_win(context
, &content
, nonce
, key
);
1079 ret
= get_reply_key(context
, &content
, req_buffer
, key
);
1085 /* XXX compare given etype with key->etype */
1089 _krb5_pk_cert_free(host
);
1090 der_free_oid(&contentType
);
1091 krb5_data_free(&content
);
1096 static krb5_error_code
1097 pk_rd_pa_reply_dh(krb5_context context
,
1098 const heim_octet_string
*indata
,
1099 const heim_oid
*dataType
,
1101 krb5_pk_init_ctx ctx
,
1103 const krb5_krbhst_info
*hi
,
1108 krb5_keyblock
**key
)
1110 unsigned char *p
, *dh_gen_key
= NULL
;
1111 struct krb5_pk_cert
*host
= NULL
;
1112 BIGNUM
*kdc_dh_pubkey
= NULL
;
1113 KDCDHKeyInfo kdc_dh_info
;
1114 heim_oid contentType
= { 0, NULL
};
1116 krb5_error_code ret
;
1120 krb5_data_zero(&content
);
1121 memset(&kdc_dh_info
, 0, sizeof(kdc_dh_info
));
1123 if (der_heim_oid_cmp(oid_id_pkcs7_signedData(), dataType
)) {
1124 krb5_set_error_string(context
, "PKINIT: Invalid content type");
1128 ret
= _krb5_pk_verify_sign(context
,
1138 /* make sure that it is the kdc's certificate */
1139 ret
= pk_verify_host(context
, realm
, hi
, ctx
, host
);
1143 if (der_heim_oid_cmp(&contentType
, oid_id_pkdhkeydata())) {
1144 krb5_set_error_string(context
, "pkinit - dh reply contains wrong oid");
1145 ret
= KRB5KRB_AP_ERR_MSG_TYPE
;
1149 ret
= decode_KDCDHKeyInfo(content
.data
,
1155 krb5_set_error_string(context
, "pkinit - "
1156 "failed to decode KDC DH Key Info");
1160 if (kdc_dh_info
.nonce
!= nonce
) {
1161 krb5_set_error_string(context
, "PKINIT: DH nonce is wrong");
1162 ret
= KRB5KRB_AP_ERR_MODIFIED
;
1166 if (kdc_dh_info
.dhKeyExpiration
) {
1168 krb5_set_error_string(context
, "pkinit; got key expiration "
1169 "without server nonce");
1170 ret
= KRB5KRB_ERR_GENERIC
;
1174 krb5_set_error_string(context
, "pkinit; got DH reuse but no "
1176 ret
= KRB5KRB_ERR_GENERIC
;
1181 krb5_set_error_string(context
, "pkinit: got server nonce "
1182 "without key expiration");
1183 ret
= KRB5KRB_ERR_GENERIC
;
1190 p
= kdc_dh_info
.subjectPublicKey
.data
;
1191 size
= (kdc_dh_info
.subjectPublicKey
.length
+ 7) / 8;
1195 ret
= decode_DHPublicKey(p
, size
, &k
, NULL
);
1197 krb5_set_error_string(context
, "pkinit: can't decode "
1198 "without key expiration");
1202 kdc_dh_pubkey
= integer_to_BN(context
, "DHPublicKey", &k
);
1203 free_DHPublicKey(&k
);
1204 if (kdc_dh_pubkey
== NULL
) {
1205 ret
= KRB5KRB_ERR_GENERIC
;
1210 dh_gen_keylen
= DH_size(ctx
->dh
);
1211 size
= BN_num_bytes(ctx
->dh
->p
);
1212 if (size
< dh_gen_keylen
)
1213 size
= dh_gen_keylen
;
1215 dh_gen_key
= malloc(size
);
1216 if (dh_gen_key
== NULL
) {
1217 krb5_set_error_string(context
, "malloc: out of memory");
1221 memset(dh_gen_key
, 0, size
- dh_gen_keylen
);
1223 dh_gen_keylen
= DH_compute_key(dh_gen_key
+ (size
- dh_gen_keylen
),
1224 kdc_dh_pubkey
, ctx
->dh
);
1225 if (dh_gen_keylen
== -1) {
1226 krb5_set_error_string(context
,
1227 "PKINIT: Can't compute Diffie-Hellman key");
1228 ret
= KRB5KRB_ERR_GENERIC
;
1232 *key
= malloc (sizeof (**key
));
1234 krb5_set_error_string(context
, "malloc: out of memory");
1239 ret
= _krb5_pk_octetstring2key(context
,
1241 dh_gen_key
, dh_gen_keylen
,
1245 krb5_set_error_string(context
,
1246 "PKINIT: can't create key from DH key");
1254 BN_free(kdc_dh_pubkey
);
1256 memset(dh_gen_key
, 0, DH_size(ctx
->dh
));
1260 _krb5_pk_cert_free(host
);
1262 krb5_data_free(&content
);
1263 der_free_oid(&contentType
);
1264 free_KDCDHKeyInfo(&kdc_dh_info
);
1269 krb5_error_code KRB5_LIB_FUNCTION
1270 _krb5_pk_rd_pa_reply(krb5_context context
,
1274 const krb5_krbhst_info
*hi
,
1276 const krb5_data
*req_buffer
,
1278 krb5_keyblock
**key
)
1280 krb5_pk_init_ctx ctx
= c
;
1281 krb5_error_code ret
;
1284 /* Check for IETF PK-INIT first */
1285 if (ctx
->type
== PKINIT_27
) {
1287 heim_octet_string os
, data
;
1290 if (pa
->padata_type
!= KRB5_PADATA_PK_AS_REP
) {
1291 krb5_set_error_string(context
, "PKINIT: wrong padata recv");
1295 ret
= decode_PA_PK_AS_REP(pa
->padata_value
.data
,
1296 pa
->padata_value
.length
,
1300 krb5_set_error_string(context
, "Failed to decode pkinit AS rep");
1304 switch (rep
.element
) {
1305 case choice_PA_PK_AS_REP_dhInfo
:
1306 os
= rep
.u
.dhInfo
.dhSignedData
;
1308 case choice_PA_PK_AS_REP_encKeyPack
:
1309 os
= rep
.u
.encKeyPack
;
1312 free_PA_PK_AS_REP(&rep
);
1313 krb5_set_error_string(context
, "PKINIT: -27 reply "
1314 "invalid content type");
1318 ret
= hx509_cms_unwrap_ContentInfo(&os
, &oid
, &data
, NULL
);
1320 free_PA_PK_AS_REP(&rep
);
1321 krb5_set_error_string(context
, "PKINIT: failed to unwrap CI");
1325 switch (rep
.element
) {
1326 case choice_PA_PK_AS_REP_dhInfo
:
1327 ret
= pk_rd_pa_reply_dh(context
, &data
, &oid
, realm
, ctx
, etype
, hi
,
1329 rep
.u
.dhInfo
.serverDHNonce
,
1332 case choice_PA_PK_AS_REP_encKeyPack
:
1333 ret
= pk_rd_pa_reply_enckey(context
, PKINIT_27
, &data
, &oid
, realm
,
1334 ctx
, etype
, hi
, nonce
, req_buffer
, pa
, key
);
1337 krb5_abortx(context
, "pk-init as-rep case not possible to happen");
1339 der_free_octet_string(&data
);
1341 free_PA_PK_AS_REP(&rep
);
1343 } else if (ctx
->type
== PKINIT_WIN2K
) {
1344 PA_PK_AS_REP_Win2k w2krep
;
1346 /* Check for Windows encoding of the AS-REP pa data */
1348 #if 0 /* should this be ? */
1349 if (pa
->padata_type
!= KRB5_PADATA_PK_AS_REP
) {
1350 krb5_set_error_string(context
, "PKINIT: wrong padata recv");
1355 memset(&w2krep
, 0, sizeof(w2krep
));
1357 ret
= decode_PA_PK_AS_REP_Win2k(pa
->padata_value
.data
,
1358 pa
->padata_value
.length
,
1362 krb5_set_error_string(context
, "PKINIT: Failed decoding windows "
1363 "pkinit reply %d", (int)ret
);
1367 krb5_clear_error_string(context
);
1369 switch (w2krep
.element
) {
1370 case choice_PA_PK_AS_REP_Win2k_encKeyPack
: {
1371 heim_octet_string data
;
1374 ret
= hx509_cms_unwrap_ContentInfo(&w2krep
.u
.encKeyPack
,
1376 free_PA_PK_AS_REP_Win2k(&w2krep
);
1378 krb5_set_error_string(context
, "PKINIT: failed to unwrap CI");
1382 ret
= pk_rd_pa_reply_enckey(context
, PKINIT_WIN2K
, &data
, &oid
, realm
,
1383 ctx
, etype
, hi
, nonce
, req_buffer
, pa
, key
);
1384 der_free_octet_string(&data
);
1390 free_PA_PK_AS_REP_Win2k(&w2krep
);
1391 krb5_set_error_string(context
, "PKINIT: win2k reply invalid "
1398 krb5_set_error_string(context
, "PKINIT: unknown reply type");
1406 krb5_context context
;
1407 krb5_prompter_fct prompter
;
1408 void *prompter_data
;
1412 hx_pass_prompter(void *data
, const hx509_prompt
*prompter
)
1414 krb5_error_code ret
;
1416 krb5_data password_data
;
1417 struct prompter
*p
= data
;
1419 password_data
.data
= prompter
->reply
.data
;
1420 password_data
.length
= prompter
->reply
.length
;
1422 prompt
.prompt
= prompter
->prompt
;
1423 prompt
.hidden
= hx509_prompt_hidden(prompter
->type
);
1424 prompt
.reply
= &password_data
;
1426 switch (prompter
->type
) {
1427 case HX509_PROMPT_TYPE_INFO
:
1428 prompt
.type
= KRB5_PROMPT_TYPE_INFO
;
1430 case HX509_PROMPT_TYPE_PASSWORD
:
1431 case HX509_PROMPT_TYPE_QUESTION
:
1433 prompt
.type
= KRB5_PROMPT_TYPE_PASSWORD
;
1437 ret
= (*p
->prompter
)(p
->context
, p
->prompter_data
, NULL
, NULL
, 1, &prompt
);
1439 memset (prompter
->reply
.data
, 0, prompter
->reply
.length
);
1446 void KRB5_LIB_FUNCTION
1447 _krb5_pk_allow_proxy_certificate(struct krb5_pk_identity
*id
,
1450 hx509_verify_set_proxy_certificate(id
->verify_ctx
, boolean
);
1454 krb5_error_code KRB5_LIB_FUNCTION
1455 _krb5_pk_load_id(krb5_context context
,
1456 struct krb5_pk_identity
**ret_id
,
1457 const char *user_id
,
1458 const char *anchor_id
,
1459 char * const *chain_list
,
1460 char * const *revoke_list
,
1461 krb5_prompter_fct prompter
,
1462 void *prompter_data
,
1465 struct krb5_pk_identity
*id
= NULL
;
1466 hx509_lock lock
= NULL
;
1472 if (anchor_id
== NULL
) {
1473 krb5_set_error_string(context
, "PKINIT: No anchor given");
1474 return HEIM_PKINIT_NO_VALID_CA
;
1477 if (user_id
== NULL
) {
1478 krb5_set_error_string(context
,
1479 "PKINIT: No user certificate given");
1480 return HEIM_PKINIT_NO_PRIVATE_KEY
;
1485 id
= calloc(1, sizeof(*id
));
1487 krb5_set_error_string(context
, "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_string(context
,
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_string(context
, "%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_string(context
, "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_string(context
, "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_string(context
, "malloc - out of memory");
1708 while (isspace((unsigned char)*p
))
1714 p1
= strsep(&p
, " \t");
1716 krb5_set_error_string(context
, "moduli file %s missing name "
1717 "on line %d", file
, lineno
);
1720 m1
->name
= strdup(p1
);
1722 krb5_set_error_string(context
, "malloc - out of memeory");
1727 p1
= strsep(&p
, " \t");
1729 krb5_set_error_string(context
, "moduli file %s missing bits on line %d",
1734 m1
->bits
= atoi(p1
);
1735 if (m1
->bits
== 0) {
1736 krb5_set_error_string(context
, "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_string(context
, "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");
1876 while(fgets(buf
, sizeof(buf
), f
) != NULL
) {
1877 struct krb5_dh_moduli
*element
;
1879 buf
[strcspn(buf
, "\n")] = '\0';
1882 m2
= realloc(m
, (n
+ 2) * sizeof(m
[0]));
1884 krb5_set_error_string(context
, "malloc: out of memory");
1885 _krb5_free_moduli(m
);
1892 ret
= _krb5_parse_moduli_line(context
, file
, lineno
, buf
, &element
);
1894 _krb5_free_moduli(m
);
1897 if (element
== NULL
)
1909 _krb5_dh_group_ok(krb5_context context
, unsigned long bits
,
1910 heim_integer
*p
, heim_integer
*g
, heim_integer
*q
,
1911 struct krb5_dh_moduli
**moduli
,
1919 for (i
= 0; moduli
[i
] != NULL
; i
++) {
1920 if (der_heim_integer_cmp(&moduli
[i
]->g
, g
) == 0 &&
1921 der_heim_integer_cmp(&moduli
[i
]->p
, p
) == 0 &&
1922 (q
== NULL
|| der_heim_integer_cmp(&moduli
[i
]->q
, q
) == 0))
1924 if (bits
&& bits
> moduli
[i
]->bits
) {
1925 krb5_set_error_string(context
, "PKINIT: DH group parameter %s "
1926 "no accepted, not enough bits generated",
1928 return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED
;
1931 *name
= strdup(moduli
[i
]->name
);
1935 krb5_set_error_string(context
, "PKINIT: DH group parameter no ok");
1936 return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED
;
1939 void KRB5_LIB_FUNCTION
1940 _krb5_get_init_creds_opt_free_pkinit(krb5_get_init_creds_opt
*opt
)
1943 krb5_pk_init_ctx ctx
;
1945 if (opt
->opt_private
== NULL
|| opt
->opt_private
->pk_init_ctx
== NULL
)
1947 ctx
= opt
->opt_private
->pk_init_ctx
;
1952 hx509_verify_destroy_ctx(ctx
->id
->verify_ctx
);
1953 hx509_certs_free(&ctx
->id
->certs
);
1954 hx509_certs_free(&ctx
->id
->anchors
);
1955 hx509_certs_free(&ctx
->id
->certpool
);
1956 hx509_context_free(&ctx
->id
->hx509ctx
);
1958 if (ctx
->clientDHNonce
) {
1959 krb5_free_data(NULL
, ctx
->clientDHNonce
);
1960 ctx
->clientDHNonce
= NULL
;
1963 _krb5_free_moduli(ctx
->m
);
1967 free(opt
->opt_private
->pk_init_ctx
);
1968 opt
->opt_private
->pk_init_ctx
= NULL
;
1972 krb5_error_code KRB5_LIB_FUNCTION
1973 krb5_get_init_creds_opt_set_pkinit(krb5_context context
,
1974 krb5_get_init_creds_opt
*opt
,
1975 krb5_principal principal
,
1976 const char *user_id
,
1977 const char *x509_anchors
,
1978 char * const * pool
,
1979 char * const * pki_revoke
,
1981 krb5_prompter_fct prompter
,
1982 void *prompter_data
,
1986 krb5_error_code ret
;
1987 char *anchors
= NULL
;
1989 if (opt
->opt_private
== NULL
) {
1990 krb5_set_error_string(context
, "PKINIT: on non extendable opt");
1994 opt
->opt_private
->pk_init_ctx
=
1995 calloc(1, sizeof(*opt
->opt_private
->pk_init_ctx
));
1996 if (opt
->opt_private
->pk_init_ctx
== NULL
) {
1997 krb5_set_error_string(context
, "malloc: out of memory");
2000 opt
->opt_private
->pk_init_ctx
->dh
= NULL
;
2001 opt
->opt_private
->pk_init_ctx
->id
= NULL
;
2002 opt
->opt_private
->pk_init_ctx
->clientDHNonce
= NULL
;
2003 opt
->opt_private
->pk_init_ctx
->require_binding
= 0;
2004 opt
->opt_private
->pk_init_ctx
->require_eku
= 1;
2005 opt
->opt_private
->pk_init_ctx
->require_krbtgt_otherName
= 1;
2006 opt
->opt_private
->pk_init_ctx
->peer
= NULL
;
2008 /* XXX implement krb5_appdefault_strings */
2010 pool
= krb5_config_get_strings(context
, NULL
,
2015 if (pki_revoke
== NULL
)
2016 pki_revoke
= krb5_config_get_strings(context
, NULL
,
2021 if (x509_anchors
== NULL
) {
2022 krb5_appdefault_string(context
, "kinit",
2023 krb5_principal_get_realm(context
, principal
),
2024 "pkinit_anchors", NULL
, &anchors
);
2025 x509_anchors
= anchors
;
2028 ret
= _krb5_pk_load_id(context
,
2029 &opt
->opt_private
->pk_init_ctx
->id
,
2038 free(opt
->opt_private
->pk_init_ctx
);
2039 opt
->opt_private
->pk_init_ctx
= NULL
;
2043 if ((flags
& 2) == 0) {
2044 const char *moduli_file
;
2045 unsigned long dh_min_bits
;
2047 moduli_file
= krb5_config_get_string(context
, NULL
,
2053 krb5_config_get_int_default(context
, NULL
, 0,
2055 "pkinit_dh_min_bits",
2058 ret
= _krb5_parse_moduli(context
, moduli_file
,
2059 &opt
->opt_private
->pk_init_ctx
->m
);
2061 _krb5_get_init_creds_opt_free_pkinit(opt
);
2065 opt
->opt_private
->pk_init_ctx
->dh
= DH_new();
2066 if (opt
->opt_private
->pk_init_ctx
->dh
== NULL
) {
2067 krb5_set_error_string(context
, "malloc: out of memory");
2068 _krb5_get_init_creds_opt_free_pkinit(opt
);
2072 ret
= select_dh_group(context
, opt
->opt_private
->pk_init_ctx
->dh
,
2074 opt
->opt_private
->pk_init_ctx
->m
);
2076 _krb5_get_init_creds_opt_free_pkinit(opt
);
2080 if (DH_generate_key(opt
->opt_private
->pk_init_ctx
->dh
) != 1) {
2081 krb5_set_error_string(context
, "pkinit: failed to generate DH key");
2082 _krb5_get_init_creds_opt_free_pkinit(opt
);
2089 krb5_set_error_string(context
, "no support for PKINIT compiled in");