1 /* $NetBSD: pkinit.c,v 1.1.1.2 2014/04/24 12:45:50 pettai Exp $ */
4 * Copyright (c) 2003 - 2007 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
8 * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the Institute nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 #include "krb5_locl.h"
40 struct krb5_dh_moduli
{
50 #include <krb5/cms_asn1.h>
51 #include <krb5/pkcs8_asn1.h>
52 #include <krb5/pkcs9_asn1.h>
53 #include <krb5/pkcs12_asn1.h>
54 #include <krb5/pkinit_asn1.h>
55 #include <krb5/asn1_err.h>
63 struct krb5_pk_init_ctx_data
{
64 struct krb5_pk_identity
*id
;
65 enum { USE_RSA
, USE_DH
, USE_ECDH
} keyex
;
72 krb5_data
*clientDHNonce
;
73 struct krb5_dh_moduli
**m
;
75 enum krb5_pk_type type
;
76 unsigned int require_binding
:1;
77 unsigned int require_eku
:1;
78 unsigned int require_krbtgt_otherName
:1;
79 unsigned int require_hostname_match
:1;
80 unsigned int trustedCertifiers
:1;
81 unsigned int anonymous
:1;
85 pk_copy_error(krb5_context context
,
86 hx509_context hx509ctx
,
90 __attribute__ ((format (printf
, 4, 5)));
96 KRB5_LIB_FUNCTION
void KRB5_LIB_CALL
97 _krb5_pk_cert_free(struct krb5_pk_cert
*cert
)
100 hx509_cert_free(cert
->cert
);
105 static krb5_error_code
106 BN_to_integer(krb5_context context
, BIGNUM
*bn
, heim_integer
*integer
)
108 integer
->length
= BN_num_bytes(bn
);
109 integer
->data
= malloc(integer
->length
);
110 if (integer
->data
== NULL
) {
111 krb5_clear_error_message(context
);
114 BN_bn2bin(bn
, integer
->data
);
115 integer
->negative
= BN_is_negative(bn
);
120 integer_to_BN(krb5_context context
, const char *field
, const heim_integer
*f
)
124 bn
= BN_bin2bn((const unsigned char *)f
->data
, f
->length
, NULL
);
126 krb5_set_error_message(context
, ENOMEM
,
127 N_("PKINIT: parsing BN failed %s", ""), field
);
130 BN_set_negative(bn
, f
->negative
);
134 static krb5_error_code
135 select_dh_group(krb5_context context
, DH
*dh
, unsigned long bits
,
136 struct krb5_dh_moduli
**moduli
)
138 const struct krb5_dh_moduli
*m
;
141 m
= moduli
[1]; /* XXX */
143 m
= moduli
[0]; /* XXX */
146 for (i
= 0; moduli
[i
] != NULL
; i
++) {
147 if (bits
< moduli
[i
]->bits
)
150 if (moduli
[i
] == NULL
) {
151 krb5_set_error_message(context
, EINVAL
,
152 N_("Did not find a DH group parameter "
153 "matching requirement of %lu bits", ""),
160 dh
->p
= integer_to_BN(context
, "p", &m
->p
);
163 dh
->g
= integer_to_BN(context
, "g", &m
->g
);
166 dh
->q
= integer_to_BN(context
, "q", &m
->q
);
179 * Try searchin the key by to use by first looking for for PK-INIT
180 * EKU, then the Microsoft smart card EKU and last, no special EKU at all.
183 static krb5_error_code
184 find_cert(krb5_context context
, struct krb5_pk_identity
*id
,
185 hx509_query
*q
, hx509_cert
*cert
)
187 struct certfind cf
[4] = {
193 int ret
= HX509_CERT_NOT_FOUND
;
195 unsigned oids
[] = { 1, 2, 840, 113635, 100, 3, 2, 1 };
196 const heim_oid mobileMe
= { sizeof(oids
)/sizeof(oids
[0]), oids
};
199 if (id
->flags
& PKINIT_BTMM
)
202 cf
[0].oid
= &mobileMe
;
203 cf
[1].oid
= &asn1_oid_id_pkekuoid
;
204 cf
[2].oid
= &asn1_oid_id_pkinit_ms_eku
;
207 for (i
= start
; i
< sizeof(cf
)/sizeof(cf
[0]); i
++) {
208 ret
= hx509_query_match_eku(q
, cf
[i
].oid
);
210 pk_copy_error(context
, context
->hx509ctx
, ret
,
211 "Failed setting %s OID", cf
[i
].type
);
215 ret
= hx509_certs_find(context
->hx509ctx
, id
->certs
, q
, cert
);
218 pk_copy_error(context
, context
->hx509ctx
, ret
,
219 "Failed finding certificate with %s OID", cf
[i
].type
);
225 static krb5_error_code
226 create_signature(krb5_context context
,
227 const heim_oid
*eContentType
,
229 struct krb5_pk_identity
*id
,
230 hx509_peer_info peer
,
235 if (id
->cert
== NULL
)
236 flags
|= HX509_CMS_SIGNATURE_NO_SIGNER
;
238 ret
= hx509_cms_create_signed_1(context
->hx509ctx
,
250 pk_copy_error(context
, context
->hx509ctx
, ret
,
251 "Create CMS signedData");
259 cert2epi(hx509_context context
, void *ctx
, hx509_cert c
)
261 ExternalPrincipalIdentifiers
*ids
= ctx
;
262 ExternalPrincipalIdentifier id
;
263 hx509_name subject
= NULL
;
270 memset(&id
, 0, sizeof(id
));
272 ret
= hx509_cert_get_subject(c
, &subject
);
276 if (hx509_name_is_null_p(subject
) != 0) {
278 id
.subjectName
= calloc(1, sizeof(*id
.subjectName
));
279 if (id
.subjectName
== NULL
) {
280 hx509_name_free(&subject
);
281 free_ExternalPrincipalIdentifier(&id
);
285 ret
= hx509_name_binary(subject
, id
.subjectName
);
287 hx509_name_free(&subject
);
288 free_ExternalPrincipalIdentifier(&id
);
292 hx509_name_free(&subject
);
295 id
.issuerAndSerialNumber
= calloc(1, sizeof(*id
.issuerAndSerialNumber
));
296 if (id
.issuerAndSerialNumber
== NULL
) {
297 free_ExternalPrincipalIdentifier(&id
);
302 IssuerAndSerialNumber iasn
;
306 memset(&iasn
, 0, sizeof(iasn
));
308 ret
= hx509_cert_get_issuer(c
, &issuer
);
310 free_ExternalPrincipalIdentifier(&id
);
314 ret
= hx509_name_to_Name(issuer
, &iasn
.issuer
);
315 hx509_name_free(&issuer
);
317 free_ExternalPrincipalIdentifier(&id
);
321 ret
= hx509_cert_get_serialnumber(c
, &iasn
.serialNumber
);
323 free_IssuerAndSerialNumber(&iasn
);
324 free_ExternalPrincipalIdentifier(&id
);
328 ASN1_MALLOC_ENCODE(IssuerAndSerialNumber
,
329 id
.issuerAndSerialNumber
->data
,
330 id
.issuerAndSerialNumber
->length
,
332 free_IssuerAndSerialNumber(&iasn
);
335 if (id
.issuerAndSerialNumber
->length
!= size
)
339 id
.subjectKeyIdentifier
= NULL
;
341 p
= realloc(ids
->val
, sizeof(ids
->val
[0]) * (ids
->len
+ 1));
343 free_ExternalPrincipalIdentifier(&id
);
348 ids
->val
[ids
->len
] = id
;
354 static krb5_error_code
355 build_edi(krb5_context context
,
356 hx509_context hx509ctx
,
358 ExternalPrincipalIdentifiers
*ids
)
360 return hx509_certs_iter_f(hx509ctx
, certs
, cert2epi
, ids
);
363 static krb5_error_code
364 build_auth_pack(krb5_context context
,
366 krb5_pk_init_ctx ctx
,
367 const KDC_REQ_BODY
*body
,
370 size_t buf_size
, len
= 0;
377 krb5_clear_error_message(context
);
379 memset(&checksum
, 0, sizeof(checksum
));
381 krb5_us_timeofday(context
, &sec
, &usec
);
382 a
->pkAuthenticator
.ctime
= sec
;
383 a
->pkAuthenticator
.nonce
= nonce
;
385 ASN1_MALLOC_ENCODE(KDC_REQ_BODY
, buf
, buf_size
, body
, &len
, ret
);
389 krb5_abortx(context
, "internal error in ASN.1 encoder");
391 ret
= krb5_create_checksum(context
,
402 ALLOC(a
->pkAuthenticator
.paChecksum
, 1);
403 if (a
->pkAuthenticator
.paChecksum
== NULL
) {
404 krb5_set_error_message(context
, ENOMEM
,
405 N_("malloc: out of memory", ""));
409 ret
= krb5_data_copy(a
->pkAuthenticator
.paChecksum
,
410 checksum
.checksum
.data
, checksum
.checksum
.length
);
411 free_Checksum(&checksum
);
415 if (ctx
->keyex
== USE_DH
|| ctx
->keyex
== USE_ECDH
) {
416 const char *moduli_file
;
417 unsigned long dh_min_bits
;
421 krb5_data_zero(&dhbuf
);
425 moduli_file
= krb5_config_get_string(context
, NULL
,
431 krb5_config_get_int_default(context
, NULL
, 0,
433 "pkinit_dh_min_bits",
436 ret
= _krb5_parse_moduli(context
, moduli_file
, &ctx
->m
);
440 ctx
->u
.dh
= DH_new();
441 if (ctx
->u
.dh
== NULL
) {
442 krb5_set_error_message(context
, ENOMEM
,
443 N_("malloc: out of memory", ""));
447 ret
= select_dh_group(context
, ctx
->u
.dh
, dh_min_bits
, ctx
->m
);
451 if (DH_generate_key(ctx
->u
.dh
) != 1) {
452 krb5_set_error_message(context
, ENOMEM
,
453 N_("pkinit: failed to generate DH key", ""));
458 if (1 /* support_cached_dh */) {
459 ALLOC(a
->clientDHNonce
, 1);
460 if (a
->clientDHNonce
== NULL
) {
461 krb5_clear_error_message(context
);
464 ret
= krb5_data_alloc(a
->clientDHNonce
, 40);
465 if (a
->clientDHNonce
== NULL
) {
466 krb5_clear_error_message(context
);
469 RAND_bytes(a
->clientDHNonce
->data
, a
->clientDHNonce
->length
);
470 ret
= krb5_copy_data(context
, a
->clientDHNonce
,
471 &ctx
->clientDHNonce
);
476 ALLOC(a
->clientPublicValue
, 1);
477 if (a
->clientPublicValue
== NULL
)
480 if (ctx
->keyex
== USE_DH
) {
483 heim_integer dh_pub_key
;
485 ret
= der_copy_oid(&asn1_oid_id_dhpublicnumber
,
486 &a
->clientPublicValue
->algorithm
.algorithm
);
490 memset(&dp
, 0, sizeof(dp
));
492 ret
= BN_to_integer(context
, dh
->p
, &dp
.p
);
494 free_DomainParameters(&dp
);
497 ret
= BN_to_integer(context
, dh
->g
, &dp
.g
);
499 free_DomainParameters(&dp
);
502 dp
.q
= calloc(1, sizeof(*dp
.q
));
504 free_DomainParameters(&dp
);
507 ret
= BN_to_integer(context
, dh
->q
, dp
.q
);
509 free_DomainParameters(&dp
);
513 dp
.validationParms
= NULL
;
515 a
->clientPublicValue
->algorithm
.parameters
=
516 malloc(sizeof(*a
->clientPublicValue
->algorithm
.parameters
));
517 if (a
->clientPublicValue
->algorithm
.parameters
== NULL
) {
518 free_DomainParameters(&dp
);
522 ASN1_MALLOC_ENCODE(DomainParameters
,
523 a
->clientPublicValue
->algorithm
.parameters
->data
,
524 a
->clientPublicValue
->algorithm
.parameters
->length
,
526 free_DomainParameters(&dp
);
529 if (size
!= a
->clientPublicValue
->algorithm
.parameters
->length
)
530 krb5_abortx(context
, "Internal ASN1 encoder error");
532 ret
= BN_to_integer(context
, dh
->pub_key
, &dh_pub_key
);
536 ASN1_MALLOC_ENCODE(DHPublicKey
, dhbuf
.data
, dhbuf
.length
,
537 &dh_pub_key
, &size
, ret
);
538 der_free_heim_integer(&dh_pub_key
);
541 if (size
!= dhbuf
.length
)
542 krb5_abortx(context
, "asn1 internal error");
543 } else if (ctx
->keyex
== USE_ECDH
) {
549 /* copy in public key, XXX find the best curve that the server support or use the clients curve if possible */
551 ecp
.element
= choice_ECParameters_namedCurve
;
552 ret
= der_copy_oid(&asn1_oid_id_ec_group_secp256r1
,
557 ALLOC(a
->clientPublicValue
->algorithm
.parameters
, 1);
558 if (a
->clientPublicValue
->algorithm
.parameters
== NULL
) {
559 free_ECParameters(&ecp
);
562 ASN1_MALLOC_ENCODE(ECParameters
, p
, xlen
, &ecp
, &size
, ret
);
563 free_ECParameters(&ecp
);
566 if ((int)size
!= xlen
)
567 krb5_abortx(context
, "asn1 internal error");
569 a
->clientPublicValue
->algorithm
.parameters
->data
= p
;
570 a
->clientPublicValue
->algorithm
.parameters
->length
= size
;
572 /* copy in public key */
574 ret
= der_copy_oid(&asn1_oid_id_ecPublicKey
,
575 &a
->clientPublicValue
->algorithm
.algorithm
);
579 ctx
->u
.eckey
= EC_KEY_new_by_curve_name(NID_X9_62_prime256v1
);
580 if (ctx
->u
.eckey
== NULL
)
583 ret
= EC_KEY_generate_key(ctx
->u
.eckey
);
587 /* encode onto dhkey */
589 xlen
= i2o_ECPublicKey(ctx
->u
.eckey
, NULL
);
593 dhbuf
.data
= malloc(xlen
);
594 if (dhbuf
.data
== NULL
)
599 xlen
= i2o_ECPublicKey(ctx
->u
.eckey
, &p
);
603 /* XXX verify that this is right with RFC3279 */
608 krb5_abortx(context
, "internal error");
609 a
->clientPublicValue
->subjectPublicKey
.length
= dhbuf
.length
* 8;
610 a
->clientPublicValue
->subjectPublicKey
.data
= dhbuf
.data
;
614 a
->supportedCMSTypes
= calloc(1, sizeof(*a
->supportedCMSTypes
));
615 if (a
->supportedCMSTypes
== NULL
)
618 ret
= hx509_crypto_available(context
->hx509ctx
, HX509_SELECT_ALL
,
620 &a
->supportedCMSTypes
->val
,
621 &a
->supportedCMSTypes
->len
);
629 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
630 _krb5_pk_mk_ContentInfo(krb5_context context
,
631 const krb5_data
*buf
,
633 struct ContentInfo
*content_info
)
637 ret
= der_copy_oid(oid
, &content_info
->contentType
);
640 ALLOC(content_info
->content
, 1);
641 if (content_info
->content
== NULL
)
643 content_info
->content
->data
= malloc(buf
->length
);
644 if (content_info
->content
->data
== NULL
)
646 memcpy(content_info
->content
->data
, buf
->data
, buf
->length
);
647 content_info
->content
->length
= buf
->length
;
651 static krb5_error_code
652 pk_mk_padata(krb5_context context
,
653 krb5_pk_init_ctx ctx
,
654 const KDC_REQ_BODY
*req_body
,
658 struct ContentInfo content_info
;
660 const heim_oid
*oid
= NULL
;
662 krb5_data buf
, sd_buf
;
665 krb5_data_zero(&buf
);
666 krb5_data_zero(&sd_buf
);
667 memset(&content_info
, 0, sizeof(content_info
));
669 if (ctx
->type
== PKINIT_WIN2K
) {
674 memset(&ap
, 0, sizeof(ap
));
676 /* fill in PKAuthenticator */
677 ret
= copy_PrincipalName(req_body
->sname
, &ap
.pkAuthenticator
.kdcName
);
679 free_AuthPack_Win2k(&ap
);
680 krb5_clear_error_message(context
);
683 ret
= copy_Realm(&req_body
->realm
, &ap
.pkAuthenticator
.kdcRealm
);
685 free_AuthPack_Win2k(&ap
);
686 krb5_clear_error_message(context
);
690 krb5_us_timeofday(context
, &sec
, &usec
);
691 ap
.pkAuthenticator
.ctime
= sec
;
692 ap
.pkAuthenticator
.cusec
= usec
;
693 ap
.pkAuthenticator
.nonce
= nonce
;
695 ASN1_MALLOC_ENCODE(AuthPack_Win2k
, buf
.data
, buf
.length
,
697 free_AuthPack_Win2k(&ap
);
699 krb5_set_error_message(context
, ret
,
700 N_("Failed encoding AuthPackWin: %d", ""),
704 if (buf
.length
!= size
)
705 krb5_abortx(context
, "internal ASN1 encoder error");
707 oid
= &asn1_oid_id_pkcs7_data
;
708 } else if (ctx
->type
== PKINIT_27
) {
711 memset(&ap
, 0, sizeof(ap
));
713 ret
= build_auth_pack(context
, nonce
, ctx
, req_body
, &ap
);
719 ASN1_MALLOC_ENCODE(AuthPack
, buf
.data
, buf
.length
, &ap
, &size
, ret
);
722 krb5_set_error_message(context
, ret
,
723 N_("Failed encoding AuthPack: %d", ""),
727 if (buf
.length
!= size
)
728 krb5_abortx(context
, "internal ASN1 encoder error");
730 oid
= &asn1_oid_id_pkauthdata
;
732 krb5_abortx(context
, "internal pkinit error");
734 ret
= create_signature(context
, oid
, &buf
, ctx
->id
,
736 krb5_data_free(&buf
);
740 ret
= hx509_cms_wrap_ContentInfo(&asn1_oid_id_pkcs7_signedData
, &sd_buf
, &buf
);
741 krb5_data_free(&sd_buf
);
743 krb5_set_error_message(context
, ret
,
744 N_("ContentInfo wrapping of signedData failed",""));
748 if (ctx
->type
== PKINIT_WIN2K
) {
749 PA_PK_AS_REQ_Win2k winreq
;
751 pa_type
= KRB5_PADATA_PK_AS_REQ_WIN
;
753 memset(&winreq
, 0, sizeof(winreq
));
755 winreq
.signed_auth_pack
= buf
;
757 ASN1_MALLOC_ENCODE(PA_PK_AS_REQ_Win2k
, buf
.data
, buf
.length
,
758 &winreq
, &size
, ret
);
759 free_PA_PK_AS_REQ_Win2k(&winreq
);
761 } else if (ctx
->type
== PKINIT_27
) {
764 pa_type
= KRB5_PADATA_PK_AS_REQ
;
766 memset(&req
, 0, sizeof(req
));
767 req
.signedAuthPack
= buf
;
769 if (ctx
->trustedCertifiers
) {
771 req
.trustedCertifiers
= calloc(1, sizeof(*req
.trustedCertifiers
));
772 if (req
.trustedCertifiers
== NULL
) {
774 krb5_set_error_message(context
, ret
,
775 N_("malloc: out of memory", ""));
776 free_PA_PK_AS_REQ(&req
);
779 ret
= build_edi(context
, context
->hx509ctx
,
780 ctx
->id
->anchors
, req
.trustedCertifiers
);
782 krb5_set_error_message(context
, ret
,
783 N_("pk-init: failed to build "
784 "trustedCertifiers", ""));
785 free_PA_PK_AS_REQ(&req
);
791 ASN1_MALLOC_ENCODE(PA_PK_AS_REQ
, buf
.data
, buf
.length
,
794 free_PA_PK_AS_REQ(&req
);
797 krb5_abortx(context
, "internal pkinit error");
799 krb5_set_error_message(context
, ret
, "PA-PK-AS-REQ %d", (int)ret
);
802 if (buf
.length
!= size
)
803 krb5_abortx(context
, "Internal ASN1 encoder error");
805 ret
= krb5_padata_add(context
, md
, pa_type
, buf
.data
, buf
.length
);
810 krb5_padata_add(context
, md
, KRB5_PADATA_PK_AS_09_BINDING
, NULL
, 0);
813 free_ContentInfo(&content_info
);
819 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
820 _krb5_pk_mk_padata(krb5_context context
,
824 const KDC_REQ_BODY
*req_body
,
828 krb5_pk_init_ctx ctx
= c
;
831 if (ctx
->id
->certs
== NULL
&& ctx
->anonymous
== 0) {
832 krb5_set_error_message(context
, HEIM_PKINIT_NO_PRIVATE_KEY
,
833 N_("PKINIT: No user certificate given", ""));
834 return HEIM_PKINIT_NO_PRIVATE_KEY
;
837 win2k_compat
= krb5_config_get_bool_default(context
, NULL
,
845 ctx
->require_binding
=
846 krb5_config_get_bool_default(context
, NULL
,
850 "pkinit_win2k_require_binding",
852 ctx
->type
= PKINIT_WIN2K
;
854 ctx
->type
= PKINIT_27
;
857 krb5_config_get_bool_default(context
, NULL
,
861 "pkinit_require_eku",
863 if (ic_flags
& KRB5_INIT_CREDS_NO_C_NO_EKU_CHECK
)
864 ctx
->require_eku
= 0;
865 if (ctx
->id
->flags
& PKINIT_BTMM
)
866 ctx
->require_eku
= 0;
868 ctx
->require_krbtgt_otherName
=
869 krb5_config_get_bool_default(context
, NULL
,
873 "pkinit_require_krbtgt_otherName",
876 ctx
->require_hostname_match
=
877 krb5_config_get_bool_default(context
, NULL
,
881 "pkinit_require_hostname_match",
884 ctx
->trustedCertifiers
=
885 krb5_config_get_bool_default(context
, NULL
,
889 "pkinit_trustedCertifiers",
892 return pk_mk_padata(context
, ctx
, req_body
, nonce
, md
);
895 static krb5_error_code
896 pk_verify_sign(krb5_context context
,
899 struct krb5_pk_identity
*id
,
900 heim_oid
*contentType
,
902 struct krb5_pk_cert
**signer
)
904 hx509_certs signer_certs
;
907 /* BTMM is broken in Leo and SnowLeo */
908 if (id
->flags
& PKINIT_BTMM
) {
909 flags
|= HX509_CMS_VS_ALLOW_DATA_OID_MISMATCH
;
910 flags
|= HX509_CMS_VS_NO_KU_CHECK
;
911 flags
|= HX509_CMS_VS_NO_VALIDATE
;
916 ret
= hx509_cms_verify_signed(context
->hx509ctx
,
927 pk_copy_error(context
, context
->hx509ctx
, ret
,
928 "CMS verify signed failed");
932 *signer
= calloc(1, sizeof(**signer
));
933 if (*signer
== NULL
) {
934 krb5_clear_error_message(context
);
939 ret
= hx509_get_one_cert(context
->hx509ctx
, signer_certs
, &(*signer
)->cert
);
941 pk_copy_error(context
, context
->hx509ctx
, ret
,
942 "Failed to get on of the signer certs");
947 hx509_certs_free(&signer_certs
);
950 hx509_cert_free((*signer
)->cert
);
959 static krb5_error_code
960 get_reply_key_win(krb5_context context
,
961 const krb5_data
*content
,
965 ReplyKeyPack_Win2k key_pack
;
969 ret
= decode_ReplyKeyPack_Win2k(content
->data
,
974 krb5_set_error_message(context
, ret
,
975 N_("PKINIT decoding reply key failed", ""));
976 free_ReplyKeyPack_Win2k(&key_pack
);
980 if ((unsigned)key_pack
.nonce
!= nonce
) {
981 krb5_set_error_message(context
, ret
,
982 N_("PKINIT enckey nonce is wrong", ""));
983 free_ReplyKeyPack_Win2k(&key_pack
);
984 return KRB5KRB_AP_ERR_MODIFIED
;
987 *key
= malloc (sizeof (**key
));
989 free_ReplyKeyPack_Win2k(&key_pack
);
990 krb5_set_error_message(context
, ENOMEM
,
991 N_("malloc: out of memory", ""));
995 ret
= copy_EncryptionKey(&key_pack
.replyKey
, *key
);
996 free_ReplyKeyPack_Win2k(&key_pack
);
998 krb5_set_error_message(context
, ret
,
999 N_("PKINIT failed copying reply key", ""));
1007 static krb5_error_code
1008 get_reply_key(krb5_context context
,
1009 const krb5_data
*content
,
1010 const krb5_data
*req_buffer
,
1011 krb5_keyblock
**key
)
1013 ReplyKeyPack key_pack
;
1014 krb5_error_code ret
;
1017 ret
= decode_ReplyKeyPack(content
->data
,
1022 krb5_set_error_message(context
, ret
,
1023 N_("PKINIT decoding reply key failed", ""));
1024 free_ReplyKeyPack(&key_pack
);
1032 * XXX Verify kp.replyKey is a allowed enctype in the
1033 * configuration file
1036 ret
= krb5_crypto_init(context
, &key_pack
.replyKey
, 0, &crypto
);
1038 free_ReplyKeyPack(&key_pack
);
1042 ret
= krb5_verify_checksum(context
, crypto
, 6,
1043 req_buffer
->data
, req_buffer
->length
,
1044 &key_pack
.asChecksum
);
1045 krb5_crypto_destroy(context
, crypto
);
1047 free_ReplyKeyPack(&key_pack
);
1052 *key
= malloc (sizeof (**key
));
1054 free_ReplyKeyPack(&key_pack
);
1055 krb5_set_error_message(context
, ENOMEM
,
1056 N_("malloc: out of memory", ""));
1060 ret
= copy_EncryptionKey(&key_pack
.replyKey
, *key
);
1061 free_ReplyKeyPack(&key_pack
);
1063 krb5_set_error_message(context
, ret
,
1064 N_("PKINIT failed copying reply key", ""));
1073 static krb5_error_code
1074 pk_verify_host(krb5_context context
,
1076 const krb5_krbhst_info
*hi
,
1077 struct krb5_pk_init_ctx_data
*ctx
,
1078 struct krb5_pk_cert
*host
)
1080 krb5_error_code ret
= 0;
1082 if (ctx
->require_eku
) {
1083 ret
= hx509_cert_check_eku(context
->hx509ctx
, host
->cert
,
1084 &asn1_oid_id_pkkdcekuoid
, 0);
1086 krb5_set_error_message(context
, ret
,
1087 N_("No PK-INIT KDC EKU in kdc certificate", ""));
1091 if (ctx
->require_krbtgt_otherName
) {
1092 hx509_octet_string_list list
;
1095 ret
= hx509_cert_find_subjectAltName_otherName(context
->hx509ctx
,
1097 &asn1_oid_id_pkinit_san
,
1100 krb5_set_error_message(context
, ret
,
1101 N_("Failed to find the PK-INIT "
1102 "subjectAltName in the KDC "
1103 "certificate", ""));
1108 for (i
= 0; i
< list
.len
; i
++) {
1109 KRB5PrincipalName r
;
1111 ret
= decode_KRB5PrincipalName(list
.val
[i
].data
,
1116 krb5_set_error_message(context
, ret
,
1117 N_("Failed to decode the PK-INIT "
1118 "subjectAltName in the "
1119 "KDC certificate", ""));
1124 if (r
.principalName
.name_string
.len
!= 2 ||
1125 strcmp(r
.principalName
.name_string
.val
[0], KRB5_TGS_NAME
) != 0 ||
1126 strcmp(r
.principalName
.name_string
.val
[1], realm
) != 0 ||
1127 strcmp(r
.realm
, realm
) != 0)
1129 ret
= KRB5_KDC_ERR_INVALID_CERTIFICATE
;
1130 krb5_set_error_message(context
, ret
,
1131 N_("KDC have wrong realm name in "
1132 "the certificate", ""));
1135 free_KRB5PrincipalName(&r
);
1139 hx509_free_octet_string_list(&list
);
1145 ret
= hx509_verify_hostname(context
->hx509ctx
, host
->cert
,
1146 ctx
->require_hostname_match
,
1149 hi
->ai
->ai_addr
, hi
->ai
->ai_addrlen
);
1152 krb5_set_error_message(context
, ret
,
1153 N_("Address mismatch in "
1154 "the KDC certificate", ""));
1159 static krb5_error_code
1160 pk_rd_pa_reply_enckey(krb5_context context
,
1162 const heim_octet_string
*indata
,
1163 const heim_oid
*dataType
,
1165 krb5_pk_init_ctx ctx
,
1167 const krb5_krbhst_info
*hi
,
1169 const krb5_data
*req_buffer
,
1171 krb5_keyblock
**key
)
1173 krb5_error_code ret
;
1174 struct krb5_pk_cert
*host
= NULL
;
1176 heim_oid contentType
= { 0, NULL
};
1177 int flags
= HX509_CMS_UE_DONT_REQUIRE_KU_ENCIPHERMENT
;
1179 if (der_heim_oid_cmp(&asn1_oid_id_pkcs7_envelopedData
, dataType
)) {
1180 krb5_set_error_message(context
, EINVAL
,
1181 N_("PKINIT: Invalid content type", ""));
1185 if (ctx
->type
== PKINIT_WIN2K
)
1186 flags
|= HX509_CMS_UE_ALLOW_WEAK
;
1188 ret
= hx509_cms_unenvelope(context
->hx509ctx
,
1198 pk_copy_error(context
, context
->hx509ctx
, ret
,
1199 "Failed to unenvelope CMS data in PK-INIT reply");
1202 der_free_oid(&contentType
);
1204 /* win2k uses ContentInfo */
1205 if (type
== PKINIT_WIN2K
) {
1207 heim_octet_string out
;
1209 ret
= hx509_cms_unwrap_ContentInfo(&content
, &type2
, &out
, NULL
);
1211 /* windows LH with interesting CMS packets */
1212 size_t ph
= 1 + der_length_len(content
.length
);
1213 unsigned char *ptr
= malloc(content
.length
+ ph
);
1216 memcpy(ptr
+ ph
, content
.data
, content
.length
);
1218 ret
= der_put_length_and_tag (ptr
+ ph
- 1, ph
, content
.length
,
1219 ASN1_C_UNIV
, CONS
, UT_Sequence
, &l
);
1224 content
.length
+= ph
;
1226 ret
= hx509_cms_unwrap_ContentInfo(&content
, &type2
, &out
, NULL
);
1230 if (der_heim_oid_cmp(&type2
, &asn1_oid_id_pkcs7_signedData
)) {
1231 ret
= EINVAL
; /* XXX */
1232 krb5_set_error_message(context
, ret
,
1233 N_("PKINIT: Invalid content type", ""));
1234 der_free_oid(&type2
);
1235 der_free_octet_string(&out
);
1238 der_free_oid(&type2
);
1239 krb5_data_free(&content
);
1240 ret
= krb5_data_copy(&content
, out
.data
, out
.length
);
1241 der_free_octet_string(&out
);
1243 krb5_set_error_message(context
, ret
,
1244 N_("malloc: out of memory", ""));
1249 ret
= pk_verify_sign(context
,
1259 /* make sure that it is the kdc's certificate */
1260 ret
= pk_verify_host(context
, realm
, hi
, ctx
, host
);
1266 if (type
== PKINIT_WIN2K
) {
1267 if (der_heim_oid_cmp(&contentType
, &asn1_oid_id_pkcs7_data
) != 0) {
1268 ret
= KRB5KRB_AP_ERR_MSG_TYPE
;
1269 krb5_set_error_message(context
, ret
, "PKINIT: reply key, wrong oid");
1273 if (der_heim_oid_cmp(&contentType
, &asn1_oid_id_pkrkeydata
) != 0) {
1274 ret
= KRB5KRB_AP_ERR_MSG_TYPE
;
1275 krb5_set_error_message(context
, ret
, "PKINIT: reply key, wrong oid");
1283 ret
= get_reply_key(context
, &content
, req_buffer
, key
);
1284 if (ret
!= 0 && ctx
->require_binding
== 0)
1285 ret
= get_reply_key_win(context
, &content
, nonce
, key
);
1288 ret
= get_reply_key(context
, &content
, req_buffer
, key
);
1294 /* XXX compare given etype with key->etype */
1298 _krb5_pk_cert_free(host
);
1299 der_free_oid(&contentType
);
1300 krb5_data_free(&content
);
1305 static krb5_error_code
1306 pk_rd_pa_reply_dh(krb5_context context
,
1307 const heim_octet_string
*indata
,
1308 const heim_oid
*dataType
,
1310 krb5_pk_init_ctx ctx
,
1312 const krb5_krbhst_info
*hi
,
1317 krb5_keyblock
**key
)
1319 const unsigned char *p
;
1320 unsigned char *dh_gen_key
= NULL
;
1321 struct krb5_pk_cert
*host
= NULL
;
1322 BIGNUM
*kdc_dh_pubkey
= NULL
;
1323 KDCDHKeyInfo kdc_dh_info
;
1324 heim_oid contentType
= { 0, NULL
};
1326 krb5_error_code ret
;
1327 int dh_gen_keylen
= 0;
1330 krb5_data_zero(&content
);
1331 memset(&kdc_dh_info
, 0, sizeof(kdc_dh_info
));
1333 if (der_heim_oid_cmp(&asn1_oid_id_pkcs7_signedData
, dataType
)) {
1334 krb5_set_error_message(context
, EINVAL
,
1335 N_("PKINIT: Invalid content type", ""));
1339 ret
= pk_verify_sign(context
,
1349 /* make sure that it is the kdc's certificate */
1350 ret
= pk_verify_host(context
, realm
, hi
, ctx
, host
);
1354 if (der_heim_oid_cmp(&contentType
, &asn1_oid_id_pkdhkeydata
)) {
1355 ret
= KRB5KRB_AP_ERR_MSG_TYPE
;
1356 krb5_set_error_message(context
, ret
,
1357 N_("pkinit - dh reply contains wrong oid", ""));
1361 ret
= decode_KDCDHKeyInfo(content
.data
,
1367 krb5_set_error_message(context
, ret
,
1368 N_("pkinit - failed to decode "
1369 "KDC DH Key Info", ""));
1373 if (kdc_dh_info
.nonce
!= nonce
) {
1374 ret
= KRB5KRB_AP_ERR_MODIFIED
;
1375 krb5_set_error_message(context
, ret
,
1376 N_("PKINIT: DH nonce is wrong", ""));
1380 if (kdc_dh_info
.dhKeyExpiration
) {
1382 ret
= KRB5KRB_ERR_GENERIC
;
1383 krb5_set_error_message(context
, ret
,
1384 N_("pkinit; got key expiration "
1385 "without server nonce", ""));
1389 ret
= KRB5KRB_ERR_GENERIC
;
1390 krb5_set_error_message(context
, ret
,
1391 N_("pkinit; got DH reuse but no "
1392 "client nonce", ""));
1397 ret
= KRB5KRB_ERR_GENERIC
;
1398 krb5_set_error_message(context
, ret
,
1399 N_("pkinit: got server nonce "
1400 "without key expiration", ""));
1407 p
= kdc_dh_info
.subjectPublicKey
.data
;
1408 size
= (kdc_dh_info
.subjectPublicKey
.length
+ 7) / 8;
1410 if (ctx
->keyex
== USE_DH
) {
1412 ret
= decode_DHPublicKey(p
, size
, &k
, NULL
);
1414 krb5_set_error_message(context
, ret
,
1415 N_("pkinit: can't decode "
1416 "without key expiration", ""));
1420 kdc_dh_pubkey
= integer_to_BN(context
, "DHPublicKey", &k
);
1421 free_DHPublicKey(&k
);
1422 if (kdc_dh_pubkey
== NULL
) {
1428 size
= DH_size(ctx
->u
.dh
);
1430 dh_gen_key
= malloc(size
);
1431 if (dh_gen_key
== NULL
) {
1433 krb5_set_error_message(context
, ret
, N_("malloc: out of memory", ""));
1437 dh_gen_keylen
= DH_compute_key(dh_gen_key
, kdc_dh_pubkey
, ctx
->u
.dh
);
1438 if (dh_gen_keylen
== -1) {
1439 ret
= KRB5KRB_ERR_GENERIC
;
1441 krb5_set_error_message(context
, ret
,
1442 N_("PKINIT: Can't compute Diffie-Hellman key", ""));
1445 if (dh_gen_keylen
< (int)size
) {
1446 size
-= dh_gen_keylen
;
1447 memmove(dh_gen_key
+ size
, dh_gen_key
, dh_gen_keylen
);
1448 memset(dh_gen_key
, 0, size
);
1453 const EC_GROUP
*group
;
1454 EC_KEY
*public = NULL
;
1456 group
= EC_KEY_get0_group(ctx
->u
.eckey
);
1458 public = EC_KEY_new();
1459 if (public == NULL
) {
1463 if (EC_KEY_set_group(public, group
) != 1) {
1464 EC_KEY_free(public);
1469 if (o2i_ECPublicKey(&public, &p
, size
) == NULL
) {
1470 EC_KEY_free(public);
1471 ret
= KRB5KRB_ERR_GENERIC
;
1472 krb5_set_error_message(context
, ret
,
1473 N_("PKINIT: Can't parse ECDH public key", ""));
1477 size
= (EC_GROUP_get_degree(group
) + 7) / 8;
1478 dh_gen_key
= malloc(size
);
1479 if (dh_gen_key
== NULL
) {
1480 EC_KEY_free(public);
1482 krb5_set_error_message(context
, ret
,
1483 N_("malloc: out of memory", ""));
1486 dh_gen_keylen
= ECDH_compute_key(dh_gen_key
, size
,
1487 EC_KEY_get0_public_key(public), ctx
->u
.eckey
, NULL
);
1488 EC_KEY_free(public);
1489 if (dh_gen_keylen
== -1) {
1490 ret
= KRB5KRB_ERR_GENERIC
;
1492 krb5_set_error_message(context
, ret
,
1493 N_("PKINIT: Can't compute ECDH public key", ""));
1501 if (dh_gen_keylen
<= 0) {
1503 krb5_set_error_message(context
, ret
,
1504 N_("PKINIT: resulting DH key <= 0", ""));
1509 *key
= malloc (sizeof (**key
));
1512 krb5_set_error_message(context
, ret
,
1513 N_("malloc: out of memory", ""));
1517 ret
= _krb5_pk_octetstring2key(context
,
1519 dh_gen_key
, dh_gen_keylen
,
1523 krb5_set_error_message(context
, ret
,
1524 N_("PKINIT: can't create key from DH key", ""));
1532 BN_free(kdc_dh_pubkey
);
1534 memset(dh_gen_key
, 0, dh_gen_keylen
);
1538 _krb5_pk_cert_free(host
);
1540 krb5_data_free(&content
);
1541 der_free_oid(&contentType
);
1542 free_KDCDHKeyInfo(&kdc_dh_info
);
1547 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1548 _krb5_pk_rd_pa_reply(krb5_context context
,
1552 const krb5_krbhst_info
*hi
,
1554 const krb5_data
*req_buffer
,
1556 krb5_keyblock
**key
)
1558 krb5_pk_init_ctx ctx
= c
;
1559 krb5_error_code ret
;
1562 /* Check for IETF PK-INIT first */
1563 if (ctx
->type
== PKINIT_27
) {
1565 heim_octet_string os
, data
;
1568 if (pa
->padata_type
!= KRB5_PADATA_PK_AS_REP
) {
1569 krb5_set_error_message(context
, EINVAL
,
1570 N_("PKINIT: wrong padata recv", ""));
1574 ret
= decode_PA_PK_AS_REP(pa
->padata_value
.data
,
1575 pa
->padata_value
.length
,
1579 krb5_set_error_message(context
, ret
,
1580 N_("Failed to decode pkinit AS rep", ""));
1584 switch (rep
.element
) {
1585 case choice_PA_PK_AS_REP_dhInfo
:
1586 _krb5_debug(context
, 5, "krb5_get_init_creds: using pkinit dh");
1587 os
= rep
.u
.dhInfo
.dhSignedData
;
1589 case choice_PA_PK_AS_REP_encKeyPack
:
1590 _krb5_debug(context
, 5, "krb5_get_init_creds: using kinit enc reply key");
1591 os
= rep
.u
.encKeyPack
;
1594 PA_PK_AS_REP_BTMM btmm
;
1595 free_PA_PK_AS_REP(&rep
);
1596 memset(&rep
, 0, sizeof(rep
));
1598 _krb5_debug(context
, 5, "krb5_get_init_creds: using BTMM kinit enc reply key");
1600 ret
= decode_PA_PK_AS_REP_BTMM(pa
->padata_value
.data
,
1601 pa
->padata_value
.length
,
1605 krb5_set_error_message(context
, EINVAL
,
1606 N_("PKINIT: -27 reply "
1607 "invalid content type", ""));
1611 if (btmm
.dhSignedData
|| btmm
.encKeyPack
== NULL
) {
1612 free_PA_PK_AS_REP_BTMM(&btmm
);
1614 krb5_set_error_message(context
, ret
,
1615 N_("DH mode not supported for BTMM mode", ""));
1620 * Transform to IETF style PK-INIT reply so that free works below
1623 rep
.element
= choice_PA_PK_AS_REP_encKeyPack
;
1624 rep
.u
.encKeyPack
.data
= btmm
.encKeyPack
->data
;
1625 rep
.u
.encKeyPack
.length
= btmm
.encKeyPack
->length
;
1626 btmm
.encKeyPack
->data
= NULL
;
1627 btmm
.encKeyPack
->length
= 0;
1628 free_PA_PK_AS_REP_BTMM(&btmm
);
1629 os
= rep
.u
.encKeyPack
;
1633 ret
= hx509_cms_unwrap_ContentInfo(&os
, &oid
, &data
, NULL
);
1635 free_PA_PK_AS_REP(&rep
);
1636 krb5_set_error_message(context
, ret
,
1637 N_("PKINIT: failed to unwrap CI", ""));
1641 switch (rep
.element
) {
1642 case choice_PA_PK_AS_REP_dhInfo
:
1643 ret
= pk_rd_pa_reply_dh(context
, &data
, &oid
, realm
, ctx
, etype
, hi
,
1645 rep
.u
.dhInfo
.serverDHNonce
,
1648 case choice_PA_PK_AS_REP_encKeyPack
:
1649 ret
= pk_rd_pa_reply_enckey(context
, PKINIT_27
, &data
, &oid
, realm
,
1650 ctx
, etype
, hi
, nonce
, req_buffer
, pa
, key
);
1653 krb5_abortx(context
, "pk-init as-rep case not possible to happen");
1655 der_free_octet_string(&data
);
1657 free_PA_PK_AS_REP(&rep
);
1659 } else if (ctx
->type
== PKINIT_WIN2K
) {
1660 PA_PK_AS_REP_Win2k w2krep
;
1662 /* Check for Windows encoding of the AS-REP pa data */
1664 #if 0 /* should this be ? */
1665 if (pa
->padata_type
!= KRB5_PADATA_PK_AS_REP
) {
1666 krb5_set_error_message(context
, EINVAL
,
1667 "PKINIT: wrong padata recv");
1672 memset(&w2krep
, 0, sizeof(w2krep
));
1674 ret
= decode_PA_PK_AS_REP_Win2k(pa
->padata_value
.data
,
1675 pa
->padata_value
.length
,
1679 krb5_set_error_message(context
, ret
,
1680 N_("PKINIT: Failed decoding windows "
1681 "pkinit reply %d", ""), (int)ret
);
1685 krb5_clear_error_message(context
);
1687 switch (w2krep
.element
) {
1688 case choice_PA_PK_AS_REP_Win2k_encKeyPack
: {
1689 heim_octet_string data
;
1692 ret
= hx509_cms_unwrap_ContentInfo(&w2krep
.u
.encKeyPack
,
1694 free_PA_PK_AS_REP_Win2k(&w2krep
);
1696 krb5_set_error_message(context
, ret
,
1697 N_("PKINIT: failed to unwrap CI", ""));
1701 ret
= pk_rd_pa_reply_enckey(context
, PKINIT_WIN2K
, &data
, &oid
, realm
,
1702 ctx
, etype
, hi
, nonce
, req_buffer
, pa
, key
);
1703 der_free_octet_string(&data
);
1709 free_PA_PK_AS_REP_Win2k(&w2krep
);
1711 krb5_set_error_message(context
, ret
,
1712 N_("PKINIT: win2k reply invalid "
1713 "content type", ""));
1719 krb5_set_error_message(context
, ret
,
1720 N_("PKINIT: unknown reply type", ""));
1727 krb5_context context
;
1728 krb5_prompter_fct prompter
;
1729 void *prompter_data
;
1733 hx_pass_prompter(void *data
, const hx509_prompt
*prompter
)
1735 krb5_error_code ret
;
1737 krb5_data password_data
;
1738 struct prompter
*p
= data
;
1740 password_data
.data
= prompter
->reply
.data
;
1741 password_data
.length
= prompter
->reply
.length
;
1743 prompt
.prompt
= prompter
->prompt
;
1744 prompt
.hidden
= hx509_prompt_hidden(prompter
->type
);
1745 prompt
.reply
= &password_data
;
1747 switch (prompter
->type
) {
1748 case HX509_PROMPT_TYPE_INFO
:
1749 prompt
.type
= KRB5_PROMPT_TYPE_INFO
;
1751 case HX509_PROMPT_TYPE_PASSWORD
:
1752 case HX509_PROMPT_TYPE_QUESTION
:
1754 prompt
.type
= KRB5_PROMPT_TYPE_PASSWORD
;
1758 ret
= (*p
->prompter
)(p
->context
, p
->prompter_data
, NULL
, NULL
, 1, &prompt
);
1760 memset (prompter
->reply
.data
, 0, prompter
->reply
.length
);
1766 static krb5_error_code
1767 _krb5_pk_set_user_id(krb5_context context
,
1768 krb5_principal principal
,
1769 krb5_pk_init_ctx ctx
,
1770 struct hx509_certs_data
*certs
)
1772 hx509_certs c
= hx509_certs_ref(certs
);
1773 hx509_query
*q
= NULL
;
1777 hx509_certs_free(&ctx
->id
->certs
);
1778 if (ctx
->id
->cert
) {
1779 hx509_cert_free(ctx
->id
->cert
);
1780 ctx
->id
->cert
= NULL
;
1786 ret
= hx509_query_alloc(context
->hx509ctx
, &q
);
1788 pk_copy_error(context
, context
->hx509ctx
, ret
,
1789 "Allocate query to find signing certificate");
1793 hx509_query_match_option(q
, HX509_QUERY_OPTION_PRIVATE_KEY
);
1794 hx509_query_match_option(q
, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE
);
1796 if (principal
&& strncmp("LKDC:SHA1.", krb5_principal_get_realm(context
, principal
), 9) == 0) {
1797 ctx
->id
->flags
|= PKINIT_BTMM
;
1800 ret
= find_cert(context
, ctx
->id
, q
, &ctx
->id
->cert
);
1801 hx509_query_free(context
->hx509ctx
, q
);
1803 if (ret
== 0 && _krb5_have_debug(context
, 2)) {
1808 ret
= hx509_cert_get_subject(ctx
->id
->cert
, &name
);
1812 ret
= hx509_name_to_string(name
, &str
);
1813 hx509_name_free(&name
);
1817 ret
= hx509_cert_get_serialnumber(ctx
->id
->cert
, &i
);
1823 ret
= der_print_hex_heim_integer(&i
, &sn
);
1824 der_free_heim_integer(&i
);
1830 _krb5_debug(context
, 2, "using cert: subject: %s sn: %s", str
, sn
);
1839 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1840 _krb5_pk_load_id(krb5_context context
,
1841 struct krb5_pk_identity
**ret_id
,
1842 const char *user_id
,
1843 const char *anchor_id
,
1844 char * const *chain_list
,
1845 char * const *revoke_list
,
1846 krb5_prompter_fct prompter
,
1847 void *prompter_data
,
1850 struct krb5_pk_identity
*id
= NULL
;
1856 if (anchor_id
== NULL
) {
1857 krb5_set_error_message(context
, HEIM_PKINIT_NO_VALID_CA
,
1858 N_("PKINIT: No anchor given", ""));
1859 return HEIM_PKINIT_NO_VALID_CA
;
1864 id
= calloc(1, sizeof(*id
));
1866 krb5_set_error_message(context
, ENOMEM
,
1867 N_("malloc: out of memory", ""));
1874 ret
= hx509_lock_init(context
->hx509ctx
, &lock
);
1876 pk_copy_error(context
, context
->hx509ctx
, ret
, "Failed init lock");
1880 if (password
&& password
[0])
1881 hx509_lock_add_password(lock
, password
);
1884 p
.context
= context
;
1885 p
.prompter
= prompter
;
1886 p
.prompter_data
= prompter_data
;
1888 ret
= hx509_lock_set_prompter(lock
, hx_pass_prompter
, &p
);
1890 hx509_lock_free(lock
);
1895 ret
= hx509_certs_init(context
->hx509ctx
, user_id
, 0, lock
, &id
->certs
);
1896 hx509_lock_free(lock
);
1898 pk_copy_error(context
, context
->hx509ctx
, ret
,
1899 "Failed to init cert certs");
1906 ret
= hx509_certs_init(context
->hx509ctx
, anchor_id
, 0, NULL
, &id
->anchors
);
1908 pk_copy_error(context
, context
->hx509ctx
, ret
,
1909 "Failed to init anchors");
1913 ret
= hx509_certs_init(context
->hx509ctx
, "MEMORY:pkinit-cert-chain",
1914 0, NULL
, &id
->certpool
);
1916 pk_copy_error(context
, context
->hx509ctx
, ret
,
1917 "Failed to init chain");
1921 while (chain_list
&& *chain_list
) {
1922 ret
= hx509_certs_append(context
->hx509ctx
, id
->certpool
,
1925 pk_copy_error(context
, context
->hx509ctx
, ret
,
1926 "Failed to laod chain %s",
1934 ret
= hx509_revoke_init(context
->hx509ctx
, &id
->revokectx
);
1936 pk_copy_error(context
, context
->hx509ctx
, ret
,
1937 "Failed init revoke list");
1941 while (*revoke_list
) {
1942 ret
= hx509_revoke_add_crl(context
->hx509ctx
,
1946 pk_copy_error(context
, context
->hx509ctx
, ret
,
1947 "Failed load revoke list");
1953 hx509_context_set_missing_revoke(context
->hx509ctx
, 1);
1955 ret
= hx509_verify_init_ctx(context
->hx509ctx
, &id
->verify_ctx
);
1957 pk_copy_error(context
, context
->hx509ctx
, ret
,
1958 "Failed init verify context");
1962 hx509_verify_attach_anchors(id
->verify_ctx
, id
->anchors
);
1963 hx509_verify_attach_revoke(id
->verify_ctx
, id
->revokectx
);
1967 hx509_verify_destroy_ctx(id
->verify_ctx
);
1968 hx509_certs_free(&id
->certs
);
1969 hx509_certs_free(&id
->anchors
);
1970 hx509_certs_free(&id
->certpool
);
1971 hx509_revoke_free(&id
->revokectx
);
1984 pk_copy_error(krb5_context context
,
1985 hx509_context hx509ctx
,
1995 ret
= vasprintf(&f
, fmt
, va
);
1997 if (ret
== -1 || f
== NULL
) {
1998 krb5_clear_error_message(context
);
2002 s
= hx509_get_error_string(hx509ctx
, hxret
);
2004 krb5_clear_error_message(context
);
2008 krb5_set_error_message(context
, hxret
, "%s: %s", f
, s
);
2014 parse_integer(krb5_context context
, char **p
, const char *file
, int lineno
,
2015 const char *name
, heim_integer
*integer
)
2019 p1
= strsep(p
, " \t");
2021 krb5_set_error_message(context
, EINVAL
,
2022 N_("moduli file %s missing %s on line %d", ""),
2023 file
, name
, lineno
);
2026 ret
= der_parse_hex_heim_integer(p1
, integer
);
2028 krb5_set_error_message(context
, ret
,
2029 N_("moduli file %s failed parsing %s "
2031 file
, name
, lineno
);
2039 _krb5_parse_moduli_line(krb5_context context
,
2043 struct krb5_dh_moduli
**m
)
2045 struct krb5_dh_moduli
*m1
;
2051 m1
= calloc(1, sizeof(*m1
));
2053 krb5_set_error_message(context
, ENOMEM
,
2054 N_("malloc: out of memory", ""));
2058 while (isspace((unsigned char)*p
))
2066 p1
= strsep(&p
, " \t");
2068 krb5_set_error_message(context
, ret
,
2069 N_("moduli file %s missing name on line %d", ""),
2073 m1
->name
= strdup(p1
);
2074 if (m1
->name
== NULL
) {
2076 krb5_set_error_message(context
, ret
, N_("malloc: out of memeory", ""));
2080 p1
= strsep(&p
, " \t");
2082 krb5_set_error_message(context
, ret
,
2083 N_("moduli file %s missing bits on line %d", ""),
2088 m1
->bits
= atoi(p1
);
2089 if (m1
->bits
== 0) {
2090 krb5_set_error_message(context
, ret
,
2091 N_("moduli file %s have un-parsable "
2092 "bits on line %d", ""), file
, lineno
);
2096 ret
= parse_integer(context
, &p
, file
, lineno
, "p", &m1
->p
);
2099 ret
= parse_integer(context
, &p
, file
, lineno
, "g", &m1
->g
);
2102 ret
= parse_integer(context
, &p
, file
, lineno
, "q", &m1
->q
);
2111 der_free_heim_integer(&m1
->p
);
2112 der_free_heim_integer(&m1
->g
);
2113 der_free_heim_integer(&m1
->q
);
2119 _krb5_free_moduli(struct krb5_dh_moduli
**moduli
)
2122 for (i
= 0; moduli
[i
] != NULL
; i
++) {
2123 free(moduli
[i
]->name
);
2124 der_free_heim_integer(&moduli
[i
]->p
);
2125 der_free_heim_integer(&moduli
[i
]->g
);
2126 der_free_heim_integer(&moduli
[i
]->q
);
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";
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 krb5_set_error_message(context
, ENOMEM
,
2202 N_("malloc: out of memory", ""));
2206 strlcpy(buf
, default_moduli_rfc3526_MODP_group14
, sizeof(buf
));
2207 ret
= _krb5_parse_moduli_line(context
, "builtin", 1, buf
, &m
[0]);
2209 _krb5_free_moduli(m
);
2214 strlcpy(buf
, default_moduli_RFC2412_MODP_group2
, sizeof(buf
));
2215 ret
= _krb5_parse_moduli_line(context
, "builtin", 1, buf
, &m
[1]);
2217 _krb5_free_moduli(m
);
2226 #ifdef KRB5_USE_PATH_TOKENS
2230 if (_krb5_expand_path_tokens(context
, file
, &exp_file
) == 0) {
2231 f
= fopen(exp_file
, "r");
2232 krb5_xfree(exp_file
);
2238 f
= fopen(file
, "r");
2247 while(fgets(buf
, sizeof(buf
), f
) != NULL
) {
2248 struct krb5_dh_moduli
*element
;
2250 buf
[strcspn(buf
, "\n")] = '\0';
2253 m2
= realloc(m
, (n
+ 2) * sizeof(m
[0]));
2255 _krb5_free_moduli(m
);
2256 krb5_set_error_message(context
, ENOMEM
,
2257 N_("malloc: out of memory", ""));
2264 ret
= _krb5_parse_moduli_line(context
, file
, lineno
, buf
, &element
);
2266 _krb5_free_moduli(m
);
2269 if (element
== NULL
)
2281 _krb5_dh_group_ok(krb5_context context
, unsigned long bits
,
2282 heim_integer
*p
, heim_integer
*g
, heim_integer
*q
,
2283 struct krb5_dh_moduli
**moduli
,
2291 for (i
= 0; moduli
[i
] != NULL
; i
++) {
2292 if (der_heim_integer_cmp(&moduli
[i
]->g
, g
) == 0 &&
2293 der_heim_integer_cmp(&moduli
[i
]->p
, p
) == 0 &&
2294 (q
== NULL
|| der_heim_integer_cmp(&moduli
[i
]->q
, q
) == 0))
2296 if (bits
&& bits
> moduli
[i
]->bits
) {
2297 krb5_set_error_message(context
,
2298 KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED
,
2299 N_("PKINIT: DH group parameter %s "
2300 "no accepted, not enough bits "
2303 return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED
;
2306 *name
= strdup(moduli
[i
]->name
);
2310 krb5_set_error_message(context
,
2311 KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED
,
2312 N_("PKINIT: DH group parameter no ok", ""));
2313 return KRB5_KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED
;
2317 KRB5_LIB_FUNCTION
void KRB5_LIB_CALL
2318 _krb5_get_init_creds_opt_free_pkinit(krb5_get_init_creds_opt
*opt
)
2321 krb5_pk_init_ctx ctx
;
2323 if (opt
->opt_private
== NULL
|| opt
->opt_private
->pk_init_ctx
== NULL
)
2325 ctx
= opt
->opt_private
->pk_init_ctx
;
2326 switch (ctx
->keyex
) {
2336 EC_KEY_free(ctx
->u
.eckey
);
2341 hx509_verify_destroy_ctx(ctx
->id
->verify_ctx
);
2342 hx509_certs_free(&ctx
->id
->certs
);
2343 hx509_cert_free(ctx
->id
->cert
);
2344 hx509_certs_free(&ctx
->id
->anchors
);
2345 hx509_certs_free(&ctx
->id
->certpool
);
2347 if (ctx
->clientDHNonce
) {
2348 krb5_free_data(NULL
, ctx
->clientDHNonce
);
2349 ctx
->clientDHNonce
= NULL
;
2352 _krb5_free_moduli(ctx
->m
);
2356 free(opt
->opt_private
->pk_init_ctx
);
2357 opt
->opt_private
->pk_init_ctx
= NULL
;
2361 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2362 krb5_get_init_creds_opt_set_pkinit(krb5_context context
,
2363 krb5_get_init_creds_opt
*opt
,
2364 krb5_principal principal
,
2365 const char *user_id
,
2366 const char *x509_anchors
,
2367 char * const * pool
,
2368 char * const * pki_revoke
,
2370 krb5_prompter_fct prompter
,
2371 void *prompter_data
,
2375 krb5_error_code ret
;
2376 char *anchors
= NULL
;
2378 if (opt
->opt_private
== NULL
) {
2379 krb5_set_error_message(context
, EINVAL
,
2380 N_("PKINIT: on non extendable opt", ""));
2384 opt
->opt_private
->pk_init_ctx
=
2385 calloc(1, sizeof(*opt
->opt_private
->pk_init_ctx
));
2386 if (opt
->opt_private
->pk_init_ctx
== NULL
) {
2387 krb5_set_error_message(context
, ENOMEM
,
2388 N_("malloc: out of memory", ""));
2391 opt
->opt_private
->pk_init_ctx
->require_binding
= 0;
2392 opt
->opt_private
->pk_init_ctx
->require_eku
= 1;
2393 opt
->opt_private
->pk_init_ctx
->require_krbtgt_otherName
= 1;
2394 opt
->opt_private
->pk_init_ctx
->peer
= NULL
;
2396 /* XXX implement krb5_appdefault_strings */
2398 pool
= krb5_config_get_strings(context
, NULL
,
2403 if (pki_revoke
== NULL
)
2404 pki_revoke
= krb5_config_get_strings(context
, NULL
,
2409 if (x509_anchors
== NULL
) {
2410 krb5_appdefault_string(context
, "kinit",
2411 krb5_principal_get_realm(context
, principal
),
2412 "pkinit_anchors", NULL
, &anchors
);
2413 x509_anchors
= anchors
;
2417 opt
->opt_private
->pk_init_ctx
->anonymous
= 1;
2419 ret
= _krb5_pk_load_id(context
,
2420 &opt
->opt_private
->pk_init_ctx
->id
,
2429 free(opt
->opt_private
->pk_init_ctx
);
2430 opt
->opt_private
->pk_init_ctx
= NULL
;
2434 if (opt
->opt_private
->pk_init_ctx
->id
->certs
) {
2435 _krb5_pk_set_user_id(context
,
2437 opt
->opt_private
->pk_init_ctx
,
2438 opt
->opt_private
->pk_init_ctx
->id
->certs
);
2440 opt
->opt_private
->pk_init_ctx
->id
->cert
= NULL
;
2442 if ((flags
& 2) == 0) {
2443 hx509_context hx509ctx
= context
->hx509ctx
;
2444 hx509_cert cert
= opt
->opt_private
->pk_init_ctx
->id
->cert
;
2446 opt
->opt_private
->pk_init_ctx
->keyex
= USE_DH
;
2449 * If its a ECDSA certs, lets select ECDSA as the keyex algorithm.
2452 AlgorithmIdentifier alg
;
2454 ret
= hx509_cert_get_SPKI_AlgorithmIdentifier(hx509ctx
, cert
, &alg
);
2456 if (der_heim_oid_cmp(&alg
.algorithm
, &asn1_oid_id_ecPublicKey
) == 0)
2457 opt
->opt_private
->pk_init_ctx
->keyex
= USE_ECDH
;
2458 free_AlgorithmIdentifier(&alg
);
2463 opt
->opt_private
->pk_init_ctx
->keyex
= USE_RSA
;
2465 if (opt
->opt_private
->pk_init_ctx
->id
->certs
== NULL
) {
2466 krb5_set_error_message(context
, EINVAL
,
2467 N_("No anonymous pkinit support in RSA mode", ""));
2474 krb5_set_error_message(context
, EINVAL
,
2475 N_("no support for PKINIT compiled in", ""));
2480 krb5_error_code KRB5_LIB_FUNCTION
2481 krb5_get_init_creds_opt_set_pkinit_user_certs(krb5_context context
,
2482 krb5_get_init_creds_opt
*opt
,
2483 struct hx509_certs_data
*certs
)
2486 if (opt
->opt_private
== NULL
) {
2487 krb5_set_error_message(context
, EINVAL
,
2488 N_("PKINIT: on non extendable opt", ""));
2491 if (opt
->opt_private
->pk_init_ctx
== NULL
) {
2492 krb5_set_error_message(context
, EINVAL
,
2493 N_("PKINIT: on pkinit context", ""));
2497 _krb5_pk_set_user_id(context
, NULL
, opt
->opt_private
->pk_init_ctx
, certs
);
2501 krb5_set_error_message(context
, EINVAL
,
2502 N_("no support for PKINIT compiled in", ""));
2510 get_ms_san(hx509_context context
, hx509_cert cert
, char **upn
)
2512 hx509_octet_string_list list
;
2517 ret
= hx509_cert_find_subjectAltName_otherName(context
,
2519 &asn1_oid_id_pkinit_ms_san
,
2524 if (list
.len
> 0 && list
.val
[0].length
> 0)
2525 ret
= decode_MS_UPN_SAN(list
.val
[0].data
, list
.val
[0].length
,
2529 hx509_free_octet_string_list(&list
);
2535 find_ms_san(hx509_context context
, hx509_cert cert
, void *ctx
)
2540 ret
= get_ms_san(context
, cert
, &upn
);
2551 * Private since it need to be redesigned using krb5_get_init_creds()
2554 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
2555 krb5_pk_enterprise_cert(krb5_context context
,
2556 const char *user_id
,
2557 krb5_const_realm realm
,
2558 krb5_principal
*principal
,
2559 struct hx509_certs_data
**res
)
2562 krb5_error_code ret
;
2563 hx509_certs certs
, result
;
2564 hx509_cert cert
= NULL
;
2572 if (user_id
== NULL
) {
2573 krb5_set_error_message(context
, ENOENT
, "no user id");
2577 ret
= hx509_certs_init(context
->hx509ctx
, user_id
, 0, NULL
, &certs
);
2579 pk_copy_error(context
, context
->hx509ctx
, ret
,
2580 "Failed to init cert certs");
2584 ret
= hx509_query_alloc(context
->hx509ctx
, &q
);
2586 krb5_set_error_message(context
, ret
, "out of memory");
2587 hx509_certs_free(&certs
);
2591 hx509_query_match_option(q
, HX509_QUERY_OPTION_PRIVATE_KEY
);
2592 hx509_query_match_option(q
, HX509_QUERY_OPTION_KU_DIGITALSIGNATURE
);
2593 hx509_query_match_eku(q
, &asn1_oid_id_pkinit_ms_eku
);
2594 hx509_query_match_cmp_func(q
, find_ms_san
, NULL
);
2596 ret
= hx509_certs_filter(context
->hx509ctx
, certs
, q
, &result
);
2597 hx509_query_free(context
->hx509ctx
, q
);
2598 hx509_certs_free(&certs
);
2600 pk_copy_error(context
, context
->hx509ctx
, ret
,
2601 "Failed to find PKINIT certificate");
2605 ret
= hx509_get_one_cert(context
->hx509ctx
, result
, &cert
);
2606 hx509_certs_free(&result
);
2608 pk_copy_error(context
, context
->hx509ctx
, ret
,
2609 "Failed to get one cert");
2613 ret
= get_ms_san(context
->hx509ctx
, cert
, &name
);
2615 pk_copy_error(context
, context
->hx509ctx
, ret
,
2616 "Failed to get MS SAN");
2620 ret
= krb5_make_principal(context
, principal
, realm
, name
, NULL
);
2625 krb5_principal_set_type(context
, *principal
, KRB5_NT_ENTERPRISE_PRINCIPAL
);
2628 ret
= hx509_certs_init(context
->hx509ctx
, "MEMORY:", 0, NULL
, res
);
2632 ret
= hx509_certs_add(context
->hx509ctx
, *res
, cert
);
2634 hx509_certs_free(res
);
2640 hx509_cert_free(cert
);
2644 krb5_set_error_message(context
, EINVAL
,
2645 N_("no support for PKINIT compiled in", ""));