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
);
1501 ret
= _krb5_pk_rd_pa_reply_ecdh_compute_key(context
, ctx
, p
,
1508 if (dh_gen_keylen
<= 0) {
1510 krb5_set_error_message(context
, ret
,
1511 N_("PKINIT: resulting DH key <= 0", ""));
1516 *key
= malloc (sizeof (**key
));
1518 ret
= krb5_enomem(context
);
1522 ret
= _krb5_pk_octetstring2key(context
,
1524 dh_gen_key
, dh_gen_keylen
,
1528 krb5_set_error_message(context
, ret
,
1529 N_("PKINIT: can't create key from DH key", ""));
1537 BN_free(kdc_dh_pubkey
);
1539 memset(dh_gen_key
, 0, dh_gen_keylen
);
1543 _krb5_pk_cert_free(host
);
1545 krb5_data_free(&content
);
1546 der_free_oid(&contentType
);
1547 free_KDCDHKeyInfo(&kdc_dh_info
);
1552 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1553 _krb5_pk_rd_pa_reply(krb5_context context
,
1558 const krb5_data
*req_buffer
,
1560 krb5_keyblock
**key
)
1562 krb5_pk_init_ctx ctx
= c
;
1563 krb5_error_code ret
;
1566 /* Check for IETF PK-INIT first */
1567 if (ctx
->type
== PKINIT_27
) {
1569 heim_octet_string os
, data
;
1572 if (pa
->padata_type
!= KRB5_PADATA_PK_AS_REP
) {
1573 krb5_set_error_message(context
, EINVAL
,
1574 N_("PKINIT: wrong padata recv", ""));
1578 ret
= decode_PA_PK_AS_REP(pa
->padata_value
.data
,
1579 pa
->padata_value
.length
,
1583 krb5_set_error_message(context
, ret
,
1584 N_("Failed to decode pkinit AS rep", ""));
1588 switch (rep
.element
) {
1589 case choice_PA_PK_AS_REP_dhInfo
:
1590 _krb5_debug(context
, 5, "krb5_get_init_creds: using pkinit dh");
1591 os
= rep
.u
.dhInfo
.dhSignedData
;
1593 case choice_PA_PK_AS_REP_encKeyPack
:
1594 _krb5_debug(context
, 5, "krb5_get_init_creds: using kinit enc reply key");
1595 os
= rep
.u
.encKeyPack
;
1598 PA_PK_AS_REP_BTMM btmm
;
1599 free_PA_PK_AS_REP(&rep
);
1600 memset(&rep
, 0, sizeof(rep
));
1602 _krb5_debug(context
, 5, "krb5_get_init_creds: using BTMM kinit enc reply key");
1604 ret
= decode_PA_PK_AS_REP_BTMM(pa
->padata_value
.data
,
1605 pa
->padata_value
.length
,
1609 krb5_set_error_message(context
, EINVAL
,
1610 N_("PKINIT: -27 reply "
1611 "invalid content type", ""));
1615 if (btmm
.dhSignedData
|| btmm
.encKeyPack
== NULL
) {
1616 free_PA_PK_AS_REP_BTMM(&btmm
);
1618 krb5_set_error_message(context
, ret
,
1619 N_("DH mode not supported for BTMM mode", ""));
1624 * Transform to IETF style PK-INIT reply so that free works below
1627 rep
.element
= choice_PA_PK_AS_REP_encKeyPack
;
1628 rep
.u
.encKeyPack
.data
= btmm
.encKeyPack
->data
;
1629 rep
.u
.encKeyPack
.length
= btmm
.encKeyPack
->length
;
1630 btmm
.encKeyPack
->data
= NULL
;
1631 btmm
.encKeyPack
->length
= 0;
1632 free_PA_PK_AS_REP_BTMM(&btmm
);
1633 os
= rep
.u
.encKeyPack
;
1637 ret
= hx509_cms_unwrap_ContentInfo(&os
, &oid
, &data
, NULL
);
1639 free_PA_PK_AS_REP(&rep
);
1640 krb5_set_error_message(context
, ret
,
1641 N_("PKINIT: failed to unwrap CI", ""));
1645 switch (rep
.element
) {
1646 case choice_PA_PK_AS_REP_dhInfo
:
1647 ret
= pk_rd_pa_reply_dh(context
, &data
, &oid
, realm
, ctx
, etype
,
1649 rep
.u
.dhInfo
.serverDHNonce
,
1652 case choice_PA_PK_AS_REP_encKeyPack
:
1653 ret
= pk_rd_pa_reply_enckey(context
, PKINIT_27
, &data
, &oid
, realm
,
1654 ctx
, etype
, nonce
, req_buffer
, pa
, key
);
1657 krb5_abortx(context
, "pk-init as-rep case not possible to happen");
1659 der_free_octet_string(&data
);
1661 free_PA_PK_AS_REP(&rep
);
1663 } else if (ctx
->type
== PKINIT_WIN2K
) {
1664 PA_PK_AS_REP_Win2k w2krep
;
1666 /* Check for Windows encoding of the AS-REP pa data */
1668 #if 0 /* should this be ? */
1669 if (pa
->padata_type
!= KRB5_PADATA_PK_AS_REP
) {
1670 krb5_set_error_message(context
, EINVAL
,
1671 "PKINIT: wrong padata recv");
1676 memset(&w2krep
, 0, sizeof(w2krep
));
1678 ret
= decode_PA_PK_AS_REP_Win2k(pa
->padata_value
.data
,
1679 pa
->padata_value
.length
,
1683 krb5_set_error_message(context
, ret
,
1684 N_("PKINIT: Failed decoding windows "
1685 "pkinit reply %d", ""), (int)ret
);
1689 krb5_clear_error_message(context
);
1691 switch (w2krep
.element
) {
1692 case choice_PA_PK_AS_REP_Win2k_encKeyPack
: {
1693 heim_octet_string data
;
1696 ret
= hx509_cms_unwrap_ContentInfo(&w2krep
.u
.encKeyPack
,
1698 free_PA_PK_AS_REP_Win2k(&w2krep
);
1700 krb5_set_error_message(context
, ret
,
1701 N_("PKINIT: failed to unwrap CI", ""));
1705 ret
= pk_rd_pa_reply_enckey(context
, PKINIT_WIN2K
, &data
, &oid
, realm
,
1706 ctx
, etype
, nonce
, req_buffer
, pa
, key
);
1707 der_free_octet_string(&data
);
1713 free_PA_PK_AS_REP_Win2k(&w2krep
);
1715 krb5_set_error_message(context
, ret
,
1716 N_("PKINIT: win2k reply invalid "
1717 "content type", ""));
1723 krb5_set_error_message(context
, ret
,
1724 N_("PKINIT: unknown reply type", ""));
1731 krb5_context context
;
1732 krb5_prompter_fct prompter
;
1733 void *prompter_data
;
1737 hx_pass_prompter(void *data
, const hx509_prompt
*prompter
)
1739 krb5_error_code ret
;
1741 krb5_data password_data
;
1742 struct prompter
*p
= data
;
1744 password_data
.data
= prompter
->reply
.data
;
1745 password_data
.length
= prompter
->reply
.length
;
1747 prompt
.prompt
= prompter
->prompt
;
1748 prompt
.hidden
= hx509_prompt_hidden(prompter
->type
);
1749 prompt
.reply
= &password_data
;
1751 switch (prompter
->type
) {
1752 case HX509_PROMPT_TYPE_INFO
:
1753 prompt
.type
= KRB5_PROMPT_TYPE_INFO
;
1755 case HX509_PROMPT_TYPE_PASSWORD
:
1756 case HX509_PROMPT_TYPE_QUESTION
:
1758 prompt
.type
= KRB5_PROMPT_TYPE_PASSWORD
;
1762 ret
= (*p
->prompter
)(p
->context
, p
->prompter_data
, NULL
, NULL
, 1, &prompt
);
1764 memset (prompter
->reply
.data
, 0, prompter
->reply
.length
);
1770 static krb5_error_code
1771 _krb5_pk_set_user_id(krb5_context context
,
1772 krb5_principal principal
,
1773 krb5_pk_init_ctx ctx
,
1774 struct hx509_certs_data
*certs
)
1776 hx509_certs c
= hx509_certs_ref(certs
);
1777 hx509_query
*q
= NULL
;
1781 hx509_certs_free(&ctx
->id
->certs
);
1782 if (ctx
->id
->cert
) {
1783 hx509_cert_free(ctx
->id
->cert
);
1784 ctx
->id
->cert
= NULL
;
1790 ret
= hx509_query_alloc(context
->hx509ctx
, &q
);
1792 pk_copy_error(context
, context
->hx509ctx
, ret
,
1793 "Allocate query to find signing certificate");
1797 hx509_query_match_option(q
, HX509_QUERY_OPTION_PRIVATE_KEY
);
1798 hx509_query_match_option(q
, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE
);
1800 if (principal
&& strncmp("LKDC:SHA1.", krb5_principal_get_realm(context
, principal
), 9) == 0) {
1801 ctx
->id
->flags
|= PKINIT_BTMM
;
1804 ret
= find_cert(context
, ctx
->id
, q
, &ctx
->id
->cert
);
1805 hx509_query_free(context
->hx509ctx
, q
);
1807 if (ret
== 0 && _krb5_have_debug(context
, 2)) {
1812 ret
= hx509_cert_get_subject(ctx
->id
->cert
, &name
);
1816 ret
= hx509_name_to_string(name
, &str
);
1817 hx509_name_free(&name
);
1821 ret
= hx509_cert_get_serialnumber(ctx
->id
->cert
, &i
);
1827 ret
= der_print_hex_heim_integer(&i
, &sn
);
1828 der_free_heim_integer(&i
);
1834 _krb5_debug(context
, 2, "using cert: subject: %s sn: %s", str
, sn
);
1843 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1844 _krb5_pk_load_id(krb5_context context
,
1845 struct krb5_pk_identity
**ret_id
,
1846 const char *user_id
,
1847 const char *anchor_id
,
1848 char * const *chain_list
,
1849 char * const *revoke_list
,
1850 krb5_prompter_fct prompter
,
1851 void *prompter_data
,
1854 struct krb5_pk_identity
*id
= NULL
;
1856 krb5_error_code ret
;
1862 id
= calloc(1, sizeof(*id
));
1864 return krb5_enomem(context
);
1869 ret
= hx509_lock_init(context
->hx509ctx
, &lock
);
1871 pk_copy_error(context
, context
->hx509ctx
, ret
, "Failed init lock");
1875 if (password
&& password
[0])
1876 hx509_lock_add_password(lock
, password
);
1879 p
.context
= context
;
1880 p
.prompter
= prompter
;
1881 p
.prompter_data
= prompter_data
;
1883 ret
= hx509_lock_set_prompter(lock
, hx_pass_prompter
, &p
);
1885 hx509_lock_free(lock
);
1890 ret
= hx509_certs_init(context
->hx509ctx
, user_id
, 0, lock
, &id
->certs
);
1891 hx509_lock_free(lock
);
1893 pk_copy_error(context
, context
->hx509ctx
, ret
,
1894 "Failed to init cert certs");
1901 ret
= hx509_certs_init(context
->hx509ctx
, anchor_id
, 0, NULL
, &id
->anchors
);
1903 pk_copy_error(context
, context
->hx509ctx
, ret
,
1904 "Failed to init anchors");
1908 ret
= hx509_certs_init(context
->hx509ctx
, "MEMORY:pkinit-cert-chain",
1909 0, NULL
, &id
->certpool
);
1911 pk_copy_error(context
, context
->hx509ctx
, ret
,
1912 "Failed to init chain");
1916 while (chain_list
&& *chain_list
) {
1917 ret
= hx509_certs_append(context
->hx509ctx
, id
->certpool
,
1920 pk_copy_error(context
, context
->hx509ctx
, ret
,
1921 "Failed to load chain %s",
1929 ret
= hx509_revoke_init(context
->hx509ctx
, &id
->revokectx
);
1931 pk_copy_error(context
, context
->hx509ctx
, ret
,
1932 "Failed to init revoke list");
1936 while (*revoke_list
) {
1937 ret
= hx509_revoke_add_crl(context
->hx509ctx
,
1941 pk_copy_error(context
, context
->hx509ctx
, ret
,
1942 "Failed to load revoke list");
1948 hx509_context_set_missing_revoke(context
->hx509ctx
, 1);
1950 ret
= hx509_verify_init_ctx(context
->hx509ctx
, &id
->verify_ctx
);
1952 pk_copy_error(context
, context
->hx509ctx
, ret
,
1953 "Failed to init verify context");
1957 hx509_verify_attach_anchors(id
->verify_ctx
, id
->anchors
);
1958 hx509_verify_attach_revoke(id
->verify_ctx
, id
->revokectx
);
1962 hx509_verify_destroy_ctx(id
->verify_ctx
);
1963 hx509_certs_free(&id
->certs
);
1964 hx509_certs_free(&id
->anchors
);
1965 hx509_certs_free(&id
->certpool
);
1966 hx509_revoke_free(&id
->revokectx
);
1979 pk_copy_error(krb5_context context
,
1980 hx509_context hx509ctx
,
1990 ret
= vasprintf(&f
, fmt
, va
);
1992 if (ret
== -1 || f
== NULL
) {
1993 krb5_clear_error_message(context
);
1997 s
= hx509_get_error_string(hx509ctx
, hxret
);
1999 krb5_clear_error_message(context
);
2003 krb5_set_error_message(context
, hxret
, "%s: %s", f
, s
);
2009 parse_integer(krb5_context context
, char **p
, const char *file
, int lineno
,
2010 const char *name
, heim_integer
*integer
)
2014 p1
= strsep(p
, " \t");
2016 krb5_set_error_message(context
, EINVAL
,
2017 N_("moduli file %s missing %s on line %d", ""),
2018 file
, name
, lineno
);
2021 ret
= der_parse_hex_heim_integer(p1
, integer
);
2023 krb5_set_error_message(context
, ret
,
2024 N_("moduli file %s failed parsing %s "
2026 file
, name
, lineno
);
2033 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2034 _krb5_parse_moduli_line(krb5_context context
,
2038 struct krb5_dh_moduli
**m
)
2040 struct krb5_dh_moduli
*m1
;
2046 m1
= calloc(1, sizeof(*m1
));
2048 return krb5_enomem(context
);
2050 while (isspace((unsigned char)*p
))
2058 p1
= strsep(&p
, " \t");
2060 krb5_set_error_message(context
, ret
,
2061 N_("moduli file %s missing name on line %d", ""),
2065 m1
->name
= strdup(p1
);
2066 if (m1
->name
== NULL
) {
2067 ret
= krb5_enomem(context
);
2071 p1
= strsep(&p
, " \t");
2073 krb5_set_error_message(context
, ret
,
2074 N_("moduli file %s missing bits on line %d", ""),
2079 m1
->bits
= atoi(p1
);
2080 if (m1
->bits
== 0) {
2081 krb5_set_error_message(context
, ret
,
2082 N_("moduli file %s has un-parsable "
2083 "bits on line %d", ""), file
, lineno
);
2087 ret
= parse_integer(context
, &p
, file
, lineno
, "p", &m1
->p
);
2090 ret
= parse_integer(context
, &p
, file
, lineno
, "g", &m1
->g
);
2093 ret
= parse_integer(context
, &p
, file
, lineno
, "q", &m1
->q
);
2098 krb5_clear_error_message(context
);
2106 der_free_heim_integer(&m1
->p
);
2107 der_free_heim_integer(&m1
->g
);
2108 der_free_heim_integer(&m1
->q
);
2114 free_moduli_element(struct krb5_dh_moduli
*element
)
2116 free(element
->name
);
2117 der_free_heim_integer(&element
->p
);
2118 der_free_heim_integer(&element
->g
);
2119 der_free_heim_integer(&element
->q
);
2123 KRB5_LIB_FUNCTION
void KRB5_LIB_CALL
2124 _krb5_free_moduli(struct krb5_dh_moduli
**moduli
)
2127 for (i
= 0; moduli
[i
] != NULL
; i
++)
2128 free_moduli_element(moduli
[i
]);
2132 static const char *default_moduli_RFC2412_MODP_group2
=
2134 "RFC2412-MODP-group2 "
2138 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
2139 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
2140 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
2141 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
2142 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
2143 "FFFFFFFF" "FFFFFFFF "
2147 "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68"
2148 "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E"
2149 "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122"
2150 "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6"
2151 "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F67329C0"
2152 "FFFFFFFF" "FFFFFFFF";
2154 static const char *default_moduli_rfc3526_MODP_group14
=
2156 "rfc3526-MODP-group14 "
2160 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
2161 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
2162 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
2163 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
2164 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE45B3D"
2165 "C2007CB8" "A163BF05" "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F"
2166 "83655D23" "DCA3AD96" "1C62F356" "208552BB" "9ED52907" "7096966D"
2167 "670C354E" "4ABC9804" "F1746C08" "CA18217C" "32905E46" "2E36CE3B"
2168 "E39E772C" "180E8603" "9B2783A2" "EC07A28F" "B5C55DF0" "6F4C52C9"
2169 "DE2BCBF6" "95581718" "3995497C" "EA956AE5" "15D22618" "98FA0510"
2170 "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF "
2174 "7FFFFFFF" "FFFFFFFF" "E487ED51" "10B4611A" "62633145" "C06E0E68"
2175 "94812704" "4533E63A" "0105DF53" "1D89CD91" "28A5043C" "C71A026E"
2176 "F7CA8CD9" "E69D218D" "98158536" "F92F8A1B" "A7F09AB6" "B6A8E122"
2177 "F242DABB" "312F3F63" "7A262174" "D31BF6B5" "85FFAE5B" "7A035BF6"
2178 "F71C35FD" "AD44CFD2" "D74F9208" "BE258FF3" "24943328" "F6722D9E"
2179 "E1003E5C" "50B1DF82" "CC6D241B" "0E2AE9CD" "348B1FD4" "7E9267AF"
2180 "C1B2AE91" "EE51D6CB" "0E3179AB" "1042A95D" "CF6A9483" "B84B4B36"
2181 "B3861AA7" "255E4C02" "78BA3604" "650C10BE" "19482F23" "171B671D"
2182 "F1CF3B96" "0C074301" "CD93C1D1" "7603D147" "DAE2AEF8" "37A62964"
2183 "EF15E5FB" "4AAC0B8C" "1CCAA4BE" "754AB572" "8AE9130C" "4C7D0288"
2184 "0AB9472D" "45565534" "7FFFFFFF" "FFFFFFFF";
2186 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2187 _krb5_parse_moduli(krb5_context context
, const char *file
,
2188 struct krb5_dh_moduli
***moduli
)
2190 /* name bits P G Q */
2191 krb5_error_code ret
;
2192 struct krb5_dh_moduli
**m
= NULL
, **m2
;
2195 int lineno
= 0, n
= 0;
2199 m
= calloc(1, sizeof(m
[0]) * 3);
2201 return krb5_enomem(context
);
2203 strlcpy(buf
, default_moduli_rfc3526_MODP_group14
, sizeof(buf
));
2204 ret
= _krb5_parse_moduli_line(context
, "builtin", 1, buf
, &m
[0]);
2206 _krb5_free_moduli(m
);
2211 strlcpy(buf
, default_moduli_RFC2412_MODP_group2
, sizeof(buf
));
2212 ret
= _krb5_parse_moduli_line(context
, "builtin", 1, buf
, &m
[1]);
2214 _krb5_free_moduli(m
);
2226 if (_krb5_expand_path_tokens(context
, file
, 1, &exp_file
) == 0) {
2227 f
= fopen(exp_file
, "r");
2228 krb5_xfree(exp_file
);
2240 while(fgets(buf
, sizeof(buf
), f
) != NULL
) {
2241 struct krb5_dh_moduli
*element
;
2243 buf
[strcspn(buf
, "\n")] = '\0';
2246 ret
= _krb5_parse_moduli_line(context
, file
, lineno
, buf
, &element
);
2249 if (element
== NULL
)
2252 m2
= realloc(m
, (n
+ 2) * sizeof(m
[0]));
2254 free_moduli_element(element
);
2255 ret
= krb5_enomem(context
);
2265 _krb5_free_moduli(m
);
2275 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2276 _krb5_dh_group_ok(krb5_context context
, unsigned long bits
,
2277 heim_integer
*p
, heim_integer
*g
, heim_integer
*q
,
2278 struct krb5_dh_moduli
**moduli
,
2286 for (i
= 0; moduli
[i
] != NULL
; i
++) {
2287 if (der_heim_integer_cmp(&moduli
[i
]->g
, g
) == 0 &&
2288 der_heim_integer_cmp(&moduli
[i
]->p
, p
) == 0 &&
2289 (q
== NULL
|| moduli
[i
]->q
.length
== 0 ||
2290 der_heim_integer_cmp(&moduli
[i
]->q
, q
) == 0))
2292 if (bits
&& bits
> moduli
[i
]->bits
) {
2293 krb5_set_error_message(context
,
2294 KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED
,
2295 N_("PKINIT: DH group parameter %s "
2296 "not accepted, not enough bits "
2299 return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED
;
2302 *name
= strdup(moduli
[i
]->name
);
2306 krb5_set_error_message(context
,
2307 KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED
,
2308 N_("PKINIT: DH group parameter not ok", ""));
2309 return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED
;
2313 KRB5_LIB_FUNCTION
void KRB5_LIB_CALL
2314 _krb5_get_init_creds_opt_free_pkinit(krb5_get_init_creds_opt
*opt
)
2317 krb5_pk_init_ctx ctx
;
2319 if (opt
->opt_private
== NULL
|| opt
->opt_private
->pk_init_ctx
== NULL
)
2321 ctx
= opt
->opt_private
->pk_init_ctx
;
2322 switch (ctx
->keyex
) {
2331 _krb5_pk_eckey_free(ctx
->u
.eckey
);
2335 hx509_verify_destroy_ctx(ctx
->id
->verify_ctx
);
2336 hx509_certs_free(&ctx
->id
->certs
);
2337 hx509_cert_free(ctx
->id
->cert
);
2338 hx509_certs_free(&ctx
->id
->anchors
);
2339 hx509_certs_free(&ctx
->id
->certpool
);
2341 if (ctx
->clientDHNonce
) {
2342 krb5_free_data(NULL
, ctx
->clientDHNonce
);
2343 ctx
->clientDHNonce
= NULL
;
2346 _krb5_free_moduli(ctx
->m
);
2350 free(opt
->opt_private
->pk_init_ctx
);
2351 opt
->opt_private
->pk_init_ctx
= NULL
;
2355 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2356 krb5_get_init_creds_opt_set_pkinit(krb5_context context
,
2357 krb5_get_init_creds_opt
*opt
,
2358 krb5_principal principal
,
2359 const char *user_id
,
2360 const char *x509_anchors
,
2361 char * const * pool
,
2362 char * const * pki_revoke
,
2364 krb5_prompter_fct prompter
,
2365 void *prompter_data
,
2369 krb5_error_code ret
;
2370 char **freeme1
= NULL
;
2371 char **freeme2
= NULL
;
2372 char *anchors
= NULL
;
2374 if (opt
->opt_private
== NULL
) {
2375 krb5_set_error_message(context
, EINVAL
,
2376 N_("PKINIT: on non extendable opt", ""));
2380 opt
->opt_private
->pk_init_ctx
=
2381 calloc(1, sizeof(*opt
->opt_private
->pk_init_ctx
));
2382 if (opt
->opt_private
->pk_init_ctx
== NULL
)
2383 return krb5_enomem(context
);
2384 opt
->opt_private
->pk_init_ctx
->require_binding
= 0;
2385 opt
->opt_private
->pk_init_ctx
->require_eku
= 1;
2386 opt
->opt_private
->pk_init_ctx
->require_krbtgt_otherName
= 1;
2387 opt
->opt_private
->pk_init_ctx
->peer
= NULL
;
2389 /* XXX implement krb5_appdefault_strings */
2391 pool
= freeme1
= krb5_config_get_strings(context
, NULL
, "appdefaults",
2392 "pkinit_pool", NULL
);
2394 if (pki_revoke
== NULL
)
2395 pki_revoke
= freeme2
= krb5_config_get_strings(context
, NULL
,
2397 "pkinit_revoke", NULL
);
2399 if (x509_anchors
== NULL
) {
2400 krb5_appdefault_string(context
, "kinit",
2401 krb5_principal_get_realm(context
, principal
),
2402 "pkinit_anchors", NULL
, &anchors
);
2403 x509_anchors
= anchors
;
2406 if (flags
& KRB5_GIC_OPT_PKINIT_ANONYMOUS
)
2407 opt
->opt_private
->pk_init_ctx
->anonymous
= 1;
2409 if ((flags
& KRB5_GIC_OPT_PKINIT_NO_KDC_ANCHOR
) == 0 &&
2410 x509_anchors
== NULL
) {
2411 krb5_set_error_message(context
, HEIM_PKINIT_NO_VALID_CA
,
2412 N_("PKINIT: No anchor given", ""));
2413 return HEIM_PKINIT_NO_VALID_CA
;
2416 ret
= _krb5_pk_load_id(context
,
2417 &opt
->opt_private
->pk_init_ctx
->id
,
2425 krb5_config_free_strings(freeme2
);
2426 krb5_config_free_strings(freeme1
);
2429 free(opt
->opt_private
->pk_init_ctx
);
2430 opt
->opt_private
->pk_init_ctx
= NULL
;
2433 if (flags
& KRB5_GIC_OPT_PKINIT_BTMM
)
2434 opt
->opt_private
->pk_init_ctx
->id
->flags
|= PKINIT_BTMM
;
2435 if (principal
&& krb5_principal_is_lkdc(context
, principal
))
2436 opt
->opt_private
->pk_init_ctx
->id
->flags
|= PKINIT_BTMM
;
2437 if (flags
& KRB5_GIC_OPT_PKINIT_NO_KDC_ANCHOR
)
2438 opt
->opt_private
->pk_init_ctx
->id
->flags
|= PKINIT_NO_KDC_ANCHOR
;
2440 if (opt
->opt_private
->pk_init_ctx
->id
->certs
) {
2441 ret
= _krb5_pk_set_user_id(context
,
2443 opt
->opt_private
->pk_init_ctx
,
2444 opt
->opt_private
->pk_init_ctx
->id
->certs
);
2446 free(opt
->opt_private
->pk_init_ctx
);
2447 opt
->opt_private
->pk_init_ctx
= NULL
;
2451 opt
->opt_private
->pk_init_ctx
->id
->cert
= NULL
;
2453 if ((flags
& KRB5_GIC_OPT_PKINIT_USE_ENCKEY
) == 0) {
2454 hx509_context hx509ctx
= context
->hx509ctx
;
2455 hx509_cert cert
= opt
->opt_private
->pk_init_ctx
->id
->cert
;
2457 opt
->opt_private
->pk_init_ctx
->keyex
= USE_DH
;
2460 * If its a ECDSA certs, lets select ECDSA as the keyex algorithm.
2463 AlgorithmIdentifier alg
;
2465 ret
= hx509_cert_get_SPKI_AlgorithmIdentifier(hx509ctx
, cert
, &alg
);
2467 if (der_heim_oid_cmp(&alg
.algorithm
, &asn1_oid_id_ecPublicKey
) == 0)
2468 opt
->opt_private
->pk_init_ctx
->keyex
= USE_ECDH
;
2469 free_AlgorithmIdentifier(&alg
);
2474 opt
->opt_private
->pk_init_ctx
->keyex
= USE_RSA
;
2476 if (opt
->opt_private
->pk_init_ctx
->id
->certs
== NULL
) {
2477 krb5_set_error_message(context
, EINVAL
,
2478 N_("No anonymous pkinit support in RSA mode", ""));
2485 krb5_set_error_message(context
, EINVAL
,
2486 N_("no support for PKINIT compiled in", ""));
2491 krb5_error_code KRB5_LIB_FUNCTION
2492 krb5_get_init_creds_opt_set_pkinit_user_certs(krb5_context context
,
2493 krb5_get_init_creds_opt
*opt
,
2494 struct hx509_certs_data
*certs
)
2497 if (opt
->opt_private
== NULL
) {
2498 krb5_set_error_message(context
, EINVAL
,
2499 N_("PKINIT: on non extendable opt", ""));
2502 if (opt
->opt_private
->pk_init_ctx
== NULL
) {
2503 krb5_set_error_message(context
, EINVAL
,
2504 N_("PKINIT: on pkinit context", ""));
2508 return _krb5_pk_set_user_id(context
, NULL
, opt
->opt_private
->pk_init_ctx
, certs
);
2510 krb5_set_error_message(context
, EINVAL
,
2511 N_("no support for PKINIT compiled in", ""));
2519 get_ms_san(hx509_context context
, hx509_cert cert
, char **upn
)
2521 hx509_octet_string_list list
;
2526 ret
= hx509_cert_find_subjectAltName_otherName(context
,
2528 &asn1_oid_id_pkinit_ms_san
,
2533 if (list
.len
> 0 && list
.val
[0].length
> 0)
2534 ret
= decode_MS_UPN_SAN(list
.val
[0].data
, list
.val
[0].length
,
2538 hx509_free_octet_string_list(&list
);
2544 find_ms_san(hx509_context context
, hx509_cert cert
, void *ctx
)
2549 ret
= get_ms_san(context
, cert
, &upn
);
2560 * Private since it need to be redesigned using krb5_get_init_creds()
2563 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2564 krb5_pk_enterprise_cert(krb5_context context
,
2565 const char *user_id
,
2566 krb5_const_realm realm
,
2567 krb5_principal
*principal
,
2568 struct hx509_certs_data
**res
)
2571 krb5_error_code ret
;
2572 hx509_certs certs
, result
;
2573 hx509_cert cert
= NULL
;
2581 if (user_id
== NULL
) {
2582 krb5_set_error_message(context
, ENOENT
, "no user id");
2586 ret
= hx509_certs_init(context
->hx509ctx
, user_id
, 0, NULL
, &certs
);
2588 pk_copy_error(context
, context
->hx509ctx
, ret
,
2589 "Failed to init cert certs");
2593 ret
= hx509_query_alloc(context
->hx509ctx
, &q
);
2595 krb5_set_error_message(context
, ret
, "out of memory");
2596 hx509_certs_free(&certs
);
2600 hx509_query_match_option(q
, HX509_QUERY_OPTION_PRIVATE_KEY
);
2601 hx509_query_match_option(q
, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE
);
2602 hx509_query_match_eku(q
, &asn1_oid_id_pkinit_ms_eku
);
2603 hx509_query_match_cmp_func(q
, find_ms_san
, NULL
);
2605 ret
= hx509_certs_filter(context
->hx509ctx
, certs
, q
, &result
);
2606 hx509_query_free(context
->hx509ctx
, q
);
2607 hx509_certs_free(&certs
);
2609 pk_copy_error(context
, context
->hx509ctx
, ret
,
2610 "Failed to find PKINIT certificate");
2614 ret
= hx509_get_one_cert(context
->hx509ctx
, result
, &cert
);
2615 hx509_certs_free(&result
);
2617 pk_copy_error(context
, context
->hx509ctx
, ret
,
2618 "Failed to get one cert");
2622 ret
= get_ms_san(context
->hx509ctx
, cert
, &name
);
2624 pk_copy_error(context
, context
->hx509ctx
, ret
,
2625 "Failed to get MS SAN");
2629 ret
= krb5_make_principal(context
, principal
, realm
, name
, NULL
);
2634 krb5_principal_set_type(context
, *principal
, KRB5_NT_ENTERPRISE_PRINCIPAL
);
2637 ret
= hx509_certs_init(context
->hx509ctx
, "MEMORY:", 0, NULL
, res
);
2641 ret
= hx509_certs_add(context
->hx509ctx
, *res
, cert
);
2643 hx509_certs_free(res
);
2649 hx509_cert_free(cert
);
2653 krb5_set_error_message(context
, EINVAL
,
2654 N_("no support for PKINIT compiled in", ""));
2659 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
2660 _krb5_pk_is_kdc_verified(krb5_context context
,
2661 krb5_get_init_creds_opt
*opt
)
2664 opt
->opt_private
== NULL
||
2665 opt
->opt_private
->pk_init_ctx
== NULL
)
2668 return opt
->opt_private
->pk_init_ctx
->kdc_verified
;