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