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 struct krb5_dh_moduli
{
47 #include <pkcs8_asn1.h>
48 #include <pkcs9_asn1.h>
49 #include <pkcs12_asn1.h>
50 #include <pkinit_asn1.h>
59 struct krb5_pk_init_ctx_data
{
60 struct krb5_pk_identity
*id
;
61 enum { USE_RSA
, USE_DH
, USE_ECDH
} keyex
;
68 krb5_data
*clientDHNonce
;
69 struct krb5_dh_moduli
**m
;
71 enum krb5_pk_type type
;
72 unsigned int require_binding
:1;
73 unsigned int require_eku
:1;
74 unsigned int require_krbtgt_otherName
:1;
75 unsigned int require_hostname_match
:1;
76 unsigned int trustedCertifiers
:1;
77 unsigned int anonymous
:1;
81 pk_copy_error(krb5_context context
,
82 hx509_context hx509ctx
,
86 __attribute__ ((format (printf
, 4, 5)));
92 void KRB5_LIB_FUNCTION
93 _krb5_pk_cert_free(struct krb5_pk_cert
*cert
)
96 hx509_cert_free(cert
->cert
);
101 static krb5_error_code
102 BN_to_integer(krb5_context context
, BIGNUM
*bn
, heim_integer
*integer
)
104 integer
->length
= BN_num_bytes(bn
);
105 integer
->data
= malloc(integer
->length
);
106 if (integer
->data
== NULL
) {
107 krb5_clear_error_message(context
);
110 BN_bn2bin(bn
, integer
->data
);
111 integer
->negative
= BN_is_negative(bn
);
116 integer_to_BN(krb5_context context
, const char *field
, const heim_integer
*f
)
120 bn
= BN_bin2bn((const unsigned char *)f
->data
, f
->length
, NULL
);
122 krb5_set_error_message(context
, ENOMEM
,
123 N_("PKINIT: parsing BN failed %s", ""), field
);
126 BN_set_negative(bn
, f
->negative
);
130 static krb5_error_code
131 select_dh_group(krb5_context context
, DH
*dh
, unsigned long bits
,
132 struct krb5_dh_moduli
**moduli
)
134 const struct krb5_dh_moduli
*m
;
137 m
= moduli
[1]; /* XXX */
139 m
= moduli
[0]; /* XXX */
142 for (i
= 0; moduli
[i
] != NULL
; i
++) {
143 if (bits
< moduli
[i
]->bits
)
146 if (moduli
[i
] == NULL
) {
147 krb5_set_error_message(context
, EINVAL
,
148 N_("Did not find a DH group parameter "
149 "matching requirement of %lu bits", ""),
156 dh
->p
= integer_to_BN(context
, "p", &m
->p
);
159 dh
->g
= integer_to_BN(context
, "g", &m
->g
);
162 dh
->q
= integer_to_BN(context
, "q", &m
->q
);
175 * Try searchin the key by to use by first looking for for PK-INIT
176 * EKU, then the Microsoft smart card EKU and last, no special EKU at all.
179 static krb5_error_code
180 find_cert(krb5_context context
, struct krb5_pk_identity
*id
,
181 hx509_query
*q
, hx509_cert
*cert
)
183 struct certfind cf
[3] = {
190 cf
[0].oid
= &asn1_oid_id_pkekuoid
;
191 cf
[1].oid
= &asn1_oid_id_pkinit_ms_eku
;
194 for (i
= 0; i
< sizeof(cf
)/sizeof(cf
[0]); i
++) {
195 ret
= hx509_query_match_eku(q
, cf
[i
].oid
);
197 pk_copy_error(context
, context
->hx509ctx
, ret
,
198 "Failed setting %s OID", cf
[i
].type
);
202 ret
= hx509_certs_find(context
->hx509ctx
, id
->certs
, q
, cert
);
205 pk_copy_error(context
, context
->hx509ctx
, ret
,
206 "Failed finding certificate with %s OID", cf
[i
].type
);
212 static krb5_error_code
213 create_signature(krb5_context context
,
214 const heim_oid
*eContentType
,
216 struct krb5_pk_identity
*id
,
217 hx509_peer_info peer
,
222 if (id
->cert
== NULL
)
223 flags
|= HX509_CMS_SIGNATURE_NO_SIGNER
;
225 ret
= hx509_cms_create_signed_1(context
->hx509ctx
,
237 pk_copy_error(context
, context
->hx509ctx
, ret
,
238 "Create CMS signedData");
246 cert2epi(hx509_context context
, void *ctx
, hx509_cert c
)
248 ExternalPrincipalIdentifiers
*ids
= ctx
;
249 ExternalPrincipalIdentifier id
;
250 hx509_name subject
= NULL
;
257 memset(&id
, 0, sizeof(id
));
259 ret
= hx509_cert_get_subject(c
, &subject
);
263 if (hx509_name_is_null_p(subject
) != 0) {
265 id
.subjectName
= calloc(1, sizeof(*id
.subjectName
));
266 if (id
.subjectName
== NULL
) {
267 hx509_name_free(&subject
);
268 free_ExternalPrincipalIdentifier(&id
);
272 ret
= hx509_name_binary(subject
, id
.subjectName
);
274 hx509_name_free(&subject
);
275 free_ExternalPrincipalIdentifier(&id
);
279 hx509_name_free(&subject
);
282 id
.issuerAndSerialNumber
= calloc(1, sizeof(*id
.issuerAndSerialNumber
));
283 if (id
.issuerAndSerialNumber
== NULL
) {
284 free_ExternalPrincipalIdentifier(&id
);
289 IssuerAndSerialNumber iasn
;
293 memset(&iasn
, 0, sizeof(iasn
));
295 ret
= hx509_cert_get_issuer(c
, &issuer
);
297 free_ExternalPrincipalIdentifier(&id
);
301 ret
= hx509_name_to_Name(issuer
, &iasn
.issuer
);
302 hx509_name_free(&issuer
);
304 free_ExternalPrincipalIdentifier(&id
);
308 ret
= hx509_cert_get_serialnumber(c
, &iasn
.serialNumber
);
310 free_IssuerAndSerialNumber(&iasn
);
311 free_ExternalPrincipalIdentifier(&id
);
315 ASN1_MALLOC_ENCODE(IssuerAndSerialNumber
,
316 id
.issuerAndSerialNumber
->data
,
317 id
.issuerAndSerialNumber
->length
,
319 free_IssuerAndSerialNumber(&iasn
);
322 if (id
.issuerAndSerialNumber
->length
!= size
)
326 id
.subjectKeyIdentifier
= NULL
;
328 p
= realloc(ids
->val
, sizeof(ids
->val
[0]) * (ids
->len
+ 1));
330 free_ExternalPrincipalIdentifier(&id
);
335 ids
->val
[ids
->len
] = id
;
341 static krb5_error_code
342 build_edi(krb5_context context
,
343 hx509_context hx509ctx
,
345 ExternalPrincipalIdentifiers
*ids
)
347 return hx509_certs_iter(hx509ctx
, certs
, cert2epi
, ids
);
350 static krb5_error_code
351 build_auth_pack(krb5_context context
,
353 krb5_pk_init_ctx ctx
,
354 const KDC_REQ_BODY
*body
,
357 size_t buf_size
, len
;
364 krb5_clear_error_message(context
);
366 memset(&checksum
, 0, sizeof(checksum
));
368 krb5_us_timeofday(context
, &sec
, &usec
);
369 a
->pkAuthenticator
.ctime
= sec
;
370 a
->pkAuthenticator
.nonce
= nonce
;
372 ASN1_MALLOC_ENCODE(KDC_REQ_BODY
, buf
, buf_size
, body
, &len
, ret
);
376 krb5_abortx(context
, "internal error in ASN.1 encoder");
378 ret
= krb5_create_checksum(context
,
389 ALLOC(a
->pkAuthenticator
.paChecksum
, 1);
390 if (a
->pkAuthenticator
.paChecksum
== NULL
) {
391 krb5_set_error_message(context
, ENOMEM
,
392 N_("malloc: out of memory", ""));
396 ret
= krb5_data_copy(a
->pkAuthenticator
.paChecksum
,
397 checksum
.checksum
.data
, checksum
.checksum
.length
);
398 free_Checksum(&checksum
);
402 if (ctx
->keyex
== USE_DH
|| ctx
->keyex
== USE_ECDH
) {
403 const char *moduli_file
;
404 unsigned long dh_min_bits
;
408 krb5_data_zero(&dhbuf
);
412 moduli_file
= krb5_config_get_string(context
, NULL
,
418 krb5_config_get_int_default(context
, NULL
, 0,
420 "pkinit_dh_min_bits",
423 ret
= _krb5_parse_moduli(context
, moduli_file
, &ctx
->m
);
427 ctx
->u
.dh
= DH_new();
428 if (ctx
->u
.dh
== NULL
) {
429 krb5_set_error_message(context
, ENOMEM
,
430 N_("malloc: out of memory", ""));
434 ret
= select_dh_group(context
, ctx
->u
.dh
, dh_min_bits
, ctx
->m
);
438 if (DH_generate_key(ctx
->u
.dh
) != 1) {
439 krb5_set_error_message(context
, ENOMEM
,
440 N_("pkinit: failed to generate DH key", ""));
445 if (1 /* support_cached_dh */) {
446 ALLOC(a
->clientDHNonce
, 1);
447 if (a
->clientDHNonce
== NULL
) {
448 krb5_clear_error_message(context
);
451 ret
= krb5_data_alloc(a
->clientDHNonce
, 40);
452 if (a
->clientDHNonce
== NULL
) {
453 krb5_clear_error_message(context
);
456 RAND_bytes(a
->clientDHNonce
->data
, a
->clientDHNonce
->length
);
457 ret
= krb5_copy_data(context
, a
->clientDHNonce
,
458 &ctx
->clientDHNonce
);
463 ALLOC(a
->clientPublicValue
, 1);
464 if (a
->clientPublicValue
== NULL
)
467 if (ctx
->keyex
== USE_DH
) {
470 heim_integer dh_pub_key
;
472 ret
= der_copy_oid(&asn1_oid_id_dhpublicnumber
,
473 &a
->clientPublicValue
->algorithm
.algorithm
);
477 memset(&dp
, 0, sizeof(dp
));
479 ret
= BN_to_integer(context
, dh
->p
, &dp
.p
);
481 free_DomainParameters(&dp
);
484 ret
= BN_to_integer(context
, dh
->g
, &dp
.g
);
486 free_DomainParameters(&dp
);
489 ret
= BN_to_integer(context
, dh
->q
, &dp
.q
);
491 free_DomainParameters(&dp
);
495 dp
.validationParms
= NULL
;
497 a
->clientPublicValue
->algorithm
.parameters
=
498 malloc(sizeof(*a
->clientPublicValue
->algorithm
.parameters
));
499 if (a
->clientPublicValue
->algorithm
.parameters
== NULL
) {
500 free_DomainParameters(&dp
);
504 ASN1_MALLOC_ENCODE(DomainParameters
,
505 a
->clientPublicValue
->algorithm
.parameters
->data
,
506 a
->clientPublicValue
->algorithm
.parameters
->length
,
508 free_DomainParameters(&dp
);
511 if (size
!= a
->clientPublicValue
->algorithm
.parameters
->length
)
512 krb5_abortx(context
, "Internal ASN1 encoder error");
514 ret
= BN_to_integer(context
, dh
->pub_key
, &dh_pub_key
);
518 ASN1_MALLOC_ENCODE(DHPublicKey
, dhbuf
.data
, dhbuf
.length
,
519 &dh_pub_key
, &size
, ret
);
520 der_free_heim_integer(&dh_pub_key
);
523 if (size
!= dhbuf
.length
)
524 krb5_abortx(context
, "asn1 internal error");
525 } else if (ctx
->keyex
== USE_ECDH
) {
531 /* copy in public key, XXX find the best curve that the server support or use the clients curve if possible */
533 ecp
.element
= choice_ECParameters_namedCurve
;
534 ret
= der_copy_oid(&asn1_oid_id_ec_group_secp256r1
,
539 ALLOC(a
->clientPublicValue
->algorithm
.parameters
, 1);
540 if (a
->clientPublicValue
->algorithm
.parameters
== NULL
) {
541 free_ECParameters(&ecp
);
544 ASN1_MALLOC_ENCODE(ECParameters
, p
, len
, &ecp
, &size
, ret
);
545 free_ECParameters(&ecp
);
549 krb5_abortx(context
, "asn1 internal error");
551 a
->clientPublicValue
->algorithm
.parameters
->data
= p
;
552 a
->clientPublicValue
->algorithm
.parameters
->length
= size
;
554 /* copy in public key */
556 ret
= der_copy_oid(&asn1_oid_id_ecPublicKey
,
557 &a
->clientPublicValue
->algorithm
.algorithm
);
561 ctx
->u
.eckey
= EC_KEY_new_by_curve_name(NID_X9_62_prime256v1
);
562 if (ctx
->u
.eckey
== NULL
)
565 ret
= EC_KEY_generate_key(ctx
->u
.eckey
);
569 /* encode onto dhkey */
571 len
= i2o_ECPublicKey(ctx
->u
.eckey
, NULL
);
575 dhbuf
.data
= malloc(len
);
576 if (dhbuf
.data
== NULL
)
581 len
= i2o_ECPublicKey(ctx
->u
.eckey
, &p
);
585 /* XXX verify that this is right with RFC3279 */
590 krb5_abortx(context
, "internal error");
591 a
->clientPublicValue
->subjectPublicKey
.length
= dhbuf
.length
* 8;
592 a
->clientPublicValue
->subjectPublicKey
.data
= dhbuf
.data
;
596 a
->supportedCMSTypes
= calloc(1, sizeof(*a
->supportedCMSTypes
));
597 if (a
->supportedCMSTypes
== NULL
)
600 ret
= hx509_crypto_available(context
->hx509ctx
, HX509_SELECT_ALL
, NULL
,
601 &a
->supportedCMSTypes
->val
,
602 &a
->supportedCMSTypes
->len
);
610 krb5_error_code KRB5_LIB_FUNCTION
611 _krb5_pk_mk_ContentInfo(krb5_context context
,
612 const krb5_data
*buf
,
614 struct ContentInfo
*content_info
)
618 ret
= der_copy_oid(oid
, &content_info
->contentType
);
621 ALLOC(content_info
->content
, 1);
622 if (content_info
->content
== NULL
)
624 content_info
->content
->data
= malloc(buf
->length
);
625 if (content_info
->content
->data
== NULL
)
627 memcpy(content_info
->content
->data
, buf
->data
, buf
->length
);
628 content_info
->content
->length
= buf
->length
;
632 static krb5_error_code
633 pk_mk_padata(krb5_context context
,
634 krb5_pk_init_ctx ctx
,
635 const KDC_REQ_BODY
*req_body
,
639 struct ContentInfo content_info
;
643 krb5_data buf
, sd_buf
;
646 krb5_data_zero(&buf
);
647 krb5_data_zero(&sd_buf
);
648 memset(&content_info
, 0, sizeof(content_info
));
650 if (ctx
->type
== PKINIT_WIN2K
) {
655 memset(&ap
, 0, sizeof(ap
));
657 /* fill in PKAuthenticator */
658 ret
= copy_PrincipalName(req_body
->sname
, &ap
.pkAuthenticator
.kdcName
);
660 free_AuthPack_Win2k(&ap
);
661 krb5_clear_error_message(context
);
664 ret
= copy_Realm(&req_body
->realm
, &ap
.pkAuthenticator
.kdcRealm
);
666 free_AuthPack_Win2k(&ap
);
667 krb5_clear_error_message(context
);
671 krb5_us_timeofday(context
, &sec
, &usec
);
672 ap
.pkAuthenticator
.ctime
= sec
;
673 ap
.pkAuthenticator
.cusec
= usec
;
674 ap
.pkAuthenticator
.nonce
= nonce
;
676 ASN1_MALLOC_ENCODE(AuthPack_Win2k
, buf
.data
, buf
.length
,
678 free_AuthPack_Win2k(&ap
);
680 krb5_set_error_message(context
, ret
,
681 N_("Failed encoding AuthPackWin: %d", ""),
685 if (buf
.length
!= size
)
686 krb5_abortx(context
, "internal ASN1 encoder error");
688 oid
= &asn1_oid_id_pkcs7_data
;
689 } else if (ctx
->type
== PKINIT_27
) {
692 memset(&ap
, 0, sizeof(ap
));
694 ret
= build_auth_pack(context
, nonce
, ctx
, req_body
, &ap
);
700 ASN1_MALLOC_ENCODE(AuthPack
, buf
.data
, buf
.length
, &ap
, &size
, ret
);
703 krb5_set_error_message(context
, ret
,
704 N_("Failed encoding AuthPack: %d", ""),
708 if (buf
.length
!= size
)
709 krb5_abortx(context
, "internal ASN1 encoder error");
711 oid
= &asn1_oid_id_pkauthdata
;
713 krb5_abortx(context
, "internal pkinit error");
715 ret
= create_signature(context
, oid
, &buf
, ctx
->id
,
717 krb5_data_free(&buf
);
721 ret
= hx509_cms_wrap_ContentInfo(&asn1_oid_id_pkcs7_signedData
, &sd_buf
, &buf
);
722 krb5_data_free(&sd_buf
);
724 krb5_set_error_message(context
, ret
,
725 N_("ContentInfo wrapping of signedData failed",""));
729 if (ctx
->type
== PKINIT_WIN2K
) {
730 PA_PK_AS_REQ_Win2k winreq
;
732 pa_type
= KRB5_PADATA_PK_AS_REQ_WIN
;
734 memset(&winreq
, 0, sizeof(winreq
));
736 winreq
.signed_auth_pack
= buf
;
738 ASN1_MALLOC_ENCODE(PA_PK_AS_REQ_Win2k
, buf
.data
, buf
.length
,
739 &winreq
, &size
, ret
);
740 free_PA_PK_AS_REQ_Win2k(&winreq
);
742 } else if (ctx
->type
== PKINIT_27
) {
745 pa_type
= KRB5_PADATA_PK_AS_REQ
;
747 memset(&req
, 0, sizeof(req
));
748 req
.signedAuthPack
= buf
;
750 if (ctx
->trustedCertifiers
) {
752 req
.trustedCertifiers
= calloc(1, sizeof(*req
.trustedCertifiers
));
753 if (req
.trustedCertifiers
== NULL
) {
755 krb5_set_error_message(context
, ret
,
756 N_("malloc: out of memory", ""));
757 free_PA_PK_AS_REQ(&req
);
760 ret
= build_edi(context
, context
->hx509ctx
,
761 ctx
->id
->anchors
, req
.trustedCertifiers
);
763 krb5_set_error_message(context
, ret
,
764 N_("pk-init: failed to build "
765 "trustedCertifiers", ""));
766 free_PA_PK_AS_REQ(&req
);
772 ASN1_MALLOC_ENCODE(PA_PK_AS_REQ
, buf
.data
, buf
.length
,
775 free_PA_PK_AS_REQ(&req
);
778 krb5_abortx(context
, "internal pkinit error");
780 krb5_set_error_message(context
, ret
, "PA-PK-AS-REQ %d", (int)ret
);
783 if (buf
.length
!= size
)
784 krb5_abortx(context
, "Internal ASN1 encoder error");
786 ret
= krb5_padata_add(context
, md
, pa_type
, buf
.data
, buf
.length
);
791 krb5_padata_add(context
, md
, KRB5_PADATA_PK_AS_09_BINDING
, NULL
, 0);
794 free_ContentInfo(&content_info
);
800 krb5_error_code KRB5_LIB_FUNCTION
801 _krb5_pk_mk_padata(krb5_context context
,
803 const KDC_REQ_BODY
*req_body
,
807 krb5_pk_init_ctx ctx
= c
;
810 if (ctx
->id
->certs
== NULL
&& ctx
->anonymous
== 0) {
811 krb5_set_error_message(context
, HEIM_PKINIT_NO_PRIVATE_KEY
,
812 N_("PKINIT: No user certificate given", ""));
813 return HEIM_PKINIT_NO_PRIVATE_KEY
;
816 win2k_compat
= krb5_config_get_bool_default(context
, NULL
,
824 ctx
->require_binding
=
825 krb5_config_get_bool_default(context
, NULL
,
829 "pkinit_win2k_require_binding",
831 ctx
->type
= PKINIT_WIN2K
;
833 ctx
->type
= PKINIT_27
;
836 krb5_config_get_bool_default(context
, NULL
,
840 "pkinit_require_eku",
842 ctx
->require_krbtgt_otherName
=
843 krb5_config_get_bool_default(context
, NULL
,
847 "pkinit_require_krbtgt_otherName",
850 ctx
->require_hostname_match
=
851 krb5_config_get_bool_default(context
, NULL
,
855 "pkinit_require_hostname_match",
858 ctx
->trustedCertifiers
=
859 krb5_config_get_bool_default(context
, NULL
,
863 "pkinit_trustedCertifiers",
866 return pk_mk_padata(context
, ctx
, req_body
, nonce
, md
);
869 static krb5_error_code
870 pk_verify_sign(krb5_context context
,
873 struct krb5_pk_identity
*id
,
874 heim_oid
*contentType
,
876 struct krb5_pk_cert
**signer
)
878 hx509_certs signer_certs
;
883 ret
= hx509_cms_verify_signed(context
->hx509ctx
,
885 HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH
|HX509_CMS_VS_NO_KU_CHECK
,
894 pk_copy_error(context
, context
->hx509ctx
, ret
,
895 "CMS verify signed failed");
899 *signer
= calloc(1, sizeof(**signer
));
900 if (*signer
== NULL
) {
901 krb5_clear_error_message(context
);
906 ret
= hx509_get_one_cert(context
->hx509ctx
, signer_certs
, &(*signer
)->cert
);
908 pk_copy_error(context
, context
->hx509ctx
, ret
,
909 "Failed to get on of the signer certs");
914 hx509_certs_free(&signer_certs
);
917 hx509_cert_free((*signer
)->cert
);
926 static krb5_error_code
927 get_reply_key_win(krb5_context context
,
928 const krb5_data
*content
,
932 ReplyKeyPack_Win2k key_pack
;
936 ret
= decode_ReplyKeyPack_Win2k(content
->data
,
941 krb5_set_error_message(context
, ret
,
942 N_("PKINIT decoding reply key failed", ""));
943 free_ReplyKeyPack_Win2k(&key_pack
);
947 if (key_pack
.nonce
!= nonce
) {
948 krb5_set_error_message(context
, ret
,
949 N_("PKINIT enckey nonce is wrong", ""));
950 free_ReplyKeyPack_Win2k(&key_pack
);
951 return KRB5KRB_AP_ERR_MODIFIED
;
954 *key
= malloc (sizeof (**key
));
956 free_ReplyKeyPack_Win2k(&key_pack
);
957 krb5_set_error_message(context
, ENOMEM
,
958 N_("malloc: out of memory", ""));
962 ret
= copy_EncryptionKey(&key_pack
.replyKey
, *key
);
963 free_ReplyKeyPack_Win2k(&key_pack
);
965 krb5_set_error_message(context
, ret
,
966 N_("PKINIT failed copying reply key", ""));
974 static krb5_error_code
975 get_reply_key(krb5_context context
,
976 const krb5_data
*content
,
977 const krb5_data
*req_buffer
,
980 ReplyKeyPack key_pack
;
984 ret
= decode_ReplyKeyPack(content
->data
,
989 krb5_set_error_message(context
, ret
,
990 N_("PKINIT decoding reply key failed", ""));
991 free_ReplyKeyPack(&key_pack
);
999 * XXX Verify kp.replyKey is a allowed enctype in the
1000 * configuration file
1003 ret
= krb5_crypto_init(context
, &key_pack
.replyKey
, 0, &crypto
);
1005 free_ReplyKeyPack(&key_pack
);
1009 ret
= krb5_verify_checksum(context
, crypto
, 6,
1010 req_buffer
->data
, req_buffer
->length
,
1011 &key_pack
.asChecksum
);
1012 krb5_crypto_destroy(context
, crypto
);
1014 free_ReplyKeyPack(&key_pack
);
1019 *key
= malloc (sizeof (**key
));
1021 free_ReplyKeyPack(&key_pack
);
1022 krb5_set_error_message(context
, ENOMEM
,
1023 N_("malloc: out of memory", ""));
1027 ret
= copy_EncryptionKey(&key_pack
.replyKey
, *key
);
1028 free_ReplyKeyPack(&key_pack
);
1030 krb5_set_error_message(context
, ret
,
1031 N_("PKINIT failed copying reply key", ""));
1040 static krb5_error_code
1041 pk_verify_host(krb5_context context
,
1043 const krb5_krbhst_info
*hi
,
1044 struct krb5_pk_init_ctx_data
*ctx
,
1045 struct krb5_pk_cert
*host
)
1047 krb5_error_code ret
= 0;
1049 if (ctx
->require_eku
) {
1050 ret
= hx509_cert_check_eku(context
->hx509ctx
, host
->cert
,
1051 &asn1_oid_id_pkkdcekuoid
, 0);
1053 krb5_set_error_message(context
, ret
,
1054 N_("No PK-INIT KDC EKU in kdc certificate", ""));
1058 if (ctx
->require_krbtgt_otherName
) {
1059 hx509_octet_string_list list
;
1062 ret
= hx509_cert_find_subjectAltName_otherName(context
->hx509ctx
,
1064 &asn1_oid_id_pkinit_san
,
1067 krb5_set_error_message(context
, ret
,
1068 N_("Failed to find the PK-INIT "
1069 "subjectAltName in the KDC "
1070 "certificate", ""));
1075 for (i
= 0; i
< list
.len
; i
++) {
1076 KRB5PrincipalName r
;
1078 ret
= decode_KRB5PrincipalName(list
.val
[i
].data
,
1083 krb5_set_error_message(context
, ret
,
1084 N_("Failed to decode the PK-INIT "
1085 "subjectAltName in the "
1086 "KDC certificate", ""));
1091 if (r
.principalName
.name_string
.len
!= 2 ||
1092 strcmp(r
.principalName
.name_string
.val
[0], KRB5_TGS_NAME
) != 0 ||
1093 strcmp(r
.principalName
.name_string
.val
[1], realm
) != 0 ||
1094 strcmp(r
.realm
, realm
) != 0)
1096 ret
= KRB5_KDC_ERR_INVALID_CERTIFICATE
;
1097 krb5_set_error_message(context
, ret
,
1098 N_("KDC have wrong realm name in "
1099 "the certificate", ""));
1102 free_KRB5PrincipalName(&r
);
1106 hx509_free_octet_string_list(&list
);
1112 ret
= hx509_verify_hostname(context
->hx509ctx
, host
->cert
,
1113 ctx
->require_hostname_match
,
1116 hi
->ai
->ai_addr
, hi
->ai
->ai_addrlen
);
1119 krb5_set_error_message(context
, ret
,
1120 N_("Address mismatch in "
1121 "the KDC certificate", ""));
1126 static krb5_error_code
1127 pk_rd_pa_reply_enckey(krb5_context context
,
1129 const heim_octet_string
*indata
,
1130 const heim_oid
*dataType
,
1132 krb5_pk_init_ctx ctx
,
1134 const krb5_krbhst_info
*hi
,
1136 const krb5_data
*req_buffer
,
1138 krb5_keyblock
**key
)
1140 krb5_error_code ret
;
1141 struct krb5_pk_cert
*host
= NULL
;
1143 heim_oid contentType
= { 0, NULL
};
1144 int flags
= HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT
;
1146 if (der_heim_oid_cmp(&asn1_oid_id_pkcs7_envelopedData
, dataType
)) {
1147 krb5_set_error_message(context
, EINVAL
,
1148 N_("PKINIT: Invalid content type", ""));
1152 if (ctx
->type
== PKINIT_WIN2K
)
1153 flags
|= HX509_CMS_UE_ALLOW_WEAK
;
1155 ret
= hx509_cms_unenvelope(context
->hx509ctx
,
1165 pk_copy_error(context
, context
->hx509ctx
, ret
,
1166 "Failed to unenvelope CMS data in PK-INIT reply");
1169 der_free_oid(&contentType
);
1171 /* win2k uses ContentInfo */
1172 if (type
== PKINIT_WIN2K
) {
1174 heim_octet_string out
;
1176 ret
= hx509_cms_unwrap_ContentInfo(&content
, &type
, &out
, NULL
);
1178 /* windows LH with interesting CMS packets */
1179 size_t ph
= 1 + der_length_len(content
.length
);
1180 unsigned char *ptr
= malloc(content
.length
+ ph
);
1183 memcpy(ptr
+ ph
, content
.data
, content
.length
);
1185 ret
= der_put_length_and_tag (ptr
+ ph
- 1, ph
, content
.length
,
1186 ASN1_C_UNIV
, CONS
, UT_Sequence
, &l
);
1191 content
.length
+= ph
;
1193 ret
= hx509_cms_unwrap_ContentInfo(&content
, &type
, &out
, NULL
);
1197 if (der_heim_oid_cmp(&type
, &asn1_oid_id_pkcs7_signedData
)) {
1198 ret
= EINVAL
; /* XXX */
1199 krb5_set_error_message(context
, ret
,
1200 N_("PKINIT: Invalid content type", ""));
1201 der_free_oid(&type
);
1202 der_free_octet_string(&out
);
1205 der_free_oid(&type
);
1206 krb5_data_free(&content
);
1207 ret
= krb5_data_copy(&content
, out
.data
, out
.length
);
1208 der_free_octet_string(&out
);
1210 krb5_set_error_message(context
, ret
,
1211 N_("malloc: out of memory", ""));
1216 ret
= pk_verify_sign(context
,
1226 /* make sure that it is the kdc's certificate */
1227 ret
= pk_verify_host(context
, realm
, hi
, ctx
, host
);
1233 if (type
== PKINIT_WIN2K
) {
1234 if (der_heim_oid_cmp(&contentType
, &asn1_oid_id_pkcs7_data
) != 0) {
1235 ret
= KRB5KRB_AP_ERR_MSG_TYPE
;
1236 krb5_set_error_message(context
, ret
, "PKINIT: reply key, wrong oid");
1240 if (der_heim_oid_cmp(&contentType
, &asn1_oid_id_pkrkeydata
) != 0) {
1241 ret
= KRB5KRB_AP_ERR_MSG_TYPE
;
1242 krb5_set_error_message(context
, ret
, "PKINIT: reply key, wrong oid");
1250 ret
= get_reply_key(context
, &content
, req_buffer
, key
);
1251 if (ret
!= 0 && ctx
->require_binding
== 0)
1252 ret
= get_reply_key_win(context
, &content
, nonce
, key
);
1255 ret
= get_reply_key(context
, &content
, req_buffer
, key
);
1261 /* XXX compare given etype with key->etype */
1265 _krb5_pk_cert_free(host
);
1266 der_free_oid(&contentType
);
1267 krb5_data_free(&content
);
1272 static krb5_error_code
1273 pk_rd_pa_reply_dh(krb5_context context
,
1274 const heim_octet_string
*indata
,
1275 const heim_oid
*dataType
,
1277 krb5_pk_init_ctx ctx
,
1279 const krb5_krbhst_info
*hi
,
1284 krb5_keyblock
**key
)
1286 const unsigned char *p
;
1287 unsigned char *dh_gen_key
= NULL
;
1288 struct krb5_pk_cert
*host
= NULL
;
1289 BIGNUM
*kdc_dh_pubkey
= NULL
;
1290 KDCDHKeyInfo kdc_dh_info
;
1291 heim_oid contentType
= { 0, NULL
};
1293 krb5_error_code ret
;
1294 int dh_gen_keylen
= 0;
1297 krb5_data_zero(&content
);
1298 memset(&kdc_dh_info
, 0, sizeof(kdc_dh_info
));
1300 if (der_heim_oid_cmp(&asn1_oid_id_pkcs7_signedData
, dataType
)) {
1301 krb5_set_error_message(context
, EINVAL
,
1302 N_("PKINIT: Invalid content type", ""));
1306 ret
= pk_verify_sign(context
,
1316 /* make sure that it is the kdc's certificate */
1317 ret
= pk_verify_host(context
, realm
, hi
, ctx
, host
);
1321 if (der_heim_oid_cmp(&contentType
, &asn1_oid_id_pkdhkeydata
)) {
1322 ret
= KRB5KRB_AP_ERR_MSG_TYPE
;
1323 krb5_set_error_message(context
, ret
,
1324 N_("pkinit - dh reply contains wrong oid", ""));
1328 ret
= decode_KDCDHKeyInfo(content
.data
,
1334 krb5_set_error_message(context
, ret
,
1335 N_("pkinit - failed to decode "
1336 "KDC DH Key Info", ""));
1340 if (kdc_dh_info
.nonce
!= nonce
) {
1341 ret
= KRB5KRB_AP_ERR_MODIFIED
;
1342 krb5_set_error_message(context
, ret
,
1343 N_("PKINIT: DH nonce is wrong", ""));
1347 if (kdc_dh_info
.dhKeyExpiration
) {
1349 ret
= KRB5KRB_ERR_GENERIC
;
1350 krb5_set_error_message(context
, ret
,
1351 N_("pkinit; got key expiration "
1352 "without server nonce", ""));
1356 ret
= KRB5KRB_ERR_GENERIC
;
1357 krb5_set_error_message(context
, ret
,
1358 N_("pkinit; got DH reuse but no "
1359 "client nonce", ""));
1364 ret
= KRB5KRB_ERR_GENERIC
;
1365 krb5_set_error_message(context
, ret
,
1366 N_("pkinit: got server nonce "
1367 "without key expiration", ""));
1374 p
= kdc_dh_info
.subjectPublicKey
.data
;
1375 size
= (kdc_dh_info
.subjectPublicKey
.length
+ 7) / 8;
1377 if (ctx
->keyex
== USE_DH
) {
1379 ret
= decode_DHPublicKey(p
, size
, &k
, NULL
);
1381 krb5_set_error_message(context
, ret
,
1382 N_("pkinit: can't decode "
1383 "without key expiration", ""));
1387 kdc_dh_pubkey
= integer_to_BN(context
, "DHPublicKey", &k
);
1388 free_DHPublicKey(&k
);
1389 if (kdc_dh_pubkey
== NULL
) {
1395 dh_gen_keylen
= DH_size(ctx
->u
.dh
);
1396 size
= BN_num_bytes(ctx
->u
.dh
->p
);
1397 if (size
< dh_gen_keylen
)
1398 size
= dh_gen_keylen
;
1400 dh_gen_key
= malloc(size
);
1401 if (dh_gen_key
== NULL
) {
1403 krb5_set_error_message(context
, ret
, N_("malloc: out of memory", ""));
1406 memset(dh_gen_key
, 0, size
- dh_gen_keylen
);
1408 dh_gen_keylen
= DH_compute_key(dh_gen_key
+ (size
- dh_gen_keylen
),
1409 kdc_dh_pubkey
, ctx
->u
.dh
);
1410 if (dh_gen_keylen
== -1) {
1411 ret
= KRB5KRB_ERR_GENERIC
;
1413 krb5_set_error_message(context
, ret
,
1414 N_("PKINIT: Can't compute Diffie-Hellman key", ""));
1419 const EC_GROUP
*group
;
1420 EC_KEY
*public = NULL
;
1422 group
= EC_KEY_get0_group(ctx
->u
.eckey
);
1424 public = EC_KEY_new();
1425 if (public == NULL
) {
1429 if (EC_KEY_set_group(public, group
) != 1) {
1430 EC_KEY_free(public);
1435 if (o2i_ECPublicKey(&public, &p
, size
) == NULL
) {
1436 EC_KEY_free(public);
1437 ret
= KRB5KRB_ERR_GENERIC
;
1438 krb5_set_error_message(context
, ret
,
1439 N_("PKINIT: Can't parse ECDH public key", ""));
1443 size
= (EC_GROUP_get_degree(group
) + 7) / 8;
1444 dh_gen_key
= malloc(size
);
1445 if (dh_gen_key
== NULL
) {
1446 EC_KEY_free(public);
1448 krb5_set_error_message(context
, ret
,
1449 N_("malloc: out of memory", ""));
1452 dh_gen_keylen
= ECDH_compute_key(dh_gen_key
, size
,
1453 EC_KEY_get0_public_key(public), ctx
->u
.eckey
, NULL
);
1454 EC_KEY_free(public);
1455 if (dh_gen_keylen
== -1) {
1456 ret
= KRB5KRB_ERR_GENERIC
;
1458 krb5_set_error_message(context
, ret
,
1459 N_("PKINIT: Can't compute ECDH public key", ""));
1467 if (dh_gen_keylen
<= 0) {
1469 krb5_set_error_message(context
, ret
,
1470 N_("PKINIT: resulting DH key <= 0", ""));
1475 *key
= malloc (sizeof (**key
));
1478 krb5_set_error_message(context
, ret
,
1479 N_("malloc: out of memory", ""));
1483 ret
= _krb5_pk_octetstring2key(context
,
1485 dh_gen_key
, dh_gen_keylen
,
1489 krb5_set_error_message(context
, ret
,
1490 N_("PKINIT: can't create key from DH key", ""));
1498 BN_free(kdc_dh_pubkey
);
1500 memset(dh_gen_key
, 0, dh_gen_keylen
);
1504 _krb5_pk_cert_free(host
);
1506 krb5_data_free(&content
);
1507 der_free_oid(&contentType
);
1508 free_KDCDHKeyInfo(&kdc_dh_info
);
1513 krb5_error_code KRB5_LIB_FUNCTION
1514 _krb5_pk_rd_pa_reply(krb5_context context
,
1518 const krb5_krbhst_info
*hi
,
1520 const krb5_data
*req_buffer
,
1522 krb5_keyblock
**key
)
1524 krb5_pk_init_ctx ctx
= c
;
1525 krb5_error_code ret
;
1528 /* Check for IETF PK-INIT first */
1529 if (ctx
->type
== PKINIT_27
) {
1531 heim_octet_string os
, data
;
1534 if (pa
->padata_type
!= KRB5_PADATA_PK_AS_REP
) {
1535 krb5_set_error_message(context
, EINVAL
,
1536 N_("PKINIT: wrong padata recv", ""));
1540 ret
= decode_PA_PK_AS_REP(pa
->padata_value
.data
,
1541 pa
->padata_value
.length
,
1545 krb5_set_error_message(context
, ret
,
1546 N_("Failed to decode pkinit AS rep", ""));
1550 switch (rep
.element
) {
1551 case choice_PA_PK_AS_REP_dhInfo
:
1552 os
= rep
.u
.dhInfo
.dhSignedData
;
1554 case choice_PA_PK_AS_REP_encKeyPack
:
1555 os
= rep
.u
.encKeyPack
;
1558 PA_PK_AS_REP_BTMM btmm
;
1559 free_PA_PK_AS_REP(&rep
);
1560 memset(&rep
, 0, sizeof(rep
));
1562 ret
= decode_PA_PK_AS_REP_BTMM(pa
->padata_value
.data
,
1563 pa
->padata_value
.length
,
1567 krb5_set_error_message(context
, EINVAL
,
1568 N_("PKINIT: -27 reply "
1569 "invalid content type", ""));
1573 if (btmm
.dhSignedData
|| btmm
.encKeyPack
== NULL
) {
1574 free_PA_PK_AS_REP_BTMM(&btmm
);
1576 krb5_set_error_message(context
, ret
,
1577 N_("DH mode not supported for BTMM mode", ""));
1582 * Transform to IETF style PK-INIT reply so that free works below
1585 rep
.element
= choice_PA_PK_AS_REP_encKeyPack
;
1586 rep
.u
.encKeyPack
.data
= btmm
.encKeyPack
->data
;
1587 rep
.u
.encKeyPack
.length
= btmm
.encKeyPack
->length
;
1588 btmm
.encKeyPack
->data
= NULL
;
1589 btmm
.encKeyPack
->length
= 0;
1590 free_PA_PK_AS_REP_BTMM(&btmm
);
1591 os
= rep
.u
.encKeyPack
;
1595 ret
= hx509_cms_unwrap_ContentInfo(&os
, &oid
, &data
, NULL
);
1597 free_PA_PK_AS_REP(&rep
);
1598 krb5_set_error_message(context
, ret
,
1599 N_("PKINIT: failed to unwrap CI", ""));
1603 switch (rep
.element
) {
1604 case choice_PA_PK_AS_REP_dhInfo
:
1605 ret
= pk_rd_pa_reply_dh(context
, &data
, &oid
, realm
, ctx
, etype
, hi
,
1607 rep
.u
.dhInfo
.serverDHNonce
,
1610 case choice_PA_PK_AS_REP_encKeyPack
:
1611 ret
= pk_rd_pa_reply_enckey(context
, PKINIT_27
, &data
, &oid
, realm
,
1612 ctx
, etype
, hi
, nonce
, req_buffer
, pa
, key
);
1615 krb5_abortx(context
, "pk-init as-rep case not possible to happen");
1617 der_free_octet_string(&data
);
1619 free_PA_PK_AS_REP(&rep
);
1621 } else if (ctx
->type
== PKINIT_WIN2K
) {
1622 PA_PK_AS_REP_Win2k w2krep
;
1624 /* Check for Windows encoding of the AS-REP pa data */
1626 #if 0 /* should this be ? */
1627 if (pa
->padata_type
!= KRB5_PADATA_PK_AS_REP
) {
1628 krb5_set_error_message(context
, EINVAL
,
1629 "PKINIT: wrong padata recv");
1634 memset(&w2krep
, 0, sizeof(w2krep
));
1636 ret
= decode_PA_PK_AS_REP_Win2k(pa
->padata_value
.data
,
1637 pa
->padata_value
.length
,
1641 krb5_set_error_message(context
, ret
,
1642 N_("PKINIT: Failed decoding windows "
1643 "pkinit reply %d", ""), (int)ret
);
1647 krb5_clear_error_message(context
);
1649 switch (w2krep
.element
) {
1650 case choice_PA_PK_AS_REP_Win2k_encKeyPack
: {
1651 heim_octet_string data
;
1654 ret
= hx509_cms_unwrap_ContentInfo(&w2krep
.u
.encKeyPack
,
1656 free_PA_PK_AS_REP_Win2k(&w2krep
);
1658 krb5_set_error_message(context
, ret
,
1659 N_("PKINIT: failed to unwrap CI", ""));
1663 ret
= pk_rd_pa_reply_enckey(context
, PKINIT_WIN2K
, &data
, &oid
, realm
,
1664 ctx
, etype
, hi
, nonce
, req_buffer
, pa
, key
);
1665 der_free_octet_string(&data
);
1671 free_PA_PK_AS_REP_Win2k(&w2krep
);
1673 krb5_set_error_message(context
, ret
,
1674 N_("PKINIT: win2k reply invalid "
1675 "content type", ""));
1681 krb5_set_error_message(context
, ret
,
1682 N_("PKINIT: unknown reply type", ""));
1689 krb5_context context
;
1690 krb5_prompter_fct prompter
;
1691 void *prompter_data
;
1695 hx_pass_prompter(void *data
, const hx509_prompt
*prompter
)
1697 krb5_error_code ret
;
1699 krb5_data password_data
;
1700 struct prompter
*p
= data
;
1702 password_data
.data
= prompter
->reply
.data
;
1703 password_data
.length
= prompter
->reply
.length
;
1705 prompt
.prompt
= prompter
->prompt
;
1706 prompt
.hidden
= hx509_prompt_hidden(prompter
->type
);
1707 prompt
.reply
= &password_data
;
1709 switch (prompter
->type
) {
1710 case HX509_PROMPT_TYPE_INFO
:
1711 prompt
.type
= KRB5_PROMPT_TYPE_INFO
;
1713 case HX509_PROMPT_TYPE_PASSWORD
:
1714 case HX509_PROMPT_TYPE_QUESTION
:
1716 prompt
.type
= KRB5_PROMPT_TYPE_PASSWORD
;
1720 ret
= (*p
->prompter
)(p
->context
, p
->prompter_data
, NULL
, NULL
, 1, &prompt
);
1722 memset (prompter
->reply
.data
, 0, prompter
->reply
.length
);
1728 static krb5_error_code
1729 _krb5_pk_set_user_id(krb5_context context
,
1730 krb5_pk_init_ctx ctx
,
1731 struct hx509_certs_data
*certs
)
1733 hx509_certs c
= hx509_certs_ref(certs
);
1734 hx509_query
*q
= NULL
;
1738 hx509_certs_free(&ctx
->id
->certs
);
1739 if (ctx
->id
->cert
) {
1740 hx509_cert_free(ctx
->id
->cert
);
1741 ctx
->id
->cert
= NULL
;
1747 ret
= hx509_query_alloc(context
->hx509ctx
, &q
);
1749 pk_copy_error(context
, context
->hx509ctx
, ret
,
1750 "Allocate query to find signing certificate");
1754 hx509_query_match_option(q
, HX509_QUERY_OPTION_PRIVATE_KEY
);
1755 hx509_query_match_option(q
, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE
);
1757 ret
= find_cert(context
, ctx
->id
, q
, &ctx
->id
->cert
);
1758 hx509_query_free(context
->hx509ctx
, q
);
1763 krb5_error_code KRB5_LIB_FUNCTION
1764 _krb5_pk_load_id(krb5_context context
,
1765 struct krb5_pk_identity
**ret_id
,
1766 const char *user_id
,
1767 const char *anchor_id
,
1768 char * const *chain_list
,
1769 char * const *revoke_list
,
1770 krb5_prompter_fct prompter
,
1771 void *prompter_data
,
1774 struct krb5_pk_identity
*id
= NULL
;
1780 if (anchor_id
== NULL
) {
1781 krb5_set_error_message(context
, HEIM_PKINIT_NO_VALID_CA
,
1782 N_("PKINIT: No anchor given", ""));
1783 return HEIM_PKINIT_NO_VALID_CA
;
1788 id
= calloc(1, sizeof(*id
));
1790 krb5_set_error_message(context
, ENOMEM
,
1791 N_("malloc: out of memory", ""));
1798 ret
= hx509_lock_init(context
->hx509ctx
, &lock
);
1800 pk_copy_error(context
, context
->hx509ctx
, ret
, "Failed init lock");
1804 if (password
&& password
[0])
1805 hx509_lock_add_password(lock
, password
);
1808 p
.context
= context
;
1809 p
.prompter
= prompter
;
1810 p
.prompter_data
= prompter_data
;
1812 ret
= hx509_lock_set_prompter(lock
, hx_pass_prompter
, &p
);
1814 hx509_lock_free(lock
);
1819 ret
= hx509_certs_init(context
->hx509ctx
, user_id
, 0, lock
, &id
->certs
);
1820 hx509_lock_free(lock
);
1822 pk_copy_error(context
, context
->hx509ctx
, ret
,
1823 "Failed to init cert certs");
1830 ret
= hx509_certs_init(context
->hx509ctx
, anchor_id
, 0, NULL
, &id
->anchors
);
1832 pk_copy_error(context
, context
->hx509ctx
, ret
,
1833 "Failed to init anchors");
1837 ret
= hx509_certs_init(context
->hx509ctx
, "MEMORY:pkinit-cert-chain",
1838 0, NULL
, &id
->certpool
);
1840 pk_copy_error(context
, context
->hx509ctx
, ret
,
1841 "Failed to init chain");
1845 while (chain_list
&& *chain_list
) {
1846 ret
= hx509_certs_append(context
->hx509ctx
, id
->certpool
,
1849 pk_copy_error(context
, context
->hx509ctx
, ret
,
1850 "Failed to laod chain %s",
1858 ret
= hx509_revoke_init(context
->hx509ctx
, &id
->revokectx
);
1860 pk_copy_error(context
, context
->hx509ctx
, ret
,
1861 "Failed init revoke list");
1865 while (*revoke_list
) {
1866 ret
= hx509_revoke_add_crl(context
->hx509ctx
,
1870 pk_copy_error(context
, context
->hx509ctx
, ret
,
1871 "Failed load revoke list");
1877 hx509_context_set_missing_revoke(context
->hx509ctx
, 1);
1879 ret
= hx509_verify_init_ctx(context
->hx509ctx
, &id
->verify_ctx
);
1881 pk_copy_error(context
, context
->hx509ctx
, ret
,
1882 "Failed init verify context");
1886 hx509_verify_attach_anchors(id
->verify_ctx
, id
->anchors
);
1887 hx509_verify_attach_revoke(id
->verify_ctx
, id
->revokectx
);
1891 hx509_verify_destroy_ctx(id
->verify_ctx
);
1892 hx509_certs_free(&id
->certs
);
1893 hx509_certs_free(&id
->anchors
);
1894 hx509_certs_free(&id
->certpool
);
1895 hx509_revoke_free(&id
->revokectx
);
1908 pk_copy_error(krb5_context context
,
1909 hx509_context hx509ctx
,
1919 ret
= vasprintf(&f
, fmt
, va
);
1921 if (ret
== -1 || f
== NULL
) {
1922 krb5_clear_error_message(context
);
1926 s
= hx509_get_error_string(hx509ctx
, hxret
);
1928 krb5_clear_error_message(context
);
1932 krb5_set_error_message(context
, hxret
, "%s: %s", f
, s
);
1938 parse_integer(krb5_context context
, char **p
, const char *file
, int lineno
,
1939 const char *name
, heim_integer
*integer
)
1943 p1
= strsep(p
, " \t");
1945 krb5_set_error_message(context
, EINVAL
,
1946 N_("moduli file %s missing %s on line %d", ""),
1947 file
, name
, lineno
);
1950 ret
= der_parse_hex_heim_integer(p1
, integer
);
1952 krb5_set_error_message(context
, ret
,
1953 N_("moduli file %s failed parsing %s "
1955 file
, name
, lineno
);
1963 _krb5_parse_moduli_line(krb5_context context
,
1967 struct krb5_dh_moduli
**m
)
1969 struct krb5_dh_moduli
*m1
;
1975 m1
= calloc(1, sizeof(*m1
));
1977 krb5_set_error_message(context
, ENOMEM
,
1978 N_("malloc: out of memory", ""));
1982 while (isspace((unsigned char)*p
))
1990 p1
= strsep(&p
, " \t");
1992 krb5_set_error_message(context
, ret
,
1993 N_("moduli file %s missing name on line %d", ""),
1997 m1
->name
= strdup(p1
);
1998 if (m1
->name
== NULL
) {
2000 krb5_set_error_message(context
, ret
, N_("malloc: out of memeory", ""));
2004 p1
= strsep(&p
, " \t");
2006 krb5_set_error_message(context
, ret
,
2007 N_("moduli file %s missing bits on line %d", ""),
2012 m1
->bits
= atoi(p1
);
2013 if (m1
->bits
== 0) {
2014 krb5_set_error_message(context
, ret
,
2015 N_("moduli file %s have un-parsable "
2016 "bits on line %d", ""), file
, lineno
);
2020 ret
= parse_integer(context
, &p
, file
, lineno
, "p", &m1
->p
);
2023 ret
= parse_integer(context
, &p
, file
, lineno
, "g", &m1
->g
);
2026 ret
= parse_integer(context
, &p
, file
, lineno
, "q", &m1
->q
);
2035 der_free_heim_integer(&m1
->p
);
2036 der_free_heim_integer(&m1
->g
);
2037 der_free_heim_integer(&m1
->q
);
2043 _krb5_free_moduli(struct krb5_dh_moduli
**moduli
)
2046 for (i
= 0; moduli
[i
] != NULL
; i
++) {
2047 free(moduli
[i
]->name
);
2048 der_free_heim_integer(&moduli
[i
]->p
);
2049 der_free_heim_integer(&moduli
[i
]->g
);
2050 der_free_heim_integer(&moduli
[i
]->q
);
2056 static const char *default_moduli_RFC2412_MODP_group2
=
2058 "RFC2412-MODP-group2 "
2062 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
2063 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
2064 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
2065 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
2066 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
2067 "FFFFFFFF" "FFFFFFFF "
2071 "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68"
2072 "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E"
2073 "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122"
2074 "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6"
2075 "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F67329C0"
2076 "FFFFFFFF" "FFFFFFFF";
2078 static const char *default_moduli_rfc3526_MODP_group14
=
2080 "rfc3526-MODP-group14 "
2084 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
2085 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
2086 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
2087 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
2088 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D"
2089 "C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"
2090 "83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"
2091 "670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"
2092 "E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"
2093 "DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
2094 "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF "
2098 "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68"
2099 "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E"
2100 "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122"
2101 "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6"
2102 "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F6722D9E"
2103 "E1003E5C" "50B1DF82" "CC6D241B" "0E2AE9CD" "348B1FD4" "7E9267AF"
2104 "C1B2AE91" "EE51D6CB" "0E3179AB" "1042A95D" "CF6A9483" "B84B4B36"
2105 "B3861AA7" "255E4C02" "78BA3604" "650C10BE" "19482F23" "171B671D"
2106 "F1CF3B96" "0C074301" "CD93C1D1" "7603D147" "DAE2AEF8" "37A62964"
2107 "EF15E5FB" "4AAC0B8C" "1CCAA4BE" "754AB572" "8AE9130C" "4C7D0288"
2108 "0AB9472D" "45565534" "7FFFFFFF" "FFFFFFFF";
2111 _krb5_parse_moduli(krb5_context context
, const char *file
,
2112 struct krb5_dh_moduli
***moduli
)
2114 /* name bits P G Q */
2115 krb5_error_code ret
;
2116 struct krb5_dh_moduli
**m
= NULL
, **m2
;
2119 int lineno
= 0, n
= 0;
2123 m
= calloc(1, sizeof(m
[0]) * 3);
2125 krb5_set_error_message(context
, ENOMEM
,
2126 N_("malloc: out of memory", ""));
2130 strlcpy(buf
, default_moduli_rfc3526_MODP_group14
, sizeof(buf
));
2131 ret
= _krb5_parse_moduli_line(context
, "builtin", 1, buf
, &m
[0]);
2133 _krb5_free_moduli(m
);
2138 strlcpy(buf
, default_moduli_RFC2412_MODP_group2
, sizeof(buf
));
2139 ret
= _krb5_parse_moduli_line(context
, "builtin", 1, buf
, &m
[1]);
2141 _krb5_free_moduli(m
);
2150 f
= fopen(file
, "r");
2157 while(fgets(buf
, sizeof(buf
), f
) != NULL
) {
2158 struct krb5_dh_moduli
*element
;
2160 buf
[strcspn(buf
, "\n")] = '\0';
2163 m2
= realloc(m
, (n
+ 2) * sizeof(m
[0]));
2165 _krb5_free_moduli(m
);
2166 krb5_set_error_message(context
, ENOMEM
,
2167 N_("malloc: out of memory", ""));
2174 ret
= _krb5_parse_moduli_line(context
, file
, lineno
, buf
, &element
);
2176 _krb5_free_moduli(m
);
2179 if (element
== NULL
)
2191 _krb5_dh_group_ok(krb5_context context
, unsigned long bits
,
2192 heim_integer
*p
, heim_integer
*g
, heim_integer
*q
,
2193 struct krb5_dh_moduli
**moduli
,
2201 for (i
= 0; moduli
[i
] != NULL
; i
++) {
2202 if (der_heim_integer_cmp(&moduli
[i
]->g
, g
) == 0 &&
2203 der_heim_integer_cmp(&moduli
[i
]->p
, p
) == 0 &&
2204 (q
== NULL
|| der_heim_integer_cmp(&moduli
[i
]->q
, q
) == 0))
2206 if (bits
&& bits
> moduli
[i
]->bits
) {
2207 krb5_set_error_message(context
,
2208 KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED
,
2209 N_("PKINIT: DH group parameter %s "
2210 "no accepted, not enough bits "
2213 return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED
;
2216 *name
= strdup(moduli
[i
]->name
);
2220 krb5_set_error_message(context
,
2221 KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED
,
2222 N_("PKINIT: DH group parameter no ok", ""));
2223 return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED
;
2227 void KRB5_LIB_FUNCTION
2228 _krb5_get_init_creds_opt_free_pkinit(krb5_get_init_creds_opt
*opt
)
2231 krb5_pk_init_ctx ctx
;
2233 if (opt
->opt_private
== NULL
|| opt
->opt_private
->pk_init_ctx
== NULL
)
2235 ctx
= opt
->opt_private
->pk_init_ctx
;
2236 switch (ctx
->keyex
) {
2246 EC_KEY_free(ctx
->u
.eckey
);
2251 hx509_verify_destroy_ctx(ctx
->id
->verify_ctx
);
2252 hx509_certs_free(&ctx
->id
->certs
);
2253 hx509_cert_free(ctx
->id
->cert
);
2254 hx509_certs_free(&ctx
->id
->anchors
);
2255 hx509_certs_free(&ctx
->id
->certpool
);
2257 if (ctx
->clientDHNonce
) {
2258 krb5_free_data(NULL
, ctx
->clientDHNonce
);
2259 ctx
->clientDHNonce
= NULL
;
2262 _krb5_free_moduli(ctx
->m
);
2266 free(opt
->opt_private
->pk_init_ctx
);
2267 opt
->opt_private
->pk_init_ctx
= NULL
;
2271 krb5_error_code KRB5_LIB_FUNCTION
2272 krb5_get_init_creds_opt_set_pkinit(krb5_context context
,
2273 krb5_get_init_creds_opt
*opt
,
2274 krb5_principal principal
,
2275 const char *user_id
,
2276 const char *x509_anchors
,
2277 char * const * pool
,
2278 char * const * pki_revoke
,
2280 krb5_prompter_fct prompter
,
2281 void *prompter_data
,
2285 krb5_error_code ret
;
2286 char *anchors
= NULL
;
2288 if (opt
->opt_private
== NULL
) {
2289 krb5_set_error_message(context
, EINVAL
,
2290 N_("PKINIT: on non extendable opt", ""));
2294 opt
->opt_private
->pk_init_ctx
=
2295 calloc(1, sizeof(*opt
->opt_private
->pk_init_ctx
));
2296 if (opt
->opt_private
->pk_init_ctx
== NULL
) {
2297 krb5_set_error_message(context
, ENOMEM
,
2298 N_("malloc: out of memory", ""));
2301 opt
->opt_private
->pk_init_ctx
->require_binding
= 0;
2302 opt
->opt_private
->pk_init_ctx
->require_eku
= 1;
2303 opt
->opt_private
->pk_init_ctx
->require_krbtgt_otherName
= 1;
2304 opt
->opt_private
->pk_init_ctx
->peer
= NULL
;
2306 /* XXX implement krb5_appdefault_strings */
2308 pool
= krb5_config_get_strings(context
, NULL
,
2313 if (pki_revoke
== NULL
)
2314 pki_revoke
= krb5_config_get_strings(context
, NULL
,
2319 if (x509_anchors
== NULL
) {
2320 krb5_appdefault_string(context
, "kinit",
2321 krb5_principal_get_realm(context
, principal
),
2322 "pkinit_anchors", NULL
, &anchors
);
2323 x509_anchors
= anchors
;
2327 opt
->opt_private
->pk_init_ctx
->anonymous
= 1;
2329 ret
= _krb5_pk_load_id(context
,
2330 &opt
->opt_private
->pk_init_ctx
->id
,
2339 free(opt
->opt_private
->pk_init_ctx
);
2340 opt
->opt_private
->pk_init_ctx
= NULL
;
2344 if (opt
->opt_private
->pk_init_ctx
->id
->certs
) {
2345 _krb5_pk_set_user_id(context
,
2346 opt
->opt_private
->pk_init_ctx
,
2347 opt
->opt_private
->pk_init_ctx
->id
->certs
);
2349 opt
->opt_private
->pk_init_ctx
->id
->cert
= NULL
;
2351 if ((flags
& 2) == 0) {
2352 hx509_context hx509ctx
= context
->hx509ctx
;
2353 hx509_cert cert
= opt
->opt_private
->pk_init_ctx
->id
->cert
;
2355 opt
->opt_private
->pk_init_ctx
->keyex
= USE_DH
;
2358 * If its a ECDSA certs, lets select ECDSA as the keyex algorithm.
2361 AlgorithmIdentifier alg
;
2363 ret
= hx509_cert_get_SPKI_AlgorithmIdentifier(hx509ctx
, cert
, &alg
);
2365 if (der_heim_oid_cmp(&alg
.algorithm
, &asn1_oid_id_ecPublicKey
) == 0)
2366 opt
->opt_private
->pk_init_ctx
->keyex
= USE_ECDH
;
2367 free_AlgorithmIdentifier(&alg
);
2372 opt
->opt_private
->pk_init_ctx
->keyex
= USE_RSA
;
2374 if (opt
->opt_private
->pk_init_ctx
->id
->certs
== NULL
) {
2375 krb5_set_error_message(context
, EINVAL
,
2376 N_("No anonymous pkinit support in RSA mode", ""));
2383 krb5_set_error_message(context
, EINVAL
,
2384 N_("no support for PKINIT compiled in", ""));
2389 krb5_error_code KRB5_LIB_FUNCTION
2390 _krb5_get_init_creds_opt_set_pkinit_user_certs(krb5_context context
,
2391 krb5_get_init_creds_opt
*opt
,
2392 struct hx509_certs_data
*certs
)
2395 if (opt
->opt_private
== NULL
) {
2396 krb5_set_error_message(context
, EINVAL
,
2397 N_("PKINIT: on non extendable opt", ""));
2400 if (opt
->opt_private
->pk_init_ctx
== NULL
) {
2401 krb5_set_error_message(context
, EINVAL
,
2402 N_("PKINIT: on pkinit context", ""));
2406 _krb5_pk_set_user_id(context
, opt
->opt_private
->pk_init_ctx
, certs
);
2410 krb5_set_error_message(context
, EINVAL
,
2411 N_("no support for PKINIT compiled in", ""));
2419 get_ms_san(hx509_context context
, hx509_cert cert
, char **upn
)
2421 hx509_octet_string_list list
;
2426 ret
= hx509_cert_find_subjectAltName_otherName(context
,
2428 &asn1_oid_id_pkinit_ms_san
,
2433 if (list
.len
> 0 && list
.val
[0].length
> 0)
2434 ret
= decode_MS_UPN_SAN(list
.val
[0].data
, list
.val
[0].length
,
2438 hx509_free_octet_string_list(&list
);
2444 find_ms_san(hx509_context context
, hx509_cert cert
, void *ctx
)
2449 ret
= get_ms_san(context
, cert
, &upn
);
2460 * Private since it need to be redesigned using krb5_get_init_creds()
2463 krb5_error_code KRB5_LIB_FUNCTION
2464 _krb5_pk_enterprise_cert(krb5_context context
,
2465 const char *user_id
,
2466 krb5_const_realm realm
,
2467 krb5_principal
*principal
,
2468 struct hx509_certs_data
**res
)
2471 krb5_error_code ret
;
2472 hx509_certs certs
, result
;
2481 if (user_id
== NULL
) {
2482 krb5_clear_error_message(context
);
2486 ret
= hx509_certs_init(context
->hx509ctx
, user_id
, 0, NULL
, &certs
);
2488 pk_copy_error(context
, context
->hx509ctx
, ret
,
2489 "Failed to init cert certs");
2493 ret
= hx509_query_alloc(context
->hx509ctx
, &q
);
2495 krb5_set_error_message(context
, ret
, "out of memory");
2496 hx509_certs_free(&certs
);
2500 hx509_query_match_option(q
, HX509_QUERY_OPTION_PRIVATE_KEY
);
2501 hx509_query_match_option(q
, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE
);
2502 hx509_query_match_eku(q
, &asn1_oid_id_pkinit_ms_eku
);
2503 hx509_query_match_cmp_func(q
, find_ms_san
, NULL
);
2505 ret
= hx509_certs_filter(context
->hx509ctx
, certs
, q
, &result
);
2506 hx509_query_free(context
->hx509ctx
, q
);
2507 hx509_certs_free(&certs
);
2509 pk_copy_error(context
, context
->hx509ctx
, ret
,
2510 "Failed to find PKINIT certificate");
2514 ret
= hx509_get_one_cert(context
->hx509ctx
, result
, &cert
);
2515 hx509_certs_free(&result
);
2517 pk_copy_error(context
, context
->hx509ctx
, ret
,
2518 "Failed to get one cert");
2522 ret
= get_ms_san(context
->hx509ctx
, cert
, &name
);
2524 pk_copy_error(context
, context
->hx509ctx
, ret
,
2525 "Failed to get MS SAN");
2529 ret
= krb5_make_principal(context
, principal
, realm
, name
, NULL
);
2534 krb5_principal_set_type(context
, *principal
, KRB5_NT_ENTERPRISE_PRINCIPAL
);
2537 ret
= hx509_certs_init(context
->hx509ctx
, "MEMORY:", 0, NULL
, res
);
2539 hx509_cert_free(cert
);
2543 ret
= hx509_certs_add(context
->hx509ctx
, *res
, cert
);
2545 hx509_certs_free(res
);
2551 hx509_cert_free(cert
);
2555 krb5_set_error_message(context
, EINVAL
,
2556 N_("no support for PKINIT compiled in", ""));