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
,
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_string(context
, "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_string(context
, "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 krb5_set_error_string(context
, "PKINIT: reply key, wrong oid");
1059 ret
= KRB5KRB_AP_ERR_MSG_TYPE
;
1063 if (der_heim_oid_cmp(&contentType
, oid_id_pkrkeydata()) != 0) {
1064 krb5_set_error_string(context
, "PKINIT: reply key, wrong oid");
1065 ret
= KRB5KRB_AP_ERR_MSG_TYPE
;
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_string(context
, "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 krb5_set_error_string(context
, "pkinit - dh reply contains wrong oid");
1144 ret
= KRB5KRB_AP_ERR_MSG_TYPE
;
1148 ret
= decode_KDCDHKeyInfo(content
.data
,
1154 krb5_set_error_string(context
, "pkinit - "
1155 "failed to decode KDC DH Key Info");
1159 if (kdc_dh_info
.nonce
!= nonce
) {
1160 krb5_set_error_string(context
, "PKINIT: DH nonce is wrong");
1161 ret
= KRB5KRB_AP_ERR_MODIFIED
;
1165 if (kdc_dh_info
.dhKeyExpiration
) {
1167 krb5_set_error_string(context
, "pkinit; got key expiration "
1168 "without server nonce");
1169 ret
= KRB5KRB_ERR_GENERIC
;
1173 krb5_set_error_string(context
, "pkinit; got DH reuse but no "
1175 ret
= KRB5KRB_ERR_GENERIC
;
1180 krb5_set_error_string(context
, "pkinit: got server nonce "
1181 "without key expiration");
1182 ret
= KRB5KRB_ERR_GENERIC
;
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_string(context
, "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
) {
1204 ret
= KRB5KRB_ERR_GENERIC
;
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
) {
1216 krb5_set_error_string(context
, "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 krb5_set_error_string(context
,
1226 "PKINIT: Can't compute Diffie-Hellman key");
1227 ret
= KRB5KRB_ERR_GENERIC
;
1231 *key
= malloc (sizeof (**key
));
1233 krb5_set_error_string(context
, "malloc: out of memory");
1238 ret
= _krb5_pk_octetstring2key(context
,
1240 dh_gen_key
, dh_gen_keylen
,
1244 krb5_set_error_string(context
,
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_string(context
, "PKINIT: wrong padata recv");
1294 ret
= decode_PA_PK_AS_REP(pa
->padata_value
.data
,
1295 pa
->padata_value
.length
,
1299 krb5_set_error_string(context
, "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_string(context
, "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_string(context
, "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_string(context
, "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_string(context
, "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_string(context
, "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
);
1390 krb5_set_error_string(context
, "PKINIT: win2k reply invalid "
1397 krb5_set_error_string(context
, "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_string(context
, "PKINIT: No anchor given");
1473 return HEIM_PKINIT_NO_VALID_CA
;
1476 if (user_id
== NULL
) {
1477 krb5_set_error_string(context
,
1478 "PKINIT: No user certificate given");
1479 return HEIM_PKINIT_NO_PRIVATE_KEY
;
1484 id
= calloc(1, sizeof(*id
));
1486 krb5_set_error_string(context
, "malloc: out of memory");
1490 ret
= hx509_context_init(&id
->hx509ctx
);
1494 ret
= hx509_lock_init(id
->hx509ctx
, &lock
);
1495 if (password
&& password
[0])
1496 hx509_lock_add_password(lock
, password
);
1499 p
.context
= context
;
1500 p
.prompter
= prompter
;
1501 p
.prompter_data
= prompter_data
;
1503 ret
= hx509_lock_set_prompter(lock
, hx_pass_prompter
, &p
);
1508 ret
= hx509_certs_init(id
->hx509ctx
, user_id
, 0, lock
, &id
->certs
);
1510 pk_copy_error(context
, id
->hx509ctx
, ret
,
1511 "Failed to init cert certs");
1515 ret
= hx509_certs_init(id
->hx509ctx
, anchor_id
, 0, NULL
, &id
->anchors
);
1517 pk_copy_error(context
, id
->hx509ctx
, ret
,
1518 "Failed to init anchors");
1522 ret
= hx509_certs_init(id
->hx509ctx
, "MEMORY:pkinit-cert-chain",
1523 0, NULL
, &id
->certpool
);
1525 pk_copy_error(context
, id
->hx509ctx
, ret
,
1526 "Failed to init chain");
1530 while (chain_list
&& *chain_list
) {
1531 ret
= hx509_certs_append(id
->hx509ctx
, id
->certpool
,
1534 pk_copy_error(context
, id
->hx509ctx
, ret
,
1535 "Failed to laod chain %s",
1543 ret
= hx509_revoke_init(id
->hx509ctx
, &id
->revokectx
);
1545 pk_copy_error(context
, id
->hx509ctx
, ret
,
1546 "Failed init revoke list");
1550 while (*revoke_list
) {
1551 ret
= hx509_revoke_add_crl(id
->hx509ctx
,
1555 pk_copy_error(context
, id
->hx509ctx
, ret
,
1556 "Failed load revoke list");
1562 hx509_context_set_missing_revoke(id
->hx509ctx
, 1);
1564 ret
= hx509_verify_init_ctx(id
->hx509ctx
, &id
->verify_ctx
);
1566 pk_copy_error(context
, id
->hx509ctx
, ret
,
1567 "Failed init verify context");
1571 hx509_verify_attach_anchors(id
->verify_ctx
, id
->anchors
);
1572 hx509_verify_attach_revoke(id
->verify_ctx
, id
->revokectx
);
1576 hx509_verify_destroy_ctx(id
->verify_ctx
);
1577 hx509_certs_free(&id
->certs
);
1578 hx509_certs_free(&id
->anchors
);
1579 hx509_certs_free(&id
->certpool
);
1580 hx509_revoke_free(&id
->revokectx
);
1581 hx509_context_free(&id
->hx509ctx
);
1586 hx509_lock_free(lock
);
1591 static krb5_error_code
1592 select_dh_group(krb5_context context
, DH
*dh
, unsigned long bits
,
1593 struct krb5_dh_moduli
**moduli
)
1595 const struct krb5_dh_moduli
*m
;
1598 m
= moduli
[1]; /* XXX */
1600 m
= moduli
[0]; /* XXX */
1603 for (i
= 0; moduli
[i
] != NULL
; i
++) {
1604 if (bits
< moduli
[i
]->bits
)
1607 if (moduli
[i
] == NULL
) {
1608 krb5_set_error_string(context
,
1609 "Did not find a DH group parameter "
1610 "matching requirement of %lu bits",
1617 dh
->p
= integer_to_BN(context
, "p", &m
->p
);
1620 dh
->g
= integer_to_BN(context
, "g", &m
->g
);
1623 dh
->q
= integer_to_BN(context
, "q", &m
->q
);
1635 pk_copy_error(krb5_context context
,
1636 hx509_context hx509ctx
,
1645 vasprintf(&f
, fmt
, va
);
1648 krb5_clear_error_string(context
);
1652 s
= hx509_get_error_string(hx509ctx
, hxret
);
1654 krb5_clear_error_string(context
);
1658 krb5_set_error_string(context
, "%s: %s", f
, s
);
1666 parse_integer(krb5_context context
, char **p
, const char *file
, int lineno
,
1667 const char *name
, heim_integer
*integer
)
1671 p1
= strsep(p
, " \t");
1673 krb5_set_error_string(context
, "moduli file %s missing %s on line %d",
1674 file
, name
, lineno
);
1677 ret
= der_parse_hex_heim_integer(p1
, integer
);
1679 krb5_set_error_string(context
, "moduli file %s failed parsing %s "
1681 file
, name
, lineno
);
1689 _krb5_parse_moduli_line(krb5_context context
,
1693 struct krb5_dh_moduli
**m
)
1695 struct krb5_dh_moduli
*m1
;
1701 m1
= calloc(1, sizeof(*m1
));
1703 krb5_set_error_string(context
, "malloc - out of memory");
1707 while (isspace((unsigned char)*p
))
1713 p1
= strsep(&p
, " \t");
1715 krb5_set_error_string(context
, "moduli file %s missing name "
1716 "on line %d", file
, lineno
);
1719 m1
->name
= strdup(p1
);
1721 krb5_set_error_string(context
, "malloc - out of memeory");
1726 p1
= strsep(&p
, " \t");
1728 krb5_set_error_string(context
, "moduli file %s missing bits on line %d",
1733 m1
->bits
= atoi(p1
);
1734 if (m1
->bits
== 0) {
1735 krb5_set_error_string(context
, "moduli file %s have un-parsable "
1736 "bits on line %d", file
, lineno
);
1740 ret
= parse_integer(context
, &p
, file
, lineno
, "p", &m1
->p
);
1743 ret
= parse_integer(context
, &p
, file
, lineno
, "g", &m1
->g
);
1746 ret
= parse_integer(context
, &p
, file
, lineno
, "q", &m1
->q
);
1755 der_free_heim_integer(&m1
->p
);
1756 der_free_heim_integer(&m1
->g
);
1757 der_free_heim_integer(&m1
->q
);
1763 _krb5_free_moduli(struct krb5_dh_moduli
**moduli
)
1766 for (i
= 0; moduli
[i
] != NULL
; i
++) {
1767 free(moduli
[i
]->name
);
1768 der_free_heim_integer(&moduli
[i
]->p
);
1769 der_free_heim_integer(&moduli
[i
]->g
);
1770 der_free_heim_integer(&moduli
[i
]->q
);
1776 static const char *default_moduli_RFC2412_MODP_group2
=
1778 "RFC2412-MODP-group2 "
1782 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
1783 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
1784 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
1785 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
1786 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
1787 "FFFFFFFF" "FFFFFFFF "
1791 "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68"
1792 "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E"
1793 "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122"
1794 "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6"
1795 "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F67329C0"
1796 "FFFFFFFF" "FFFFFFFF";
1798 static const char *default_moduli_rfc3526_MODP_group14
=
1800 "rfc3526-MODP-group14 "
1804 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
1805 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
1806 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
1807 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
1808 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D"
1809 "C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"
1810 "83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"
1811 "670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"
1812 "E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"
1813 "DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
1814 "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF "
1818 "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68"
1819 "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E"
1820 "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122"
1821 "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6"
1822 "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F6722D9E"
1823 "E1003E5C" "50B1DF82" "CC6D241B" "0E2AE9CD" "348B1FD4" "7E9267AF"
1824 "C1B2AE91" "EE51D6CB" "0E3179AB" "1042A95D" "CF6A9483" "B84B4B36"
1825 "B3861AA7" "255E4C02" "78BA3604" "650C10BE" "19482F23" "171B671D"
1826 "F1CF3B96" "0C074301" "CD93C1D1" "7603D147" "DAE2AEF8" "37A62964"
1827 "EF15E5FB" "4AAC0B8C" "1CCAA4BE" "754AB572" "8AE9130C" "4C7D0288"
1828 "0AB9472D" "45565534" "7FFFFFFF" "FFFFFFFF";
1831 _krb5_parse_moduli(krb5_context context
, const char *file
,
1832 struct krb5_dh_moduli
***moduli
)
1834 /* name bits P G Q */
1835 krb5_error_code ret
;
1836 struct krb5_dh_moduli
**m
= NULL
, **m2
;
1839 int lineno
= 0, n
= 0;
1843 m
= calloc(1, sizeof(m
[0]) * 3);
1845 krb5_set_error_string(context
, "malloc: out of memory");
1849 strlcpy(buf
, default_moduli_rfc3526_MODP_group14
, sizeof(buf
));
1850 ret
= _krb5_parse_moduli_line(context
, "builtin", 1, buf
, &m
[0]);
1852 _krb5_free_moduli(m
);
1857 strlcpy(buf
, default_moduli_RFC2412_MODP_group2
, sizeof(buf
));
1858 ret
= _krb5_parse_moduli_line(context
, "builtin", 1, buf
, &m
[1]);
1860 _krb5_free_moduli(m
);
1869 f
= fopen(file
, "r");
1875 while(fgets(buf
, sizeof(buf
), f
) != NULL
) {
1876 struct krb5_dh_moduli
*element
;
1878 buf
[strcspn(buf
, "\n")] = '\0';
1881 m2
= realloc(m
, (n
+ 2) * sizeof(m
[0]));
1883 krb5_set_error_string(context
, "malloc: out of memory");
1884 _krb5_free_moduli(m
);
1891 ret
= _krb5_parse_moduli_line(context
, file
, lineno
, buf
, &element
);
1893 _krb5_free_moduli(m
);
1896 if (element
== NULL
)
1908 _krb5_dh_group_ok(krb5_context context
, unsigned long bits
,
1909 heim_integer
*p
, heim_integer
*g
, heim_integer
*q
,
1910 struct krb5_dh_moduli
**moduli
,
1918 for (i
= 0; moduli
[i
] != NULL
; i
++) {
1919 if (der_heim_integer_cmp(&moduli
[i
]->g
, g
) == 0 &&
1920 der_heim_integer_cmp(&moduli
[i
]->p
, p
) == 0 &&
1921 (q
== NULL
|| der_heim_integer_cmp(&moduli
[i
]->q
, q
) == 0))
1923 if (bits
&& bits
> moduli
[i
]->bits
) {
1924 krb5_set_error_string(context
, "PKINIT: DH group parameter %s "
1925 "no accepted, not enough bits generated",
1927 return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED
;
1930 *name
= strdup(moduli
[i
]->name
);
1934 krb5_set_error_string(context
, "PKINIT: DH group parameter no ok");
1935 return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED
;
1938 void KRB5_LIB_FUNCTION
1939 _krb5_get_init_creds_opt_free_pkinit(krb5_get_init_creds_opt
*opt
)
1942 krb5_pk_init_ctx ctx
;
1944 if (opt
->opt_private
== NULL
|| opt
->opt_private
->pk_init_ctx
== NULL
)
1946 ctx
= opt
->opt_private
->pk_init_ctx
;
1951 hx509_verify_destroy_ctx(ctx
->id
->verify_ctx
);
1952 hx509_certs_free(&ctx
->id
->certs
);
1953 hx509_certs_free(&ctx
->id
->anchors
);
1954 hx509_certs_free(&ctx
->id
->certpool
);
1955 hx509_context_free(&ctx
->id
->hx509ctx
);
1957 if (ctx
->clientDHNonce
) {
1958 krb5_free_data(NULL
, ctx
->clientDHNonce
);
1959 ctx
->clientDHNonce
= NULL
;
1962 _krb5_free_moduli(ctx
->m
);
1966 free(opt
->opt_private
->pk_init_ctx
);
1967 opt
->opt_private
->pk_init_ctx
= NULL
;
1971 krb5_error_code KRB5_LIB_FUNCTION
1972 krb5_get_init_creds_opt_set_pkinit(krb5_context context
,
1973 krb5_get_init_creds_opt
*opt
,
1974 krb5_principal principal
,
1975 const char *user_id
,
1976 const char *x509_anchors
,
1977 char * const * pool
,
1978 char * const * pki_revoke
,
1980 krb5_prompter_fct prompter
,
1981 void *prompter_data
,
1985 krb5_error_code ret
;
1986 char *anchors
= NULL
;
1988 if (opt
->opt_private
== NULL
) {
1989 krb5_set_error_string(context
, "PKINIT: on non extendable opt");
1993 opt
->opt_private
->pk_init_ctx
=
1994 calloc(1, sizeof(*opt
->opt_private
->pk_init_ctx
));
1995 if (opt
->opt_private
->pk_init_ctx
== NULL
) {
1996 krb5_set_error_string(context
, "malloc: out of memory");
1999 opt
->opt_private
->pk_init_ctx
->dh
= NULL
;
2000 opt
->opt_private
->pk_init_ctx
->id
= NULL
;
2001 opt
->opt_private
->pk_init_ctx
->clientDHNonce
= NULL
;
2002 opt
->opt_private
->pk_init_ctx
->require_binding
= 0;
2003 opt
->opt_private
->pk_init_ctx
->require_eku
= 1;
2004 opt
->opt_private
->pk_init_ctx
->require_krbtgt_otherName
= 1;
2005 opt
->opt_private
->pk_init_ctx
->peer
= NULL
;
2007 /* XXX implement krb5_appdefault_strings */
2009 pool
= krb5_config_get_strings(context
, NULL
,
2014 if (pki_revoke
== NULL
)
2015 pki_revoke
= krb5_config_get_strings(context
, NULL
,
2020 if (x509_anchors
== NULL
) {
2021 krb5_appdefault_string(context
, "kinit",
2022 krb5_principal_get_realm(context
, principal
),
2023 "pkinit_anchors", NULL
, &anchors
);
2024 x509_anchors
= anchors
;
2027 ret
= _krb5_pk_load_id(context
,
2028 &opt
->opt_private
->pk_init_ctx
->id
,
2037 free(opt
->opt_private
->pk_init_ctx
);
2038 opt
->opt_private
->pk_init_ctx
= NULL
;
2042 if ((flags
& 2) == 0) {
2043 const char *moduli_file
;
2044 unsigned long dh_min_bits
;
2046 moduli_file
= krb5_config_get_string(context
, NULL
,
2052 krb5_config_get_int_default(context
, NULL
, 0,
2054 "pkinit_dh_min_bits",
2057 ret
= _krb5_parse_moduli(context
, moduli_file
,
2058 &opt
->opt_private
->pk_init_ctx
->m
);
2060 _krb5_get_init_creds_opt_free_pkinit(opt
);
2064 opt
->opt_private
->pk_init_ctx
->dh
= DH_new();
2065 if (opt
->opt_private
->pk_init_ctx
->dh
== NULL
) {
2066 krb5_set_error_string(context
, "malloc: out of memory");
2067 _krb5_get_init_creds_opt_free_pkinit(opt
);
2071 ret
= select_dh_group(context
, opt
->opt_private
->pk_init_ctx
->dh
,
2073 opt
->opt_private
->pk_init_ctx
->m
);
2075 _krb5_get_init_creds_opt_free_pkinit(opt
);
2079 if (DH_generate_key(opt
->opt_private
->pk_init_ctx
->dh
) != 1) {
2080 krb5_set_error_string(context
, "pkinit: failed to generate DH key");
2081 _krb5_get_init_creds_opt_free_pkinit(opt
);
2088 krb5_set_error_string(context
, "no support for PKINIT compiled in");