2 * Copyright (c) 2003 - 2016 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #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>
62 pk_copy_error(krb5_context context
,
63 hx509_context hx509ctx
,
67 __attribute__ ((__format__ (__printf__
, 4, 5)));
73 KRB5_LIB_FUNCTION
void KRB5_LIB_CALL
74 _krb5_pk_cert_free(struct krb5_pk_cert
*cert
)
77 hx509_cert_free(cert
->cert
);
82 static krb5_error_code
83 BN_to_integer(krb5_context context
, BIGNUM
*bn
, heim_integer
*integer
)
85 integer
->length
= BN_num_bytes(bn
);
86 integer
->data
= malloc(integer
->length
);
87 if (integer
->data
== NULL
) {
88 krb5_clear_error_message(context
);
91 BN_bn2bin(bn
, integer
->data
);
92 integer
->negative
= BN_is_negative(bn
);
97 integer_to_BN(krb5_context context
, const char *field
, const heim_integer
*f
)
101 bn
= BN_bin2bn((const unsigned char *)f
->data
, f
->length
, NULL
);
103 krb5_set_error_message(context
, ENOMEM
,
104 N_("PKINIT: parsing BN failed %s", ""), field
);
107 BN_set_negative(bn
, f
->negative
);
111 static krb5_error_code
112 select_dh_group(krb5_context context
, DH
*dh
, unsigned long min_bits
,
113 struct krb5_dh_moduli
**moduli
)
115 const struct krb5_dh_moduli
*m
;
117 if (moduli
[0] == NULL
) {
118 krb5_set_error_message(context
, EINVAL
,
119 N_("Did not find a DH group parameter "
120 "matching requirement of %lu bits", ""),
126 m
= moduli
[1]; /* XXX */
128 m
= moduli
[0]; /* XXX */
131 for (i
= 0; moduli
[i
] != NULL
; i
++) {
132 if (moduli
[i
]->bits
>= min_bits
)
135 if (moduli
[i
] == NULL
) {
136 krb5_set_error_message(context
, EINVAL
,
137 N_("Did not find a DH group parameter "
138 "matching requirement of %lu bits", ""),
145 dh
->p
= integer_to_BN(context
, "p", &m
->p
);
148 dh
->g
= integer_to_BN(context
, "g", &m
->g
);
151 dh
->q
= integer_to_BN(context
, "q", &m
->q
);
164 * Try searchin the key by to use by first looking for for PK-INIT
165 * EKU, then the Microsoft smart card EKU and last, no special EKU at all.
168 static krb5_error_code
169 find_cert(krb5_context context
, struct krb5_pk_identity
*id
,
170 hx509_query
*q
, hx509_cert
*cert
)
172 struct certfind cf
[4] = {
173 { "MobileMe EKU", NULL
},
174 { "PKINIT EKU", NULL
},
176 { "any (or no)", NULL
}
178 int ret
= HX509_CERT_NOT_FOUND
;
180 unsigned oids
[] = { 1, 2, 840, 113635, 100, 3, 2, 1 };
181 const heim_oid mobileMe
= { sizeof(oids
)/sizeof(oids
[0]), oids
};
184 if (id
->flags
& PKINIT_BTMM
)
187 cf
[0].oid
= &mobileMe
;
188 cf
[1].oid
= &asn1_oid_id_pkekuoid
;
189 cf
[2].oid
= &asn1_oid_id_pkinit_ms_eku
;
192 for (i
= start
; i
< sizeof(cf
)/sizeof(cf
[0]); i
++) {
193 ret
= hx509_query_match_eku(q
, cf
[i
].oid
);
195 pk_copy_error(context
, context
->hx509ctx
, ret
,
196 "Failed setting %s OID", cf
[i
].type
);
200 ret
= hx509_certs_find(context
->hx509ctx
, id
->certs
, q
, cert
);
203 pk_copy_error(context
, context
->hx509ctx
, ret
,
204 "Failed finding certificate with %s OID", cf
[i
].type
);
210 static krb5_error_code
211 create_signature(krb5_context context
,
212 const heim_oid
*eContentType
,
214 struct krb5_pk_identity
*id
,
215 hx509_peer_info peer
,
220 if (id
->cert
== NULL
)
221 flags
|= HX509_CMS_SIGNATURE_NO_SIGNER
;
223 ret
= hx509_cms_create_signed_1(context
->hx509ctx
,
235 pk_copy_error(context
, context
->hx509ctx
, ret
,
236 "Create CMS signedData");
243 static int KRB5_LIB_CALL
244 cert2epi(hx509_context context
, void *ctx
, hx509_cert c
)
246 ExternalPrincipalIdentifiers
*ids
= ctx
;
247 ExternalPrincipalIdentifier id
;
248 hx509_name subject
= NULL
;
255 memset(&id
, 0, sizeof(id
));
257 ret
= hx509_cert_get_subject(c
, &subject
);
261 if (hx509_name_is_null_p(subject
) != 0) {
263 id
.subjectName
= calloc(1, sizeof(*id
.subjectName
));
264 if (id
.subjectName
== NULL
) {
265 hx509_name_free(&subject
);
266 free_ExternalPrincipalIdentifier(&id
);
270 ret
= hx509_name_binary(subject
, id
.subjectName
);
272 hx509_name_free(&subject
);
273 free_ExternalPrincipalIdentifier(&id
);
277 hx509_name_free(&subject
);
280 id
.issuerAndSerialNumber
= calloc(1, sizeof(*id
.issuerAndSerialNumber
));
281 if (id
.issuerAndSerialNumber
== NULL
) {
282 free_ExternalPrincipalIdentifier(&id
);
287 IssuerAndSerialNumber iasn
;
291 memset(&iasn
, 0, sizeof(iasn
));
293 ret
= hx509_cert_get_issuer(c
, &issuer
);
295 free_ExternalPrincipalIdentifier(&id
);
299 ret
= hx509_name_to_Name(issuer
, &iasn
.issuer
);
300 hx509_name_free(&issuer
);
302 free_ExternalPrincipalIdentifier(&id
);
306 ret
= hx509_cert_get_serialnumber(c
, &iasn
.serialNumber
);
308 free_IssuerAndSerialNumber(&iasn
);
309 free_ExternalPrincipalIdentifier(&id
);
313 ASN1_MALLOC_ENCODE(IssuerAndSerialNumber
,
314 id
.issuerAndSerialNumber
->data
,
315 id
.issuerAndSerialNumber
->length
,
317 free_IssuerAndSerialNumber(&iasn
);
319 free_ExternalPrincipalIdentifier(&id
);
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_f(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
= 0;
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 return krb5_enomem(context
);
394 ret
= krb5_data_copy(a
->pkAuthenticator
.paChecksum
,
395 checksum
.checksum
.data
, checksum
.checksum
.length
);
396 free_Checksum(&checksum
);
400 if (ctx
->keyex
== USE_DH
|| ctx
->keyex
== USE_ECDH
) {
401 const char *moduli_file
;
402 unsigned long dh_min_bits
;
406 krb5_data_zero(&dhbuf
);
410 moduli_file
= krb5_config_get_string(context
, NULL
,
416 krb5_config_get_int_default(context
, NULL
, 0,
418 "pkinit_dh_min_bits",
421 ret
= _krb5_parse_moduli(context
, moduli_file
, &ctx
->m
);
425 ctx
->u
.dh
= DH_new();
426 if (ctx
->u
.dh
== NULL
)
427 return krb5_enomem(context
);
429 ret
= select_dh_group(context
, ctx
->u
.dh
, dh_min_bits
, ctx
->m
);
433 if (DH_generate_key(ctx
->u
.dh
) != 1) {
434 krb5_set_error_message(context
, ENOMEM
,
435 N_("pkinit: failed to generate DH key", ""));
440 if (1 /* support_cached_dh */) {
441 ALLOC(a
->clientDHNonce
, 1);
442 if (a
->clientDHNonce
== NULL
) {
443 krb5_clear_error_message(context
);
446 ret
= krb5_data_alloc(a
->clientDHNonce
, 40);
447 if (a
->clientDHNonce
== NULL
) {
448 krb5_clear_error_message(context
);
451 ret
= RAND_bytes(a
->clientDHNonce
->data
, a
->clientDHNonce
->length
);
453 return KRB5_CRYPTO_INTERNAL
;
454 ret
= krb5_copy_data(context
, a
->clientDHNonce
,
455 &ctx
->clientDHNonce
);
460 ALLOC(a
->clientPublicValue
, 1);
461 if (a
->clientPublicValue
== NULL
)
464 if (ctx
->keyex
== USE_DH
) {
467 heim_integer dh_pub_key
;
469 ret
= der_copy_oid(&asn1_oid_id_dhpublicnumber
,
470 &a
->clientPublicValue
->algorithm
.algorithm
);
474 memset(&dp
, 0, sizeof(dp
));
476 ret
= BN_to_integer(context
, dh
->p
, &dp
.p
);
478 free_DomainParameters(&dp
);
481 ret
= BN_to_integer(context
, dh
->g
, &dp
.g
);
483 free_DomainParameters(&dp
);
486 if (dh
->q
&& BN_num_bits(dh
->q
)) {
488 * The q parameter is required, but MSFT made it optional.
489 * It's only required in order to verify the domain parameters
490 * -- the security of the DH group --, but we validate groups
491 * against known groups rather than accepting arbitrary groups
492 * chosen by the peer, so we really don't need to have put it
493 * on the wire. Because these are Oakley groups, and the
494 * primes are Sophie Germain primes, q is p>>1 and we can
495 * compute it on the fly like MIT Kerberos does, but we'd have
496 * to implement BN_rshift1().
498 dp
.q
= calloc(1, sizeof(*dp
.q
));
500 free_DomainParameters(&dp
);
503 ret
= BN_to_integer(context
, dh
->q
, dp
.q
);
505 free_DomainParameters(&dp
);
510 dp
.validationParms
= NULL
;
512 a
->clientPublicValue
->algorithm
.parameters
=
513 malloc(sizeof(*a
->clientPublicValue
->algorithm
.parameters
));
514 if (a
->clientPublicValue
->algorithm
.parameters
== NULL
) {
515 free_DomainParameters(&dp
);
519 ASN1_MALLOC_ENCODE(DomainParameters
,
520 a
->clientPublicValue
->algorithm
.parameters
->data
,
521 a
->clientPublicValue
->algorithm
.parameters
->length
,
523 free_DomainParameters(&dp
);
526 if (size
!= a
->clientPublicValue
->algorithm
.parameters
->length
)
527 krb5_abortx(context
, "Internal ASN1 encoder error");
529 ret
= BN_to_integer(context
, dh
->pub_key
, &dh_pub_key
);
533 ASN1_MALLOC_ENCODE(DHPublicKey
, dhbuf
.data
, dhbuf
.length
,
534 &dh_pub_key
, &size
, ret
);
535 der_free_heim_integer(&dh_pub_key
);
538 if (size
!= dhbuf
.length
)
539 krb5_abortx(context
, "asn1 internal error");
540 a
->clientPublicValue
->subjectPublicKey
.length
= dhbuf
.length
* 8;
541 a
->clientPublicValue
->subjectPublicKey
.data
= dhbuf
.data
;
542 } else if (ctx
->keyex
== USE_ECDH
) {
543 ret
= _krb5_build_authpack_subjectPK_EC(context
, ctx
, a
);
547 krb5_abortx(context
, "internal error");
551 a
->supportedCMSTypes
= calloc(1, sizeof(*a
->supportedCMSTypes
));
552 if (a
->supportedCMSTypes
== NULL
)
555 ret
= hx509_crypto_available(context
->hx509ctx
, HX509_SELECT_ALL
,
557 &a
->supportedCMSTypes
->val
,
558 &a
->supportedCMSTypes
->len
);
566 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
567 _krb5_pk_mk_ContentInfo(krb5_context context
,
568 const krb5_data
*buf
,
570 struct ContentInfo
*content_info
)
574 ret
= der_copy_oid(oid
, &content_info
->contentType
);
577 ALLOC(content_info
->content
, 1);
578 if (content_info
->content
== NULL
)
580 content_info
->content
->data
= malloc(buf
->length
);
581 if (content_info
->content
->data
== NULL
)
583 memcpy(content_info
->content
->data
, buf
->data
, buf
->length
);
584 content_info
->content
->length
= buf
->length
;
588 static krb5_error_code
589 pk_mk_padata(krb5_context context
,
590 krb5_pk_init_ctx ctx
,
591 const KDC_REQ_BODY
*req_body
,
595 struct ContentInfo content_info
;
597 const heim_oid
*oid
= NULL
;
599 krb5_data buf
, sd_buf
;
602 krb5_data_zero(&buf
);
603 krb5_data_zero(&sd_buf
);
604 memset(&content_info
, 0, sizeof(content_info
));
606 if (ctx
->type
== PKINIT_WIN2K
) {
611 memset(&ap
, 0, sizeof(ap
));
613 /* fill in PKAuthenticator */
614 ret
= copy_PrincipalName(req_body
->sname
, &ap
.pkAuthenticator
.kdcName
);
616 free_AuthPack_Win2k(&ap
);
617 krb5_clear_error_message(context
);
620 ret
= copy_Realm(&req_body
->realm
, &ap
.pkAuthenticator
.kdcRealm
);
622 free_AuthPack_Win2k(&ap
);
623 krb5_clear_error_message(context
);
627 krb5_us_timeofday(context
, &sec
, &usec
);
628 ap
.pkAuthenticator
.ctime
= sec
;
629 ap
.pkAuthenticator
.cusec
= usec
;
630 ap
.pkAuthenticator
.nonce
= nonce
;
632 ASN1_MALLOC_ENCODE(AuthPack_Win2k
, buf
.data
, buf
.length
,
634 free_AuthPack_Win2k(&ap
);
636 krb5_set_error_message(context
, ret
,
637 N_("Failed encoding AuthPackWin: %d", ""),
641 if (buf
.length
!= size
)
642 krb5_abortx(context
, "internal ASN1 encoder error");
644 oid
= &asn1_oid_id_pkcs7_data
;
645 } else if (ctx
->type
== PKINIT_27
) {
648 memset(&ap
, 0, sizeof(ap
));
650 ret
= build_auth_pack(context
, nonce
, ctx
, req_body
, &ap
);
656 ASN1_MALLOC_ENCODE(AuthPack
, buf
.data
, buf
.length
, &ap
, &size
, ret
);
659 krb5_set_error_message(context
, ret
,
660 N_("Failed encoding AuthPack: %d", ""),
664 if (buf
.length
!= size
)
665 krb5_abortx(context
, "internal ASN1 encoder error");
667 oid
= &asn1_oid_id_pkauthdata
;
669 krb5_abortx(context
, "internal pkinit error");
671 ret
= create_signature(context
, oid
, &buf
, ctx
->id
,
673 krb5_data_free(&buf
);
677 ret
= hx509_cms_wrap_ContentInfo(&asn1_oid_id_pkcs7_signedData
, &sd_buf
, &buf
);
678 krb5_data_free(&sd_buf
);
680 krb5_set_error_message(context
, ret
,
681 N_("ContentInfo wrapping of signedData failed",""));
685 if (ctx
->type
== PKINIT_WIN2K
) {
686 PA_PK_AS_REQ_Win2k winreq
;
688 pa_type
= KRB5_PADATA_PK_AS_REQ_WIN
;
690 memset(&winreq
, 0, sizeof(winreq
));
692 winreq
.signed_auth_pack
= buf
;
694 ASN1_MALLOC_ENCODE(PA_PK_AS_REQ_Win2k
, buf
.data
, buf
.length
,
695 &winreq
, &size
, ret
);
696 free_PA_PK_AS_REQ_Win2k(&winreq
);
698 } else if (ctx
->type
== PKINIT_27
) {
701 pa_type
= KRB5_PADATA_PK_AS_REQ
;
703 memset(&req
, 0, sizeof(req
));
704 req
.signedAuthPack
= buf
;
706 if (ctx
->trustedCertifiers
) {
708 req
.trustedCertifiers
= calloc(1, sizeof(*req
.trustedCertifiers
));
709 if (req
.trustedCertifiers
== NULL
) {
710 ret
= krb5_enomem(context
);
711 free_PA_PK_AS_REQ(&req
);
714 ret
= build_edi(context
, context
->hx509ctx
,
715 ctx
->id
->anchors
, req
.trustedCertifiers
);
717 krb5_set_error_message(context
, ret
,
718 N_("pk-init: failed to build "
719 "trustedCertifiers", ""));
720 free_PA_PK_AS_REQ(&req
);
726 ASN1_MALLOC_ENCODE(PA_PK_AS_REQ
, buf
.data
, buf
.length
,
729 free_PA_PK_AS_REQ(&req
);
732 krb5_abortx(context
, "internal pkinit error");
734 krb5_set_error_message(context
, ret
, "PA-PK-AS-REQ %d", (int)ret
);
737 if (buf
.length
!= size
)
738 krb5_abortx(context
, "Internal ASN1 encoder error");
740 ret
= krb5_padata_add(context
, md
, pa_type
, buf
.data
, buf
.length
);
745 ret
= krb5_padata_add(context
, md
, KRB5_PADATA_PK_AS_09_BINDING
, NULL
, 0);
748 free_ContentInfo(&content_info
);
754 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
755 _krb5_pk_mk_padata(krb5_context context
,
759 const KDC_REQ_BODY
*req_body
,
763 krb5_pk_init_ctx ctx
= c
;
766 if (ctx
->id
->certs
== NULL
&& ctx
->anonymous
== 0) {
767 krb5_set_error_message(context
, HEIM_PKINIT_NO_PRIVATE_KEY
,
768 N_("PKINIT: No user certificate given", ""));
769 return HEIM_PKINIT_NO_PRIVATE_KEY
;
772 win2k_compat
= krb5_config_get_bool_default(context
, NULL
,
780 ctx
->require_binding
=
781 krb5_config_get_bool_default(context
, NULL
,
785 "pkinit_win2k_require_binding",
787 ctx
->type
= PKINIT_WIN2K
;
789 ctx
->type
= PKINIT_27
;
792 krb5_config_get_bool_default(context
, NULL
,
796 "pkinit_require_eku",
798 if (ic_flags
& KRB5_INIT_CREDS_NO_C_NO_EKU_CHECK
)
799 ctx
->require_eku
= 0;
800 if (ctx
->id
->flags
& (PKINIT_BTMM
| PKINIT_NO_KDC_ANCHOR
))
801 ctx
->require_eku
= 0;
803 ctx
->require_krbtgt_otherName
=
804 krb5_config_get_bool_default(context
, NULL
,
808 "pkinit_require_krbtgt_otherName",
810 if (ic_flags
& KRB5_INIT_CREDS_PKINIT_NO_KRBTGT_OTHERNAME_CHECK
)
811 ctx
->require_krbtgt_otherName
= FALSE
;
813 ctx
->require_hostname_match
=
814 krb5_config_get_bool_default(context
, NULL
,
818 "pkinit_require_hostname_match",
821 ctx
->trustedCertifiers
=
822 krb5_config_get_bool_default(context
, NULL
,
826 "pkinit_trustedCertifiers",
829 return pk_mk_padata(context
, ctx
, req_body
, nonce
, md
);
832 static krb5_error_code
833 pk_verify_sign(krb5_context context
,
836 struct krb5_pk_identity
*id
,
837 heim_oid
*contentType
,
839 struct krb5_pk_cert
**signer
)
841 hx509_certs signer_certs
;
843 unsigned flags
= 0, verify_flags
= 0;
847 if (id
->flags
& PKINIT_BTMM
) {
848 flags
|= HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH
;
849 flags
|= HX509_CMS_VS_NO_KU_CHECK
;
850 flags
|= HX509_CMS_VS_NO_VALIDATE
;
852 if (id
->flags
& PKINIT_NO_KDC_ANCHOR
)
853 flags
|= HX509_CMS_VS_NO_VALIDATE
;
855 ret
= hx509_cms_verify_signed_ext(context
->hx509ctx
,
867 pk_copy_error(context
, context
->hx509ctx
, ret
,
868 "CMS verify signed failed");
872 heim_assert((verify_flags
& HX509_CMS_VSE_VALIDATED
) ||
873 (id
->flags
& PKINIT_NO_KDC_ANCHOR
),
874 "Either PKINIT signer must be validated, or NO_KDC_ANCHOR must be set");
876 if ((verify_flags
& HX509_CMS_VSE_VALIDATED
) == 0)
879 *signer
= calloc(1, sizeof(**signer
));
880 if (*signer
== NULL
) {
881 krb5_clear_error_message(context
);
886 ret
= hx509_get_one_cert(context
->hx509ctx
, signer_certs
, &(*signer
)->cert
);
888 pk_copy_error(context
, context
->hx509ctx
, ret
,
889 "Failed to get one of the signer certs");
894 hx509_certs_free(&signer_certs
);
897 hx509_cert_free((*signer
)->cert
);
906 static krb5_error_code
907 get_reply_key_win(krb5_context context
,
908 const krb5_data
*content
,
912 ReplyKeyPack_Win2k key_pack
;
916 ret
= decode_ReplyKeyPack_Win2k(content
->data
,
921 krb5_set_error_message(context
, ret
,
922 N_("PKINIT decoding reply key failed", ""));
923 free_ReplyKeyPack_Win2k(&key_pack
);
927 if ((unsigned)key_pack
.nonce
!= nonce
) {
928 krb5_set_error_message(context
, ret
,
929 N_("PKINIT enckey nonce is wrong", ""));
930 free_ReplyKeyPack_Win2k(&key_pack
);
931 return KRB5KRB_AP_ERR_MODIFIED
;
934 *key
= malloc (sizeof (**key
));
936 free_ReplyKeyPack_Win2k(&key_pack
);
937 return krb5_enomem(context
);
940 ret
= copy_EncryptionKey(&key_pack
.replyKey
, *key
);
941 free_ReplyKeyPack_Win2k(&key_pack
);
943 krb5_set_error_message(context
, ret
,
944 N_("PKINIT failed copying reply key", ""));
952 static krb5_error_code
953 get_reply_key(krb5_context context
,
954 const krb5_data
*content
,
955 const krb5_data
*req_buffer
,
958 ReplyKeyPack key_pack
;
962 ret
= decode_ReplyKeyPack(content
->data
,
967 krb5_set_error_message(context
, ret
,
968 N_("PKINIT decoding reply key failed", ""));
969 free_ReplyKeyPack(&key_pack
);
977 * XXX Verify kp.replyKey is a allowed enctype in the
981 ret
= krb5_crypto_init(context
, &key_pack
.replyKey
, 0, &crypto
);
983 free_ReplyKeyPack(&key_pack
);
987 ret
= krb5_verify_checksum(context
, crypto
, 6,
988 req_buffer
->data
, req_buffer
->length
,
989 &key_pack
.asChecksum
);
990 krb5_crypto_destroy(context
, crypto
);
992 free_ReplyKeyPack(&key_pack
);
997 *key
= malloc (sizeof (**key
));
999 free_ReplyKeyPack(&key_pack
);
1000 return krb5_enomem(context
);
1003 ret
= copy_EncryptionKey(&key_pack
.replyKey
, *key
);
1004 free_ReplyKeyPack(&key_pack
);
1006 krb5_set_error_message(context
, ret
,
1007 N_("PKINIT failed copying reply key", ""));
1016 static krb5_error_code
1017 pk_verify_host(krb5_context context
,
1019 struct krb5_pk_init_ctx_data
*ctx
,
1020 struct krb5_pk_cert
*host
)
1022 krb5_error_code ret
= 0;
1024 if (ctx
->require_eku
) {
1025 ret
= hx509_cert_check_eku(context
->hx509ctx
, host
->cert
,
1026 &asn1_oid_id_pkkdcekuoid
, 0);
1028 krb5_set_error_message(context
, ret
,
1029 N_("No PK-INIT KDC EKU in kdc certificate", ""));
1033 if (ctx
->require_krbtgt_otherName
) {
1034 hx509_octet_string_list list
;
1038 ret
= hx509_cert_find_subjectAltName_otherName(context
->hx509ctx
,
1040 &asn1_oid_id_pkinit_san
,
1043 krb5_set_error_message(context
, ret
,
1044 N_("Failed to find the PK-INIT "
1045 "subjectAltName in the KDC "
1046 "certificate", ""));
1052 * subjectAltNames are multi-valued, and a single KDC may serve
1053 * multiple realms. The SAN validation here must accept
1054 * the KDC's cert if *any* of the SANs match the expected KDC.
1055 * It is OK for *some* of the SANs to not match, provided at least
1058 for (i
= 0; matched
== 0 && i
< list
.len
; i
++) {
1059 KRB5PrincipalName r
;
1061 ret
= decode_KRB5PrincipalName(list
.val
[i
].data
,
1066 krb5_set_error_message(context
, ret
,
1067 N_("Failed to decode the PK-INIT "
1068 "subjectAltName in the "
1069 "KDC certificate", ""));
1074 if (r
.principalName
.name_string
.len
== 2 &&
1075 strcmp(r
.principalName
.name_string
.val
[0], KRB5_TGS_NAME
) == 0
1076 && strcmp(r
.principalName
.name_string
.val
[1], realm
) == 0
1077 && strcmp(r
.realm
, realm
) == 0)
1080 free_KRB5PrincipalName(&r
);
1082 hx509_free_octet_string_list(&list
);
1085 (ctx
->id
->flags
& PKINIT_NO_KDC_ANCHOR
) == 0) {
1086 ret
= KRB5_KDC_ERR_INVALID_CERTIFICATE
;
1087 /* XXX: Lost in translation... */
1088 krb5_set_error_message(context
, ret
,
1089 N_("KDC has wrong realm name in "
1090 "the certificate", ""));
1099 static krb5_error_code
1100 pk_rd_pa_reply_enckey(krb5_context context
,
1102 const heim_octet_string
*indata
,
1103 const heim_oid
*dataType
,
1105 krb5_pk_init_ctx ctx
,
1108 const krb5_data
*req_buffer
,
1110 krb5_keyblock
**key
)
1112 krb5_error_code ret
;
1113 struct krb5_pk_cert
*host
= NULL
;
1115 heim_octet_string unwrapped
;
1116 heim_oid contentType
= { 0, NULL
};
1117 int flags
= HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT
;
1119 if (der_heim_oid_cmp(&asn1_oid_id_pkcs7_envelopedData
, dataType
)) {
1120 krb5_set_error_message(context
, EINVAL
,
1121 N_("PKINIT: Invalid content type", ""));
1125 if (ctx
->type
== PKINIT_WIN2K
)
1126 flags
|= HX509_CMS_UE_ALLOW_WEAK
;
1128 ret
= hx509_cms_unenvelope(context
->hx509ctx
,
1138 pk_copy_error(context
, context
->hx509ctx
, ret
,
1139 "Failed to unenvelope CMS data in PK-INIT reply");
1142 der_free_oid(&contentType
);
1144 /* win2k uses ContentInfo */
1145 if (type
== PKINIT_WIN2K
) {
1148 ret
= hx509_cms_unwrap_ContentInfo(&content
, &type2
, &unwrapped
, NULL
);
1150 /* windows LH with interesting CMS packets */
1151 size_t ph
= 1 + der_length_len(content
.length
);
1152 unsigned char *ptr
= malloc(content
.length
+ ph
);
1155 memcpy(ptr
+ ph
, content
.data
, content
.length
);
1157 ret
= der_put_length_and_tag (ptr
+ ph
- 1, ph
, content
.length
,
1158 ASN1_C_UNIV
, CONS
, UT_Sequence
, &l
);
1165 content
.length
+= ph
;
1167 ret
= hx509_cms_unwrap_ContentInfo(&content
, &type2
, &unwrapped
, NULL
);
1171 if (der_heim_oid_cmp(&type2
, &asn1_oid_id_pkcs7_signedData
)) {
1172 ret
= EINVAL
; /* XXX */
1173 krb5_set_error_message(context
, ret
,
1174 N_("PKINIT: Invalid content type", ""));
1175 der_free_oid(&type2
);
1176 der_free_octet_string(&unwrapped
);
1179 der_free_oid(&type2
);
1180 krb5_data_free(&content
);
1181 ret
= krb5_data_copy(&content
, unwrapped
.data
, unwrapped
.length
);
1182 der_free_octet_string(&unwrapped
);
1184 krb5_set_error_message(context
, ret
,
1185 N_("malloc: out of memory", ""));
1190 ret
= pk_verify_sign(context
,
1198 krb5_data_free(&content
);
1199 ret
= krb5_data_copy(&content
, unwrapped
.data
, unwrapped
.length
);
1200 der_free_octet_string(&unwrapped
);
1205 heim_assert(host
|| (ctx
->id
->flags
& PKINIT_NO_KDC_ANCHOR
),
1206 "KDC signature must be verified unless PKINIT_NO_KDC_ANCHOR set");
1209 /* make sure that it is the kdc's certificate */
1210 ret
= pk_verify_host(context
, realm
, ctx
, host
);
1214 ctx
->kdc_verified
= 1;
1218 if (type
== PKINIT_WIN2K
) {
1219 if (der_heim_oid_cmp(&contentType
, &asn1_oid_id_pkcs7_data
) != 0) {
1220 ret
= KRB5KRB_AP_ERR_MSG_TYPE
;
1221 krb5_set_error_message(context
, ret
, "PKINIT: reply key, wrong oid");
1225 if (der_heim_oid_cmp(&contentType
, &asn1_oid_id_pkrkeydata
) != 0) {
1226 ret
= KRB5KRB_AP_ERR_MSG_TYPE
;
1227 krb5_set_error_message(context
, ret
, "PKINIT: reply key, wrong oid");
1235 ret
= get_reply_key(context
, &content
, req_buffer
, key
);
1236 if (ret
!= 0 && ctx
->require_binding
== 0)
1237 ret
= get_reply_key_win(context
, &content
, nonce
, key
);
1240 ret
= get_reply_key(context
, &content
, req_buffer
, key
);
1246 /* XXX compare given etype with key->etype */
1250 _krb5_pk_cert_free(host
);
1251 der_free_oid(&contentType
);
1252 krb5_data_free(&content
);
1258 * RFC 8062 section 7:
1260 * The client then decrypts the KDC contribution key and verifies that
1261 * the ticket session key in the returned ticket is the combined key of
1262 * the KDC contribution key and the reply key.
1264 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1265 _krb5_pk_kx_confirm(krb5_context context
,
1266 krb5_pk_init_ctx ctx
,
1267 krb5_keyblock
*reply_key
,
1268 krb5_keyblock
*session_key
,
1269 PA_DATA
*pa_pkinit_kx
)
1271 krb5_error_code ret
;
1273 krb5_keyblock ck
, sk_verify
;
1274 krb5_crypto ck_crypto
= NULL
;
1275 krb5_crypto rk_crypto
= NULL
;
1278 krb5_data p1
= { sizeof("PKINIT") - 1, "PKINIT" };
1279 krb5_data p2
= { sizeof("KEYEXCHANGE") - 1, "KEYEXCHANGE" };
1281 heim_assert(ctx
!= NULL
, "PKINIT context is non-NULL");
1282 heim_assert(reply_key
!= NULL
, "reply key is non-NULL");
1283 heim_assert(session_key
!= NULL
, "session key is non-NULL");
1285 /* PA-PKINIT-KX is optional unless anonymous */
1286 if (pa_pkinit_kx
== NULL
)
1287 return ctx
->anonymous
? KRB5_KDCREP_MODIFIED
: 0;
1289 memset(&ed
, 0, sizeof(ed
));
1290 krb5_keyblock_zero(&ck
);
1291 krb5_keyblock_zero(&sk_verify
);
1292 krb5_data_zero(&data
);
1294 ret
= decode_EncryptedData(pa_pkinit_kx
->padata_value
.data
,
1295 pa_pkinit_kx
->padata_value
.length
,
1300 if (len
!= pa_pkinit_kx
->padata_value
.length
) {
1301 ret
= KRB5_KDCREP_MODIFIED
;
1305 ret
= krb5_crypto_init(context
, reply_key
, 0, &rk_crypto
);
1309 ret
= krb5_decrypt_EncryptedData(context
, rk_crypto
,
1310 KRB5_KU_PA_PKINIT_KX
,
1315 ret
= decode_EncryptionKey(data
.data
, data
.length
,
1320 ret
= krb5_crypto_init(context
, &ck
, 0, &ck_crypto
);
1324 ret
= krb5_crypto_fx_cf2(context
, ck_crypto
, rk_crypto
,
1325 &p1
, &p2
, session_key
->keytype
,
1330 if (sk_verify
.keytype
!= session_key
->keytype
||
1331 krb5_data_ct_cmp(&sk_verify
.keyvalue
, &session_key
->keyvalue
) != 0) {
1332 ret
= KRB5_KDCREP_MODIFIED
;
1337 free_EncryptedData(&ed
);
1338 krb5_free_keyblock_contents(context
, &ck
);
1339 krb5_free_keyblock_contents(context
, &sk_verify
);
1341 krb5_crypto_destroy(context
, ck_crypto
);
1343 krb5_crypto_destroy(context
, rk_crypto
);
1344 krb5_data_free(&data
);
1349 static krb5_error_code
1350 pk_rd_pa_reply_dh(krb5_context context
,
1351 const heim_octet_string
*indata
,
1352 const heim_oid
*dataType
,
1354 krb5_pk_init_ctx ctx
,
1360 krb5_keyblock
**key
)
1362 const unsigned char *p
;
1363 unsigned char *dh_gen_key
= NULL
;
1364 struct krb5_pk_cert
*host
= NULL
;
1365 BIGNUM
*kdc_dh_pubkey
= NULL
;
1366 KDCDHKeyInfo kdc_dh_info
;
1367 heim_oid contentType
= { 0, NULL
};
1369 krb5_error_code ret
;
1370 int dh_gen_keylen
= 0;
1373 krb5_data_zero(&content
);
1374 memset(&kdc_dh_info
, 0, sizeof(kdc_dh_info
));
1376 if (der_heim_oid_cmp(&asn1_oid_id_pkcs7_signedData
, dataType
)) {
1377 krb5_set_error_message(context
, EINVAL
,
1378 N_("PKINIT: Invalid content type", ""));
1382 ret
= pk_verify_sign(context
,
1392 heim_assert(host
|| (ctx
->id
->flags
& PKINIT_NO_KDC_ANCHOR
),
1393 "KDC signature must be verified unless PKINIT_NO_KDC_ANCHOR set");
1396 /* make sure that it is the kdc's certificate */
1397 ret
= pk_verify_host(context
, realm
, ctx
, host
);
1401 ctx
->kdc_verified
= 1;
1404 if (der_heim_oid_cmp(&contentType
, &asn1_oid_id_pkdhkeydata
)) {
1405 ret
= KRB5KRB_AP_ERR_MSG_TYPE
;
1406 krb5_set_error_message(context
, ret
,
1407 N_("pkinit - dh reply contains wrong oid", ""));
1411 ret
= decode_KDCDHKeyInfo(content
.data
,
1417 krb5_set_error_message(context
, ret
,
1418 N_("pkinit - failed to decode "
1419 "KDC DH Key Info", ""));
1423 if (kdc_dh_info
.nonce
!= nonce
) {
1424 ret
= KRB5KRB_AP_ERR_MODIFIED
;
1425 krb5_set_error_message(context
, ret
,
1426 N_("PKINIT: DH nonce is wrong", ""));
1430 if (kdc_dh_info
.dhKeyExpiration
) {
1432 ret
= KRB5KRB_ERR_GENERIC
;
1433 krb5_set_error_message(context
, ret
,
1434 N_("pkinit; got key expiration "
1435 "without server nonce", ""));
1439 ret
= KRB5KRB_ERR_GENERIC
;
1440 krb5_set_error_message(context
, ret
,
1441 N_("pkinit; got DH reuse but no "
1442 "client nonce", ""));
1447 ret
= KRB5KRB_ERR_GENERIC
;
1448 krb5_set_error_message(context
, ret
,
1449 N_("pkinit: got server nonce "
1450 "without key expiration", ""));
1457 p
= kdc_dh_info
.subjectPublicKey
.data
;
1458 size
= (kdc_dh_info
.subjectPublicKey
.length
+ 7) / 8;
1460 if (ctx
->keyex
== USE_DH
) {
1462 ret
= decode_DHPublicKey(p
, size
, &k
, NULL
);
1464 krb5_set_error_message(context
, ret
,
1465 N_("pkinit: can't decode "
1466 "without key expiration", ""));
1470 kdc_dh_pubkey
= integer_to_BN(context
, "DHPublicKey", &k
);
1471 free_DHPublicKey(&k
);
1472 if (kdc_dh_pubkey
== NULL
) {
1478 size
= DH_size(ctx
->u
.dh
);
1480 dh_gen_key
= malloc(size
);
1481 if (dh_gen_key
== NULL
) {
1482 ret
= krb5_enomem(context
);
1486 dh_gen_keylen
= DH_compute_key(dh_gen_key
, kdc_dh_pubkey
, ctx
->u
.dh
);
1487 if (dh_gen_keylen
== -1) {
1488 ret
= KRB5KRB_ERR_GENERIC
;
1490 krb5_set_error_message(context
, ret
,
1491 N_("PKINIT: Can't compute Diffie-Hellman key", ""));
1494 if (dh_gen_keylen
< (int)size
) {
1495 size
-= dh_gen_keylen
;
1496 memmove(dh_gen_key
+ size
, dh_gen_key
, dh_gen_keylen
);
1497 memset(dh_gen_key
, 0, size
);
1498 dh_gen_keylen
+= size
;
1502 ret
= _krb5_pk_rd_pa_reply_ecdh_compute_key(context
, ctx
, p
,
1509 if (dh_gen_keylen
<= 0) {
1511 krb5_set_error_message(context
, ret
,
1512 N_("PKINIT: resulting DH key <= 0", ""));
1517 *key
= malloc (sizeof (**key
));
1519 ret
= krb5_enomem(context
);
1523 ret
= _krb5_pk_octetstring2key(context
,
1525 dh_gen_key
, dh_gen_keylen
,
1529 krb5_set_error_message(context
, ret
,
1530 N_("PKINIT: can't create key from DH key", ""));
1538 BN_free(kdc_dh_pubkey
);
1540 memset(dh_gen_key
, 0, dh_gen_keylen
);
1544 _krb5_pk_cert_free(host
);
1546 krb5_data_free(&content
);
1547 der_free_oid(&contentType
);
1548 free_KDCDHKeyInfo(&kdc_dh_info
);
1553 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1554 _krb5_pk_rd_pa_reply(krb5_context context
,
1559 const krb5_data
*req_buffer
,
1561 krb5_keyblock
**key
)
1563 krb5_pk_init_ctx ctx
= c
;
1564 krb5_error_code ret
;
1567 /* Check for IETF PK-INIT first */
1568 if (ctx
->type
== PKINIT_27
) {
1570 heim_octet_string os
, data
;
1573 if (pa
->padata_type
!= KRB5_PADATA_PK_AS_REP
) {
1574 krb5_set_error_message(context
, EINVAL
,
1575 N_("PKINIT: wrong padata recv", ""));
1579 ret
= decode_PA_PK_AS_REP(pa
->padata_value
.data
,
1580 pa
->padata_value
.length
,
1584 krb5_set_error_message(context
, ret
,
1585 N_("Failed to decode pkinit AS rep", ""));
1589 switch (rep
.element
) {
1590 case choice_PA_PK_AS_REP_dhInfo
:
1591 _krb5_debug(context
, 5, "krb5_get_init_creds: using pkinit dh");
1592 os
= rep
.u
.dhInfo
.dhSignedData
;
1594 case choice_PA_PK_AS_REP_encKeyPack
:
1595 _krb5_debug(context
, 5, "krb5_get_init_creds: using kinit enc reply key");
1596 os
= rep
.u
.encKeyPack
;
1599 PA_PK_AS_REP_BTMM btmm
;
1600 free_PA_PK_AS_REP(&rep
);
1601 memset(&rep
, 0, sizeof(rep
));
1603 _krb5_debug(context
, 5, "krb5_get_init_creds: using BTMM kinit enc reply key");
1605 ret
= decode_PA_PK_AS_REP_BTMM(pa
->padata_value
.data
,
1606 pa
->padata_value
.length
,
1610 krb5_set_error_message(context
, EINVAL
,
1611 N_("PKINIT: -27 reply "
1612 "invalid content type", ""));
1616 if (btmm
.dhSignedData
|| btmm
.encKeyPack
== NULL
) {
1617 free_PA_PK_AS_REP_BTMM(&btmm
);
1619 krb5_set_error_message(context
, ret
,
1620 N_("DH mode not supported for BTMM mode", ""));
1625 * Transform to IETF style PK-INIT reply so that free works below
1628 rep
.element
= choice_PA_PK_AS_REP_encKeyPack
;
1629 rep
.u
.encKeyPack
.data
= btmm
.encKeyPack
->data
;
1630 rep
.u
.encKeyPack
.length
= btmm
.encKeyPack
->length
;
1631 btmm
.encKeyPack
->data
= NULL
;
1632 btmm
.encKeyPack
->length
= 0;
1633 free_PA_PK_AS_REP_BTMM(&btmm
);
1634 os
= rep
.u
.encKeyPack
;
1638 ret
= hx509_cms_unwrap_ContentInfo(&os
, &oid
, &data
, NULL
);
1640 free_PA_PK_AS_REP(&rep
);
1641 krb5_set_error_message(context
, ret
,
1642 N_("PKINIT: failed to unwrap CI", ""));
1646 switch (rep
.element
) {
1647 case choice_PA_PK_AS_REP_dhInfo
:
1648 ret
= pk_rd_pa_reply_dh(context
, &data
, &oid
, realm
, ctx
, etype
,
1650 rep
.u
.dhInfo
.serverDHNonce
,
1653 case choice_PA_PK_AS_REP_encKeyPack
:
1654 ret
= pk_rd_pa_reply_enckey(context
, PKINIT_27
, &data
, &oid
, realm
,
1655 ctx
, etype
, nonce
, req_buffer
, pa
, key
);
1658 krb5_abortx(context
, "pk-init as-rep case not possible to happen");
1660 der_free_octet_string(&data
);
1662 free_PA_PK_AS_REP(&rep
);
1664 } else if (ctx
->type
== PKINIT_WIN2K
) {
1665 PA_PK_AS_REP_Win2k w2krep
;
1667 /* Check for Windows encoding of the AS-REP pa data */
1669 #if 0 /* should this be ? */
1670 if (pa
->padata_type
!= KRB5_PADATA_PK_AS_REP
) {
1671 krb5_set_error_message(context
, EINVAL
,
1672 "PKINIT: wrong padata recv");
1677 memset(&w2krep
, 0, sizeof(w2krep
));
1679 ret
= decode_PA_PK_AS_REP_Win2k(pa
->padata_value
.data
,
1680 pa
->padata_value
.length
,
1684 krb5_set_error_message(context
, ret
,
1685 N_("PKINIT: Failed decoding windows "
1686 "pkinit reply %d", ""), (int)ret
);
1690 krb5_clear_error_message(context
);
1692 switch (w2krep
.element
) {
1693 case choice_PA_PK_AS_REP_Win2k_encKeyPack
: {
1694 heim_octet_string data
;
1697 ret
= hx509_cms_unwrap_ContentInfo(&w2krep
.u
.encKeyPack
,
1699 free_PA_PK_AS_REP_Win2k(&w2krep
);
1701 krb5_set_error_message(context
, ret
,
1702 N_("PKINIT: failed to unwrap CI", ""));
1706 ret
= pk_rd_pa_reply_enckey(context
, PKINIT_WIN2K
, &data
, &oid
, realm
,
1707 ctx
, etype
, nonce
, req_buffer
, pa
, key
);
1708 der_free_octet_string(&data
);
1714 free_PA_PK_AS_REP_Win2k(&w2krep
);
1716 krb5_set_error_message(context
, ret
,
1717 N_("PKINIT: win2k reply invalid "
1718 "content type", ""));
1724 krb5_set_error_message(context
, ret
,
1725 N_("PKINIT: unknown reply type", ""));
1732 krb5_context context
;
1733 krb5_prompter_fct prompter
;
1734 void *prompter_data
;
1738 hx_pass_prompter(void *data
, const hx509_prompt
*prompter
)
1740 krb5_error_code ret
;
1742 krb5_data password_data
;
1743 struct prompter
*p
= data
;
1745 password_data
.data
= prompter
->reply
.data
;
1746 password_data
.length
= prompter
->reply
.length
;
1748 prompt
.prompt
= prompter
->prompt
;
1749 prompt
.hidden
= hx509_prompt_hidden(prompter
->type
);
1750 prompt
.reply
= &password_data
;
1752 switch (prompter
->type
) {
1753 case HX509_PROMPT_TYPE_INFO
:
1754 prompt
.type
= KRB5_PROMPT_TYPE_INFO
;
1756 case HX509_PROMPT_TYPE_PASSWORD
:
1757 case HX509_PROMPT_TYPE_QUESTION
:
1759 prompt
.type
= KRB5_PROMPT_TYPE_PASSWORD
;
1763 ret
= (*p
->prompter
)(p
->context
, p
->prompter_data
, NULL
, NULL
, 1, &prompt
);
1765 memset (prompter
->reply
.data
, 0, prompter
->reply
.length
);
1771 static krb5_error_code
1772 _krb5_pk_set_user_id(krb5_context context
,
1773 krb5_principal principal
,
1774 krb5_pk_init_ctx ctx
,
1775 struct hx509_certs_data
*certs
)
1777 hx509_certs c
= hx509_certs_ref(certs
);
1778 hx509_query
*q
= NULL
;
1782 hx509_certs_free(&ctx
->id
->certs
);
1783 if (ctx
->id
->cert
) {
1784 hx509_cert_free(ctx
->id
->cert
);
1785 ctx
->id
->cert
= NULL
;
1791 ret
= hx509_query_alloc(context
->hx509ctx
, &q
);
1793 pk_copy_error(context
, context
->hx509ctx
, ret
,
1794 "Allocate query to find signing certificate");
1798 hx509_query_match_option(q
, HX509_QUERY_OPTION_PRIVATE_KEY
);
1799 hx509_query_match_option(q
, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE
);
1801 if (principal
&& strncmp("LKDC:SHA1.", krb5_principal_get_realm(context
, principal
), 9) == 0) {
1802 ctx
->id
->flags
|= PKINIT_BTMM
;
1805 ret
= find_cert(context
, ctx
->id
, q
, &ctx
->id
->cert
);
1806 hx509_query_free(context
->hx509ctx
, q
);
1808 if (ret
== 0 && _krb5_have_debug(context
, 2)) {
1813 ret
= hx509_cert_get_subject(ctx
->id
->cert
, &name
);
1817 ret
= hx509_name_to_string(name
, &str
);
1818 hx509_name_free(&name
);
1822 ret
= hx509_cert_get_serialnumber(ctx
->id
->cert
, &i
);
1828 ret
= der_print_hex_heim_integer(&i
, &sn
);
1829 der_free_heim_integer(&i
);
1835 _krb5_debug(context
, 2, "using cert: subject: %s sn: %s", str
, sn
);
1844 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1845 _krb5_pk_load_id(krb5_context context
,
1846 struct krb5_pk_identity
**ret_id
,
1847 const char *user_id
,
1848 const char *anchor_id
,
1849 char * const *chain_list
,
1850 char * const *revoke_list
,
1851 krb5_prompter_fct prompter
,
1852 void *prompter_data
,
1855 struct krb5_pk_identity
*id
= NULL
;
1857 krb5_error_code ret
;
1863 id
= calloc(1, sizeof(*id
));
1865 return krb5_enomem(context
);
1870 ret
= hx509_lock_init(context
->hx509ctx
, &lock
);
1872 pk_copy_error(context
, context
->hx509ctx
, ret
, "Failed init lock");
1876 if (password
&& password
[0])
1877 hx509_lock_add_password(lock
, password
);
1880 p
.context
= context
;
1881 p
.prompter
= prompter
;
1882 p
.prompter_data
= prompter_data
;
1884 ret
= hx509_lock_set_prompter(lock
, hx_pass_prompter
, &p
);
1886 hx509_lock_free(lock
);
1891 ret
= hx509_certs_init(context
->hx509ctx
, user_id
, 0, lock
, &id
->certs
);
1892 hx509_lock_free(lock
);
1894 pk_copy_error(context
, context
->hx509ctx
, ret
,
1895 "Failed to init cert certs");
1902 ret
= hx509_certs_init(context
->hx509ctx
, anchor_id
, 0, NULL
, &id
->anchors
);
1904 pk_copy_error(context
, context
->hx509ctx
, ret
,
1905 "Failed to init anchors");
1909 ret
= hx509_certs_init(context
->hx509ctx
, "MEMORY:pkinit-cert-chain",
1910 0, NULL
, &id
->certpool
);
1912 pk_copy_error(context
, context
->hx509ctx
, ret
,
1913 "Failed to init chain");
1917 while (chain_list
&& *chain_list
) {
1918 ret
= hx509_certs_append(context
->hx509ctx
, id
->certpool
,
1921 pk_copy_error(context
, context
->hx509ctx
, ret
,
1922 "Failed to load chain %s",
1930 ret
= hx509_revoke_init(context
->hx509ctx
, &id
->revokectx
);
1932 pk_copy_error(context
, context
->hx509ctx
, ret
,
1933 "Failed to init revoke list");
1937 while (*revoke_list
) {
1938 ret
= hx509_revoke_add_crl(context
->hx509ctx
,
1942 pk_copy_error(context
, context
->hx509ctx
, ret
,
1943 "Failed to load revoke list");
1949 hx509_context_set_missing_revoke(context
->hx509ctx
, 1);
1951 ret
= hx509_verify_init_ctx(context
->hx509ctx
, &id
->verify_ctx
);
1953 pk_copy_error(context
, context
->hx509ctx
, ret
,
1954 "Failed to init verify context");
1958 hx509_verify_attach_anchors(id
->verify_ctx
, id
->anchors
);
1959 hx509_verify_attach_revoke(id
->verify_ctx
, id
->revokectx
);
1963 hx509_verify_destroy_ctx(id
->verify_ctx
);
1964 hx509_certs_free(&id
->certs
);
1965 hx509_certs_free(&id
->anchors
);
1966 hx509_certs_free(&id
->certpool
);
1967 hx509_revoke_free(&id
->revokectx
);
1980 pk_copy_error(krb5_context context
,
1981 hx509_context hx509ctx
,
1991 ret
= vasprintf(&f
, fmt
, va
);
1993 if (ret
== -1 || f
== NULL
) {
1994 krb5_clear_error_message(context
);
1998 s
= hx509_get_error_string(hx509ctx
, hxret
);
2000 krb5_clear_error_message(context
);
2004 krb5_set_error_message(context
, hxret
, "%s: %s", f
, s
);
2010 parse_integer(krb5_context context
, char **p
, const char *file
, int lineno
,
2011 const char *name
, heim_integer
*integer
)
2015 p1
= strsep(p
, " \t");
2017 krb5_set_error_message(context
, EINVAL
,
2018 N_("moduli file %s missing %s on line %d", ""),
2019 file
, name
, lineno
);
2022 ret
= der_parse_hex_heim_integer(p1
, integer
);
2024 krb5_set_error_message(context
, ret
,
2025 N_("moduli file %s failed parsing %s "
2027 file
, name
, lineno
);
2034 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2035 _krb5_parse_moduli_line(krb5_context context
,
2039 struct krb5_dh_moduli
**m
)
2041 struct krb5_dh_moduli
*m1
;
2047 m1
= calloc(1, sizeof(*m1
));
2049 return krb5_enomem(context
);
2051 while (isspace((unsigned char)*p
))
2059 p1
= strsep(&p
, " \t");
2061 krb5_set_error_message(context
, ret
,
2062 N_("moduli file %s missing name on line %d", ""),
2066 m1
->name
= strdup(p1
);
2067 if (m1
->name
== NULL
) {
2068 ret
= krb5_enomem(context
);
2072 p1
= strsep(&p
, " \t");
2074 krb5_set_error_message(context
, ret
,
2075 N_("moduli file %s missing bits on line %d", ""),
2080 m1
->bits
= atoi(p1
);
2081 if (m1
->bits
== 0) {
2082 krb5_set_error_message(context
, ret
,
2083 N_("moduli file %s has un-parsable "
2084 "bits on line %d", ""), file
, lineno
);
2088 ret
= parse_integer(context
, &p
, file
, lineno
, "p", &m1
->p
);
2091 ret
= parse_integer(context
, &p
, file
, lineno
, "g", &m1
->g
);
2094 ret
= parse_integer(context
, &p
, file
, lineno
, "q", &m1
->q
);
2099 krb5_clear_error_message(context
);
2107 der_free_heim_integer(&m1
->p
);
2108 der_free_heim_integer(&m1
->g
);
2109 der_free_heim_integer(&m1
->q
);
2115 free_moduli_element(struct krb5_dh_moduli
*element
)
2117 free(element
->name
);
2118 der_free_heim_integer(&element
->p
);
2119 der_free_heim_integer(&element
->g
);
2120 der_free_heim_integer(&element
->q
);
2124 KRB5_LIB_FUNCTION
void KRB5_LIB_CALL
2125 _krb5_free_moduli(struct krb5_dh_moduli
**moduli
)
2128 for (i
= 0; moduli
[i
] != NULL
; i
++)
2129 free_moduli_element(moduli
[i
]);
2133 static const char *default_moduli_RFC2412_MODP_group2
=
2135 "RFC2412-MODP-group2 "
2139 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
2140 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
2141 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
2142 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
2143 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
2144 "FFFFFFFF" "FFFFFFFF "
2148 "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68"
2149 "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E"
2150 "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122"
2151 "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6"
2152 "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F67329C0"
2153 "FFFFFFFF" "FFFFFFFF";
2155 static const char *default_moduli_rfc3526_MODP_group14
=
2157 "rfc3526-MODP-group14 "
2161 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
2162 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
2163 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
2164 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
2165 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D"
2166 "C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"
2167 "83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"
2168 "670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"
2169 "E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"
2170 "DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
2171 "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF "
2175 "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68"
2176 "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E"
2177 "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122"
2178 "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6"
2179 "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F6722D9E"
2180 "E1003E5C" "50B1DF82" "CC6D241B" "0E2AE9CD" "348B1FD4" "7E9267AF"
2181 "C1B2AE91" "EE51D6CB" "0E3179AB" "1042A95D" "CF6A9483" "B84B4B36"
2182 "B3861AA7" "255E4C02" "78BA3604" "650C10BE" "19482F23" "171B671D"
2183 "F1CF3B96" "0C074301" "CD93C1D1" "7603D147" "DAE2AEF8" "37A62964"
2184 "EF15E5FB" "4AAC0B8C" "1CCAA4BE" "754AB572" "8AE9130C" "4C7D0288"
2185 "0AB9472D" "45565534" "7FFFFFFF" "FFFFFFFF";
2187 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2188 _krb5_parse_moduli(krb5_context context
, const char *file
,
2189 struct krb5_dh_moduli
***moduli
)
2191 /* name bits P G Q */
2192 krb5_error_code ret
;
2193 struct krb5_dh_moduli
**m
= NULL
, **m2
;
2196 int lineno
= 0, n
= 0;
2200 m
= calloc(1, sizeof(m
[0]) * 3);
2202 return krb5_enomem(context
);
2204 strlcpy(buf
, default_moduli_rfc3526_MODP_group14
, sizeof(buf
));
2205 ret
= _krb5_parse_moduli_line(context
, "builtin", 1, buf
, &m
[0]);
2207 _krb5_free_moduli(m
);
2212 strlcpy(buf
, default_moduli_RFC2412_MODP_group2
, sizeof(buf
));
2213 ret
= _krb5_parse_moduli_line(context
, "builtin", 1, buf
, &m
[1]);
2215 _krb5_free_moduli(m
);
2227 if (_krb5_expand_path_tokens(context
, file
, 1, &exp_file
) == 0) {
2228 f
= fopen(exp_file
, "r");
2229 krb5_xfree(exp_file
);
2241 while(fgets(buf
, sizeof(buf
), f
) != NULL
) {
2242 struct krb5_dh_moduli
*element
;
2244 buf
[strcspn(buf
, "\n")] = '\0';
2247 ret
= _krb5_parse_moduli_line(context
, file
, lineno
, buf
, &element
);
2250 if (element
== NULL
)
2253 m2
= realloc(m
, (n
+ 2) * sizeof(m
[0]));
2255 free_moduli_element(element
);
2256 ret
= krb5_enomem(context
);
2266 _krb5_free_moduli(m
);
2276 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2277 _krb5_dh_group_ok(krb5_context context
, unsigned long bits
,
2278 heim_integer
*p
, heim_integer
*g
, heim_integer
*q
,
2279 struct krb5_dh_moduli
**moduli
,
2287 for (i
= 0; moduli
[i
] != NULL
; i
++) {
2288 if (der_heim_integer_cmp(&moduli
[i
]->g
, g
) == 0 &&
2289 der_heim_integer_cmp(&moduli
[i
]->p
, p
) == 0 &&
2290 (q
== NULL
|| moduli
[i
]->q
.length
== 0 ||
2291 der_heim_integer_cmp(&moduli
[i
]->q
, q
) == 0))
2293 if (bits
&& bits
> moduli
[i
]->bits
) {
2294 krb5_set_error_message(context
,
2295 KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED
,
2296 N_("PKINIT: DH group parameter %s "
2297 "not accepted, not enough bits "
2300 return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED
;
2303 *name
= strdup(moduli
[i
]->name
);
2307 krb5_set_error_message(context
,
2308 KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED
,
2309 N_("PKINIT: DH group parameter not ok", ""));
2310 return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED
;
2314 KRB5_LIB_FUNCTION
void KRB5_LIB_CALL
2315 _krb5_get_init_creds_opt_free_pkinit(krb5_get_init_creds_opt
*opt
)
2318 krb5_pk_init_ctx ctx
;
2320 if (opt
->opt_private
== NULL
|| opt
->opt_private
->pk_init_ctx
== NULL
)
2322 ctx
= opt
->opt_private
->pk_init_ctx
;
2323 switch (ctx
->keyex
) {
2332 _krb5_pk_eckey_free(ctx
->u
.eckey
);
2336 hx509_verify_destroy_ctx(ctx
->id
->verify_ctx
);
2337 hx509_certs_free(&ctx
->id
->certs
);
2338 hx509_cert_free(ctx
->id
->cert
);
2339 hx509_certs_free(&ctx
->id
->anchors
);
2340 hx509_certs_free(&ctx
->id
->certpool
);
2342 if (ctx
->clientDHNonce
) {
2343 krb5_free_data(NULL
, ctx
->clientDHNonce
);
2344 ctx
->clientDHNonce
= NULL
;
2347 _krb5_free_moduli(ctx
->m
);
2351 free(opt
->opt_private
->pk_init_ctx
);
2352 opt
->opt_private
->pk_init_ctx
= NULL
;
2356 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2357 krb5_get_init_creds_opt_set_pkinit(krb5_context context
,
2358 krb5_get_init_creds_opt
*opt
,
2359 krb5_principal principal
,
2360 const char *user_id
,
2361 const char *x509_anchors
,
2362 char * const * pool
,
2363 char * const * pki_revoke
,
2365 krb5_prompter_fct prompter
,
2366 void *prompter_data
,
2370 krb5_error_code ret
;
2371 char **freeme1
= NULL
;
2372 char **freeme2
= NULL
;
2373 char *anchors
= NULL
;
2375 if (opt
->opt_private
== NULL
) {
2376 krb5_set_error_message(context
, EINVAL
,
2377 N_("PKINIT: on non extendable opt", ""));
2381 opt
->opt_private
->pk_init_ctx
=
2382 calloc(1, sizeof(*opt
->opt_private
->pk_init_ctx
));
2383 if (opt
->opt_private
->pk_init_ctx
== NULL
)
2384 return krb5_enomem(context
);
2385 opt
->opt_private
->pk_init_ctx
->require_binding
= 0;
2386 opt
->opt_private
->pk_init_ctx
->require_eku
= 1;
2387 opt
->opt_private
->pk_init_ctx
->require_krbtgt_otherName
= 1;
2388 opt
->opt_private
->pk_init_ctx
->peer
= NULL
;
2390 /* XXX implement krb5_appdefault_strings */
2392 pool
= freeme1
= krb5_config_get_strings(context
, NULL
, "appdefaults",
2393 "pkinit_pool", NULL
);
2395 if (pki_revoke
== NULL
)
2396 pki_revoke
= freeme2
= krb5_config_get_strings(context
, NULL
,
2398 "pkinit_revoke", NULL
);
2400 if (x509_anchors
== NULL
) {
2401 krb5_appdefault_string(context
, "kinit",
2402 krb5_principal_get_realm(context
, principal
),
2403 "pkinit_anchors", NULL
, &anchors
);
2404 x509_anchors
= anchors
;
2407 if (flags
& KRB5_GIC_OPT_PKINIT_ANONYMOUS
)
2408 opt
->opt_private
->pk_init_ctx
->anonymous
= 1;
2410 if ((flags
& KRB5_GIC_OPT_PKINIT_NO_KDC_ANCHOR
) == 0 &&
2411 x509_anchors
== NULL
) {
2412 krb5_set_error_message(context
, HEIM_PKINIT_NO_VALID_CA
,
2413 N_("PKINIT: No anchor given", ""));
2414 return HEIM_PKINIT_NO_VALID_CA
;
2417 ret
= _krb5_pk_load_id(context
,
2418 &opt
->opt_private
->pk_init_ctx
->id
,
2426 krb5_config_free_strings(freeme2
);
2427 krb5_config_free_strings(freeme1
);
2430 free(opt
->opt_private
->pk_init_ctx
);
2431 opt
->opt_private
->pk_init_ctx
= NULL
;
2434 if (flags
& KRB5_GIC_OPT_PKINIT_BTMM
)
2435 opt
->opt_private
->pk_init_ctx
->id
->flags
|= PKINIT_BTMM
;
2436 if (principal
&& krb5_principal_is_lkdc(context
, principal
))
2437 opt
->opt_private
->pk_init_ctx
->id
->flags
|= PKINIT_BTMM
;
2438 if (flags
& KRB5_GIC_OPT_PKINIT_NO_KDC_ANCHOR
)
2439 opt
->opt_private
->pk_init_ctx
->id
->flags
|= PKINIT_NO_KDC_ANCHOR
;
2441 if (opt
->opt_private
->pk_init_ctx
->id
->certs
) {
2442 ret
= _krb5_pk_set_user_id(context
,
2444 opt
->opt_private
->pk_init_ctx
,
2445 opt
->opt_private
->pk_init_ctx
->id
->certs
);
2447 free(opt
->opt_private
->pk_init_ctx
);
2448 opt
->opt_private
->pk_init_ctx
= NULL
;
2452 opt
->opt_private
->pk_init_ctx
->id
->cert
= NULL
;
2454 if ((flags
& KRB5_GIC_OPT_PKINIT_USE_ENCKEY
) == 0) {
2455 hx509_context hx509ctx
= context
->hx509ctx
;
2456 hx509_cert cert
= opt
->opt_private
->pk_init_ctx
->id
->cert
;
2458 opt
->opt_private
->pk_init_ctx
->keyex
= USE_DH
;
2461 * If its a ECDSA certs, lets select ECDSA as the keyex algorithm.
2464 AlgorithmIdentifier alg
;
2466 ret
= hx509_cert_get_SPKI_AlgorithmIdentifier(hx509ctx
, cert
, &alg
);
2468 if (der_heim_oid_cmp(&alg
.algorithm
, &asn1_oid_id_ecPublicKey
) == 0)
2469 opt
->opt_private
->pk_init_ctx
->keyex
= USE_ECDH
;
2470 free_AlgorithmIdentifier(&alg
);
2475 opt
->opt_private
->pk_init_ctx
->keyex
= USE_RSA
;
2477 if (opt
->opt_private
->pk_init_ctx
->id
->certs
== NULL
) {
2478 krb5_set_error_message(context
, EINVAL
,
2479 N_("No anonymous pkinit support in RSA mode", ""));
2486 krb5_set_error_message(context
, EINVAL
,
2487 N_("no support for PKINIT compiled in", ""));
2492 krb5_error_code KRB5_LIB_FUNCTION
2493 krb5_get_init_creds_opt_set_pkinit_user_certs(krb5_context context
,
2494 krb5_get_init_creds_opt
*opt
,
2495 struct hx509_certs_data
*certs
)
2498 if (opt
->opt_private
== NULL
) {
2499 krb5_set_error_message(context
, EINVAL
,
2500 N_("PKINIT: on non extendable opt", ""));
2503 if (opt
->opt_private
->pk_init_ctx
== NULL
) {
2504 krb5_set_error_message(context
, EINVAL
,
2505 N_("PKINIT: on pkinit context", ""));
2509 return _krb5_pk_set_user_id(context
, NULL
, opt
->opt_private
->pk_init_ctx
, certs
);
2511 krb5_set_error_message(context
, EINVAL
,
2512 N_("no support for PKINIT compiled in", ""));
2520 get_ms_san(hx509_context context
, hx509_cert cert
, char **upn
)
2522 hx509_octet_string_list list
;
2527 ret
= hx509_cert_find_subjectAltName_otherName(context
,
2529 &asn1_oid_id_pkinit_ms_san
,
2534 if (list
.len
> 0 && list
.val
[0].length
> 0)
2535 ret
= decode_MS_UPN_SAN(list
.val
[0].data
, list
.val
[0].length
,
2539 hx509_free_octet_string_list(&list
);
2545 find_ms_san(hx509_context context
, hx509_cert cert
, void *ctx
)
2550 ret
= get_ms_san(context
, cert
, &upn
);
2561 * Private since it need to be redesigned using krb5_get_init_creds()
2564 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2565 krb5_pk_enterprise_cert(krb5_context context
,
2566 const char *user_id
,
2567 krb5_const_realm realm
,
2568 krb5_principal
*principal
,
2569 struct hx509_certs_data
**res
)
2572 krb5_error_code ret
;
2573 hx509_certs certs
, result
;
2574 hx509_cert cert
= NULL
;
2582 if (user_id
== NULL
) {
2583 krb5_set_error_message(context
, ENOENT
, "no user id");
2587 ret
= hx509_certs_init(context
->hx509ctx
, user_id
, 0, NULL
, &certs
);
2589 pk_copy_error(context
, context
->hx509ctx
, ret
,
2590 "Failed to init cert certs");
2594 ret
= hx509_query_alloc(context
->hx509ctx
, &q
);
2596 krb5_set_error_message(context
, ret
, "out of memory");
2597 hx509_certs_free(&certs
);
2601 hx509_query_match_option(q
, HX509_QUERY_OPTION_PRIVATE_KEY
);
2602 hx509_query_match_option(q
, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE
);
2603 hx509_query_match_eku(q
, &asn1_oid_id_pkinit_ms_eku
);
2604 hx509_query_match_cmp_func(q
, find_ms_san
, NULL
);
2606 ret
= hx509_certs_filter(context
->hx509ctx
, certs
, q
, &result
);
2607 hx509_query_free(context
->hx509ctx
, q
);
2608 hx509_certs_free(&certs
);
2610 pk_copy_error(context
, context
->hx509ctx
, ret
,
2611 "Failed to find PKINIT certificate");
2615 ret
= hx509_get_one_cert(context
->hx509ctx
, result
, &cert
);
2616 hx509_certs_free(&result
);
2618 pk_copy_error(context
, context
->hx509ctx
, ret
,
2619 "Failed to get one cert");
2623 ret
= get_ms_san(context
->hx509ctx
, cert
, &name
);
2625 pk_copy_error(context
, context
->hx509ctx
, ret
,
2626 "Failed to get MS SAN");
2630 ret
= krb5_make_principal(context
, principal
, realm
, name
, NULL
);
2635 krb5_principal_set_type(context
, *principal
, KRB5_NT_ENTERPRISE_PRINCIPAL
);
2638 ret
= hx509_certs_init(context
->hx509ctx
, "MEMORY:", 0, NULL
, res
);
2642 ret
= hx509_certs_add(context
->hx509ctx
, *res
, cert
);
2644 hx509_certs_free(res
);
2650 hx509_cert_free(cert
);
2654 krb5_set_error_message(context
, EINVAL
,
2655 N_("no support for PKINIT compiled in", ""));
2660 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
2661 _krb5_pk_is_kdc_verified(krb5_context context
,
2662 krb5_get_init_creds_opt
*opt
)
2665 opt
->opt_private
== NULL
||
2666 opt
->opt_private
->pk_init_ctx
== NULL
)
2669 return opt
->opt_private
->pk_init_ctx
->kdc_verified
;