xref: /freebsd/crypto/krb5/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1*7f2fe78bSCy Schubert /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2*7f2fe78bSCy Schubert /*
3*7f2fe78bSCy Schubert  * COPYRIGHT (C) 2006,2007
4*7f2fe78bSCy Schubert  * THE REGENTS OF THE UNIVERSITY OF MICHIGAN
5*7f2fe78bSCy Schubert  * ALL RIGHTS RESERVED
6*7f2fe78bSCy Schubert  *
7*7f2fe78bSCy Schubert  * Permission is granted to use, copy, create derivative works
8*7f2fe78bSCy Schubert  * and redistribute this software and such derivative works
9*7f2fe78bSCy Schubert  * for any purpose, so long as the name of The University of
10*7f2fe78bSCy Schubert  * Michigan is not used in any advertising or publicity
11*7f2fe78bSCy Schubert  * pertaining to the use of distribution of this software
12*7f2fe78bSCy Schubert  * without specific, written prior authorization.  If the
13*7f2fe78bSCy Schubert  * above copyright notice or any other identification of the
14*7f2fe78bSCy Schubert  * University of Michigan is included in any copy of any
15*7f2fe78bSCy Schubert  * portion of this software, then the disclaimer below must
16*7f2fe78bSCy Schubert  * also be included.
17*7f2fe78bSCy Schubert  *
18*7f2fe78bSCy Schubert  * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
19*7f2fe78bSCy Schubert  * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
20*7f2fe78bSCy Schubert  * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
21*7f2fe78bSCy Schubert  * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
22*7f2fe78bSCy Schubert  * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
23*7f2fe78bSCy Schubert  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
24*7f2fe78bSCy Schubert  * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
25*7f2fe78bSCy Schubert  * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
26*7f2fe78bSCy Schubert  * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
27*7f2fe78bSCy Schubert  * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
28*7f2fe78bSCy Schubert  * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
29*7f2fe78bSCy Schubert  * SUCH DAMAGES.
30*7f2fe78bSCy Schubert  */
31*7f2fe78bSCy Schubert 
32*7f2fe78bSCy Schubert #include "k5-int.h"
33*7f2fe78bSCy Schubert #include "pkinit_crypto_openssl.h"
34*7f2fe78bSCy Schubert #include "k5-buf.h"
35*7f2fe78bSCy Schubert #include "k5-err.h"
36*7f2fe78bSCy Schubert #include "k5-hex.h"
37*7f2fe78bSCy Schubert #include <unistd.h>
38*7f2fe78bSCy Schubert #include <dirent.h>
39*7f2fe78bSCy Schubert #include <arpa/inet.h>
40*7f2fe78bSCy Schubert 
41*7f2fe78bSCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x30000000L
42*7f2fe78bSCy Schubert #include <openssl/core_names.h>
43*7f2fe78bSCy Schubert #include <openssl/kdf.h>
44*7f2fe78bSCy Schubert #include <openssl/params.h>
45*7f2fe78bSCy Schubert #endif
46*7f2fe78bSCy Schubert 
47*7f2fe78bSCy Schubert static krb5_error_code pkinit_init_pkinit_oids(pkinit_plg_crypto_context );
48*7f2fe78bSCy Schubert static void pkinit_fini_pkinit_oids(pkinit_plg_crypto_context );
49*7f2fe78bSCy Schubert 
50*7f2fe78bSCy Schubert static krb5_error_code pkinit_init_dh_params(pkinit_plg_crypto_context );
51*7f2fe78bSCy Schubert static void pkinit_fini_dh_params(pkinit_plg_crypto_context );
52*7f2fe78bSCy Schubert 
53*7f2fe78bSCy Schubert static krb5_error_code pkinit_init_certs(pkinit_identity_crypto_context ctx);
54*7f2fe78bSCy Schubert static void pkinit_fini_certs(pkinit_identity_crypto_context ctx);
55*7f2fe78bSCy Schubert 
56*7f2fe78bSCy Schubert static krb5_error_code pkinit_init_pkcs11(pkinit_identity_crypto_context ctx);
57*7f2fe78bSCy Schubert static void pkinit_fini_pkcs11(pkinit_identity_crypto_context ctx);
58*7f2fe78bSCy Schubert 
59*7f2fe78bSCy Schubert static krb5_error_code pkinit_sign_data
60*7f2fe78bSCy Schubert (krb5_context context, pkinit_identity_crypto_context cryptoctx,
61*7f2fe78bSCy Schubert  unsigned char *data, unsigned int data_len,
62*7f2fe78bSCy Schubert  unsigned char **sig, unsigned int *sig_len);
63*7f2fe78bSCy Schubert 
64*7f2fe78bSCy Schubert static krb5_error_code create_signature
65*7f2fe78bSCy Schubert (unsigned char **, unsigned int *, unsigned char *, unsigned int,
66*7f2fe78bSCy Schubert  EVP_PKEY *pkey);
67*7f2fe78bSCy Schubert 
68*7f2fe78bSCy Schubert static krb5_error_code pkinit_decode_data
69*7f2fe78bSCy Schubert (krb5_context context, pkinit_identity_crypto_context cryptoctx,
70*7f2fe78bSCy Schubert  const uint8_t *data, unsigned int data_len, uint8_t **decoded,
71*7f2fe78bSCy Schubert  unsigned int *decoded_len);
72*7f2fe78bSCy Schubert 
73*7f2fe78bSCy Schubert #ifdef DEBUG_DH
74*7f2fe78bSCy Schubert static void print_dh(DH *, char *);
75*7f2fe78bSCy Schubert static void print_pubkey(BIGNUM *, char *);
76*7f2fe78bSCy Schubert #endif
77*7f2fe78bSCy Schubert 
78*7f2fe78bSCy Schubert static int prepare_enc_data
79*7f2fe78bSCy Schubert (const uint8_t *indata, int indata_len, uint8_t **outdata, int *outdata_len);
80*7f2fe78bSCy Schubert 
81*7f2fe78bSCy Schubert static int openssl_callback (int, X509_STORE_CTX *);
82*7f2fe78bSCy Schubert static int openssl_callback_ignore_crls (int, X509_STORE_CTX *);
83*7f2fe78bSCy Schubert 
84*7f2fe78bSCy Schubert static int pkcs7_decrypt
85*7f2fe78bSCy Schubert (krb5_context context, pkinit_identity_crypto_context id_cryptoctx, PKCS7 *p7,
86*7f2fe78bSCy Schubert  unsigned char **data_out, unsigned int *len_out);
87*7f2fe78bSCy Schubert 
88*7f2fe78bSCy Schubert static ASN1_OBJECT * pkinit_pkcs7type2oid
89*7f2fe78bSCy Schubert (pkinit_plg_crypto_context plg_cryptoctx, int pkcs7_type);
90*7f2fe78bSCy Schubert 
91*7f2fe78bSCy Schubert static krb5_error_code pkinit_create_sequence_of_principal_identifiers
92*7f2fe78bSCy Schubert (krb5_context context, pkinit_plg_crypto_context plg_cryptoctx,
93*7f2fe78bSCy Schubert  pkinit_req_crypto_context req_cryptoctx,
94*7f2fe78bSCy Schubert  pkinit_identity_crypto_context id_cryptoctx,
95*7f2fe78bSCy Schubert  int type, krb5_pa_data ***e_data_out);
96*7f2fe78bSCy Schubert 
97*7f2fe78bSCy Schubert #ifndef WITHOUT_PKCS11
98*7f2fe78bSCy Schubert static krb5_error_code pkinit_find_private_key
99*7f2fe78bSCy Schubert (pkinit_identity_crypto_context, CK_ATTRIBUTE_TYPE usage,
100*7f2fe78bSCy Schubert  CK_OBJECT_HANDLE *objp);
101*7f2fe78bSCy Schubert static krb5_error_code pkinit_login
102*7f2fe78bSCy Schubert (krb5_context context, pkinit_identity_crypto_context id_cryptoctx,
103*7f2fe78bSCy Schubert  CK_TOKEN_INFO *tip, const char *password);
104*7f2fe78bSCy Schubert static krb5_error_code pkinit_open_session
105*7f2fe78bSCy Schubert (krb5_context context, pkinit_identity_crypto_context id_cryptoctx);
106*7f2fe78bSCy Schubert #ifdef SILLYDECRYPT
107*7f2fe78bSCy Schubert CK_RV pkinit_C_Decrypt
108*7f2fe78bSCy Schubert (pkinit_identity_crypto_context id_cryptoctx,
109*7f2fe78bSCy Schubert  CK_BYTE_PTR pEncryptedData, CK_ULONG  ulEncryptedDataLen,
110*7f2fe78bSCy Schubert  CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen);
111*7f2fe78bSCy Schubert #endif
112*7f2fe78bSCy Schubert 
113*7f2fe78bSCy Schubert static krb5_error_code pkinit_sign_data_pkcs11
114*7f2fe78bSCy Schubert (krb5_context context, pkinit_identity_crypto_context id_cryptoctx,
115*7f2fe78bSCy Schubert  unsigned char *data, unsigned int data_len,
116*7f2fe78bSCy Schubert  unsigned char **sig, unsigned int *sig_len);
117*7f2fe78bSCy Schubert static krb5_error_code pkinit_decode_data_pkcs11
118*7f2fe78bSCy Schubert (krb5_context context, pkinit_identity_crypto_context id_cryptoctx,
119*7f2fe78bSCy Schubert  const uint8_t *data, unsigned int data_len, uint8_t **decoded_data,
120*7f2fe78bSCy Schubert  unsigned int *decoded_data_len);
121*7f2fe78bSCy Schubert #endif  /* WITHOUT_PKCS11 */
122*7f2fe78bSCy Schubert 
123*7f2fe78bSCy Schubert static krb5_error_code pkinit_sign_data_fs
124*7f2fe78bSCy Schubert (krb5_context context, pkinit_identity_crypto_context id_cryptoctx,
125*7f2fe78bSCy Schubert  unsigned char *data, unsigned int data_len,
126*7f2fe78bSCy Schubert  unsigned char **sig, unsigned int *sig_len);
127*7f2fe78bSCy Schubert static krb5_error_code pkinit_decode_data_fs
128*7f2fe78bSCy Schubert (krb5_context context, pkinit_identity_crypto_context id_cryptoctx,
129*7f2fe78bSCy Schubert  const uint8_t *data, unsigned int data_len, uint8_t **decoded_data,
130*7f2fe78bSCy Schubert  unsigned int *decoded_data_len);
131*7f2fe78bSCy Schubert 
132*7f2fe78bSCy Schubert static krb5_error_code
133*7f2fe78bSCy Schubert create_krb5_invalidCertificates(krb5_context context,
134*7f2fe78bSCy Schubert                                 pkinit_plg_crypto_context plg_cryptoctx,
135*7f2fe78bSCy Schubert                                 pkinit_req_crypto_context req_cryptoctx,
136*7f2fe78bSCy Schubert                                 pkinit_identity_crypto_context id_cryptoctx,
137*7f2fe78bSCy Schubert                                 krb5_external_principal_identifier *** ids);
138*7f2fe78bSCy Schubert 
139*7f2fe78bSCy Schubert static krb5_error_code
140*7f2fe78bSCy Schubert create_identifiers_from_stack(STACK_OF(X509) *sk,
141*7f2fe78bSCy Schubert                               krb5_external_principal_identifier *** ids);
142*7f2fe78bSCy Schubert static int
143*7f2fe78bSCy Schubert wrap_signeddata(unsigned char *data, unsigned int data_len,
144*7f2fe78bSCy Schubert                 unsigned char **out, unsigned int *out_len);
145*7f2fe78bSCy Schubert 
146*7f2fe78bSCy Schubert static const char *
147*7f2fe78bSCy Schubert pkcs11err(int err);
148*7f2fe78bSCy Schubert 
149*7f2fe78bSCy Schubert 
150*7f2fe78bSCy Schubert #if OPENSSL_VERSION_NUMBER < 0x10100000L
151*7f2fe78bSCy Schubert 
152*7f2fe78bSCy Schubert /* 1.1 standardizes constructor and destructor names, renaming
153*7f2fe78bSCy Schubert  * EVP_MD_CTX_{create,destroy} and deprecating ASN1_STRING_data. */
154*7f2fe78bSCy Schubert 
155*7f2fe78bSCy Schubert #define EVP_MD_CTX_new EVP_MD_CTX_create
156*7f2fe78bSCy Schubert #define EVP_MD_CTX_free EVP_MD_CTX_destroy
157*7f2fe78bSCy Schubert #define ASN1_STRING_get0_data ASN1_STRING_data
158*7f2fe78bSCy Schubert 
159*7f2fe78bSCy Schubert /*
160*7f2fe78bSCy Schubert  * 1.1 adds DHX support, which uses the RFC 3279 DomainParameters encoding we
161*7f2fe78bSCy Schubert  * need for PKINIT.  For 1.0 we must use the original DH type when creating
162*7f2fe78bSCy Schubert  * EVP_PKEY objects.
163*7f2fe78bSCy Schubert  */
164*7f2fe78bSCy Schubert #define EVP_PKEY_DHX EVP_PKEY_DH
165*7f2fe78bSCy Schubert 
166*7f2fe78bSCy Schubert /* 1.1 makes many handle types opaque and adds accessors.  Add compatibility
167*7f2fe78bSCy Schubert  * versions of the new accessors we use for pre-1.1. */
168*7f2fe78bSCy Schubert 
169*7f2fe78bSCy Schubert #define OBJ_get0_data(o) ((o)->data)
170*7f2fe78bSCy Schubert #define OBJ_length(o) ((o)->length)
171*7f2fe78bSCy Schubert 
172*7f2fe78bSCy Schubert #define DH_set0_key compat_dh_set0_key
173*7f2fe78bSCy Schubert static int
compat_dh_set0_key(DH * dh,BIGNUM * pub,BIGNUM * priv)174*7f2fe78bSCy Schubert compat_dh_set0_key(DH *dh, BIGNUM *pub, BIGNUM *priv)
175*7f2fe78bSCy Schubert {
176*7f2fe78bSCy Schubert     if (pub != NULL) {
177*7f2fe78bSCy Schubert         BN_clear_free(dh->pub_key);
178*7f2fe78bSCy Schubert         dh->pub_key = pub;
179*7f2fe78bSCy Schubert     }
180*7f2fe78bSCy Schubert     if (priv != NULL) {
181*7f2fe78bSCy Schubert         BN_clear_free(dh->priv_key);
182*7f2fe78bSCy Schubert         dh->priv_key = priv;
183*7f2fe78bSCy Schubert     }
184*7f2fe78bSCy Schubert     return 1;
185*7f2fe78bSCy Schubert }
186*7f2fe78bSCy Schubert 
187*7f2fe78bSCy Schubert #define DH_get0_key compat_dh_get0_key
compat_dh_get0_key(const DH * dh,const BIGNUM ** pub,const BIGNUM ** priv)188*7f2fe78bSCy Schubert static void compat_dh_get0_key(const DH *dh, const BIGNUM **pub,
189*7f2fe78bSCy Schubert                                const BIGNUM **priv)
190*7f2fe78bSCy Schubert {
191*7f2fe78bSCy Schubert     if (pub != NULL)
192*7f2fe78bSCy Schubert         *pub = dh->pub_key;
193*7f2fe78bSCy Schubert     if (priv != NULL)
194*7f2fe78bSCy Schubert         *priv = dh->priv_key;
195*7f2fe78bSCy Schubert }
196*7f2fe78bSCy Schubert 
197*7f2fe78bSCy Schubert #define EVP_PKEY_get0_DH compat_get0_DH
198*7f2fe78bSCy Schubert static DH *
compat_get0_DH(const EVP_PKEY * pkey)199*7f2fe78bSCy Schubert compat_get0_DH(const EVP_PKEY *pkey)
200*7f2fe78bSCy Schubert {
201*7f2fe78bSCy Schubert     if (pkey->type != EVP_PKEY_DH)
202*7f2fe78bSCy Schubert         return NULL;
203*7f2fe78bSCy Schubert     return pkey->pkey.dh;
204*7f2fe78bSCy Schubert 
205*7f2fe78bSCy Schubert }
206*7f2fe78bSCy Schubert 
207*7f2fe78bSCy Schubert /* Return true if the cert c includes a key usage which doesn't include u.
208*7f2fe78bSCy Schubert  * Define using direct member access for pre-1.1. */
209*7f2fe78bSCy Schubert #define ku_reject(c, u)                                                 \
210*7f2fe78bSCy Schubert     (((c)->ex_flags & EXFLAG_KUSAGE) && !((c)->ex_kusage & (u)))
211*7f2fe78bSCy Schubert 
212*7f2fe78bSCy Schubert #else /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
213*7f2fe78bSCy Schubert 
214*7f2fe78bSCy Schubert /* Return true if the cert x includes a key usage which doesn't include u. */
215*7f2fe78bSCy Schubert #define ku_reject(c, u) (!(X509_get_key_usage(c) & (u)))
216*7f2fe78bSCy Schubert 
217*7f2fe78bSCy Schubert #endif
218*7f2fe78bSCy Schubert 
219*7f2fe78bSCy Schubert #if OPENSSL_VERSION_NUMBER < 0x30000000L
220*7f2fe78bSCy Schubert /* OpenSSL 3.0 changes several preferred function names. */
221*7f2fe78bSCy Schubert #define EVP_PKEY_parameters_eq EVP_PKEY_cmp_parameters
222*7f2fe78bSCy Schubert #define EVP_MD_CTX_get0_md EVP_MD_CTX_md
223*7f2fe78bSCy Schubert #define EVP_PKEY_get_size EVP_PKEY_size
224*7f2fe78bSCy Schubert #define EVP_PKEY_get_bits EVP_PKEY_bits
225*7f2fe78bSCy Schubert 
226*7f2fe78bSCy Schubert /*
227*7f2fe78bSCy Schubert  * Convert *dh to an EVP_PKEY object, taking ownership of *dh and setting it to
228*7f2fe78bSCy Schubert  * NULL.  On error, return NULL and do not take ownership of or change *dh.
229*7f2fe78bSCy Schubert  * OpenSSL 3.0 deprecates the low-level DH interfaces, so this helper will only
230*7f2fe78bSCy Schubert  * be used with prior versions.
231*7f2fe78bSCy Schubert  */
232*7f2fe78bSCy Schubert static EVP_PKEY *
dh_to_pkey(DH ** dh)233*7f2fe78bSCy Schubert dh_to_pkey(DH **dh)
234*7f2fe78bSCy Schubert {
235*7f2fe78bSCy Schubert     EVP_PKEY *pkey;
236*7f2fe78bSCy Schubert 
237*7f2fe78bSCy Schubert     pkey = EVP_PKEY_new();
238*7f2fe78bSCy Schubert     if (pkey == NULL)
239*7f2fe78bSCy Schubert         return NULL;
240*7f2fe78bSCy Schubert     if (!EVP_PKEY_assign(pkey, EVP_PKEY_DHX, *dh)) {
241*7f2fe78bSCy Schubert         EVP_PKEY_free(pkey);
242*7f2fe78bSCy Schubert         return NULL;
243*7f2fe78bSCy Schubert     }
244*7f2fe78bSCy Schubert     *dh = NULL;
245*7f2fe78bSCy Schubert     return pkey;
246*7f2fe78bSCy Schubert }
247*7f2fe78bSCy Schubert #endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
248*7f2fe78bSCy Schubert 
249*7f2fe78bSCy Schubert /* Encode a bignum as an ASN.1 integer in DER. */
250*7f2fe78bSCy Schubert static int
encode_bn_der(const BIGNUM * bn,uint8_t ** der_out,int * len_out)251*7f2fe78bSCy Schubert encode_bn_der(const BIGNUM *bn, uint8_t **der_out, int *len_out)
252*7f2fe78bSCy Schubert {
253*7f2fe78bSCy Schubert     ASN1_INTEGER *intval;
254*7f2fe78bSCy Schubert     int len;
255*7f2fe78bSCy Schubert     uint8_t *der = NULL, *outptr;
256*7f2fe78bSCy Schubert 
257*7f2fe78bSCy Schubert     intval = BN_to_ASN1_INTEGER(bn, NULL);
258*7f2fe78bSCy Schubert     if (intval == NULL)
259*7f2fe78bSCy Schubert         return 0;
260*7f2fe78bSCy Schubert     len = i2d_ASN1_INTEGER(intval, NULL);
261*7f2fe78bSCy Schubert     if (len > 0 && (outptr = der = malloc(len)) != NULL)
262*7f2fe78bSCy Schubert         (void)i2d_ASN1_INTEGER(intval, &outptr);
263*7f2fe78bSCy Schubert     ASN1_INTEGER_free(intval);
264*7f2fe78bSCy Schubert     if (der == NULL)
265*7f2fe78bSCy Schubert         return 0;
266*7f2fe78bSCy Schubert     *der_out = der;
267*7f2fe78bSCy Schubert     *len_out = len;
268*7f2fe78bSCy Schubert     return 1;
269*7f2fe78bSCy Schubert }
270*7f2fe78bSCy Schubert 
271*7f2fe78bSCy Schubert /* Decode an ASN.1 integer, returning a bignum. */
272*7f2fe78bSCy Schubert static BIGNUM *
decode_bn_der(const uint8_t * der,size_t len)273*7f2fe78bSCy Schubert decode_bn_der(const uint8_t *der, size_t len)
274*7f2fe78bSCy Schubert {
275*7f2fe78bSCy Schubert     ASN1_INTEGER *intval;
276*7f2fe78bSCy Schubert     BIGNUM *bn;
277*7f2fe78bSCy Schubert 
278*7f2fe78bSCy Schubert     intval = d2i_ASN1_INTEGER(NULL, &der, len);
279*7f2fe78bSCy Schubert     if (intval == NULL)
280*7f2fe78bSCy Schubert         return NULL;
281*7f2fe78bSCy Schubert     bn = ASN1_INTEGER_to_BN(intval, NULL);
282*7f2fe78bSCy Schubert     ASN1_INTEGER_free(intval);
283*7f2fe78bSCy Schubert     return bn;
284*7f2fe78bSCy Schubert }
285*7f2fe78bSCy Schubert 
286*7f2fe78bSCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x10100000L
287*7f2fe78bSCy Schubert static int
params_valid(EVP_PKEY * params)288*7f2fe78bSCy Schubert params_valid(EVP_PKEY *params)
289*7f2fe78bSCy Schubert {
290*7f2fe78bSCy Schubert     EVP_PKEY_CTX *ctx;
291*7f2fe78bSCy Schubert     int result;
292*7f2fe78bSCy Schubert 
293*7f2fe78bSCy Schubert     ctx = EVP_PKEY_CTX_new(params, NULL);
294*7f2fe78bSCy Schubert     if (ctx == NULL)
295*7f2fe78bSCy Schubert         return 0;
296*7f2fe78bSCy Schubert     result = EVP_PKEY_param_check(ctx);
297*7f2fe78bSCy Schubert     EVP_PKEY_CTX_free(ctx);
298*7f2fe78bSCy Schubert     return result == 1;
299*7f2fe78bSCy Schubert }
300*7f2fe78bSCy Schubert #else
301*7f2fe78bSCy Schubert static int
params_valid(EVP_PKEY * params)302*7f2fe78bSCy Schubert params_valid(EVP_PKEY *params)
303*7f2fe78bSCy Schubert {
304*7f2fe78bSCy Schubert     DH *dh;
305*7f2fe78bSCy Schubert     int codes;
306*7f2fe78bSCy Schubert 
307*7f2fe78bSCy Schubert     dh = EVP_PKEY_get0_DH(params);
308*7f2fe78bSCy Schubert     return (dh == NULL) ? 0 : (DH_check(dh, &codes) && codes == 0);
309*7f2fe78bSCy Schubert }
310*7f2fe78bSCy Schubert #endif
311*7f2fe78bSCy Schubert 
312*7f2fe78bSCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x10100000L
313*7f2fe78bSCy Schubert 
314*7f2fe78bSCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x30000000L
315*7f2fe78bSCy Schubert static EVP_PKEY *
decode_dh_params(const krb5_data * params_der)316*7f2fe78bSCy Schubert decode_dh_params(const krb5_data *params_der)
317*7f2fe78bSCy Schubert {
318*7f2fe78bSCy Schubert     EVP_PKEY *pkey = NULL;
319*7f2fe78bSCy Schubert     const uint8_t *inptr = (uint8_t *)params_der->data;
320*7f2fe78bSCy Schubert     size_t len = params_der->length;
321*7f2fe78bSCy Schubert     OSSL_DECODER_CTX *dctx;
322*7f2fe78bSCy Schubert     int ok;
323*7f2fe78bSCy Schubert 
324*7f2fe78bSCy Schubert     dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "DER", "type-specific", "DHX",
325*7f2fe78bSCy Schubert                                          EVP_PKEY_KEY_PARAMETERS, NULL, NULL);
326*7f2fe78bSCy Schubert     if (dctx == NULL)
327*7f2fe78bSCy Schubert         return NULL;
328*7f2fe78bSCy Schubert 
329*7f2fe78bSCy Schubert     ok = OSSL_DECODER_from_data(dctx, &inptr, &len);
330*7f2fe78bSCy Schubert     OSSL_DECODER_CTX_free(dctx);
331*7f2fe78bSCy Schubert     return ok ? pkey : NULL;
332*7f2fe78bSCy Schubert }
333*7f2fe78bSCy Schubert #else
334*7f2fe78bSCy Schubert static EVP_PKEY *
decode_dh_params(const krb5_data * params_der)335*7f2fe78bSCy Schubert decode_dh_params(const krb5_data *params_der)
336*7f2fe78bSCy Schubert {
337*7f2fe78bSCy Schubert     const uint8_t *p = (uint8_t *)params_der->data;
338*7f2fe78bSCy Schubert     DH *dh;
339*7f2fe78bSCy Schubert     EVP_PKEY *pkey;
340*7f2fe78bSCy Schubert 
341*7f2fe78bSCy Schubert     dh = d2i_DHxparams(NULL, &p, params_der->length);
342*7f2fe78bSCy Schubert     pkey = dh_to_pkey(&dh);
343*7f2fe78bSCy Schubert     DH_free(dh);
344*7f2fe78bSCy Schubert     return pkey;
345*7f2fe78bSCy Schubert }
346*7f2fe78bSCy Schubert #endif
347*7f2fe78bSCy Schubert 
348*7f2fe78bSCy Schubert static krb5_error_code
encode_spki(EVP_PKEY * pkey,krb5_data * spki_out)349*7f2fe78bSCy Schubert encode_spki(EVP_PKEY *pkey, krb5_data *spki_out)
350*7f2fe78bSCy Schubert {
351*7f2fe78bSCy Schubert     krb5_error_code ret = ENOMEM;
352*7f2fe78bSCy Schubert     int len;
353*7f2fe78bSCy Schubert     uint8_t *outptr;
354*7f2fe78bSCy Schubert 
355*7f2fe78bSCy Schubert     len = i2d_PUBKEY(pkey, NULL);
356*7f2fe78bSCy Schubert     ret = alloc_data(spki_out, len);
357*7f2fe78bSCy Schubert     if (ret)
358*7f2fe78bSCy Schubert         goto cleanup;
359*7f2fe78bSCy Schubert     outptr = (uint8_t *)spki_out->data;
360*7f2fe78bSCy Schubert     (void)i2d_PUBKEY(pkey, &outptr);
361*7f2fe78bSCy Schubert 
362*7f2fe78bSCy Schubert cleanup:
363*7f2fe78bSCy Schubert     return ret;
364*7f2fe78bSCy Schubert }
365*7f2fe78bSCy Schubert 
366*7f2fe78bSCy Schubert static EVP_PKEY *
decode_spki(const krb5_data * spki)367*7f2fe78bSCy Schubert decode_spki(const krb5_data *spki)
368*7f2fe78bSCy Schubert {
369*7f2fe78bSCy Schubert     const uint8_t *inptr = (uint8_t *)spki->data;
370*7f2fe78bSCy Schubert 
371*7f2fe78bSCy Schubert     return d2i_PUBKEY(NULL, &inptr, spki->length);
372*7f2fe78bSCy Schubert }
373*7f2fe78bSCy Schubert 
374*7f2fe78bSCy Schubert #else /* OPENSSL_VERSION_NUMBER < 0x10100000L */
375*7f2fe78bSCy Schubert 
376*7f2fe78bSCy Schubert /*
377*7f2fe78bSCy Schubert  * OpenSSL 1.0 has no DHX support, so we need a custom decoder for RFC 3279
378*7f2fe78bSCy Schubert  * DomainParameters, and we need to use X509_PUBKEY values to marshal
379*7f2fe78bSCy Schubert  * SubjectPublicKeyInfo.
380*7f2fe78bSCy Schubert  */
381*7f2fe78bSCy Schubert 
382*7f2fe78bSCy Schubert typedef struct {
383*7f2fe78bSCy Schubert     ASN1_BIT_STRING *seed;
384*7f2fe78bSCy Schubert     BIGNUM *counter;
385*7f2fe78bSCy Schubert } int_dhvparams;
386*7f2fe78bSCy Schubert 
387*7f2fe78bSCy Schubert typedef struct {
388*7f2fe78bSCy Schubert     BIGNUM *p;
389*7f2fe78bSCy Schubert     BIGNUM *q;
390*7f2fe78bSCy Schubert     BIGNUM *g;
391*7f2fe78bSCy Schubert     BIGNUM *j;
392*7f2fe78bSCy Schubert     int_dhvparams *vparams;
393*7f2fe78bSCy Schubert } int_dhxparams;
394*7f2fe78bSCy Schubert 
395*7f2fe78bSCy Schubert ASN1_SEQUENCE(int_dhvparams) = {
396*7f2fe78bSCy Schubert     ASN1_SIMPLE(int_dhvparams, seed, ASN1_BIT_STRING),
397*7f2fe78bSCy Schubert     ASN1_SIMPLE(int_dhvparams, counter, BIGNUM)
398*7f2fe78bSCy Schubert } ASN1_SEQUENCE_END(int_dhvparams);
399*7f2fe78bSCy Schubert 
400*7f2fe78bSCy Schubert ASN1_SEQUENCE(int_dhxparams) = {
401*7f2fe78bSCy Schubert     ASN1_SIMPLE(int_dhxparams, p, BIGNUM),
402*7f2fe78bSCy Schubert     ASN1_SIMPLE(int_dhxparams, g, BIGNUM),
403*7f2fe78bSCy Schubert     ASN1_SIMPLE(int_dhxparams, q, BIGNUM),
404*7f2fe78bSCy Schubert     ASN1_OPT(int_dhxparams, j, BIGNUM),
405*7f2fe78bSCy Schubert     ASN1_OPT(int_dhxparams, vparams, int_dhvparams)
406*7f2fe78bSCy Schubert } ASN1_SEQUENCE_END(int_dhxparams);
407*7f2fe78bSCy Schubert 
408*7f2fe78bSCy Schubert static EVP_PKEY *
decode_dh_params(const krb5_data * params_der)409*7f2fe78bSCy Schubert decode_dh_params(const krb5_data *params_der)
410*7f2fe78bSCy Schubert {
411*7f2fe78bSCy Schubert     int_dhxparams *params;
412*7f2fe78bSCy Schubert     DH *dh;
413*7f2fe78bSCy Schubert     EVP_PKEY *pkey;
414*7f2fe78bSCy Schubert     const uint8_t *p;
415*7f2fe78bSCy Schubert 
416*7f2fe78bSCy Schubert     dh = DH_new();
417*7f2fe78bSCy Schubert     if (dh == NULL)
418*7f2fe78bSCy Schubert         return NULL;
419*7f2fe78bSCy Schubert 
420*7f2fe78bSCy Schubert     p = (uint8_t *)params_der->data;
421*7f2fe78bSCy Schubert     params = (int_dhxparams *)ASN1_item_d2i(NULL, &p, params_der->length,
422*7f2fe78bSCy Schubert                                             ASN1_ITEM_rptr(int_dhxparams));
423*7f2fe78bSCy Schubert     if (params == NULL) {
424*7f2fe78bSCy Schubert         DH_free(dh);
425*7f2fe78bSCy Schubert         return NULL;
426*7f2fe78bSCy Schubert     }
427*7f2fe78bSCy Schubert 
428*7f2fe78bSCy Schubert     /* Steal p, q, and g from dhparams for dh.  Ignore j and vparams. */
429*7f2fe78bSCy Schubert     dh->p = params->p;
430*7f2fe78bSCy Schubert     dh->q = params->q;
431*7f2fe78bSCy Schubert     dh->g = params->g;
432*7f2fe78bSCy Schubert     params->p = params->q = params->g = NULL;
433*7f2fe78bSCy Schubert     ASN1_item_free((ASN1_VALUE *)params, ASN1_ITEM_rptr(int_dhxparams));
434*7f2fe78bSCy Schubert     pkey = dh_to_pkey(&dh);
435*7f2fe78bSCy Schubert     DH_free(dh);
436*7f2fe78bSCy Schubert     return pkey;
437*7f2fe78bSCy Schubert }
438*7f2fe78bSCy Schubert 
439*7f2fe78bSCy Schubert static krb5_error_code
encode_spki(EVP_PKEY * pkey,krb5_data * spki_out)440*7f2fe78bSCy Schubert encode_spki(EVP_PKEY *pkey, krb5_data *spki_out)
441*7f2fe78bSCy Schubert {
442*7f2fe78bSCy Schubert     krb5_error_code ret = ENOMEM;
443*7f2fe78bSCy Schubert     const DH *dh;
444*7f2fe78bSCy Schubert     uint8_t *param_der = NULL, *pubkey_der = NULL, *outptr;
445*7f2fe78bSCy Schubert     int param_der_len, pubkey_der_len, len;
446*7f2fe78bSCy Schubert     X509_PUBKEY pubkey;
447*7f2fe78bSCy Schubert     int_dhxparams dhxparams;
448*7f2fe78bSCy Schubert     X509_ALGOR algor;
449*7f2fe78bSCy Schubert     ASN1_OBJECT algorithm;
450*7f2fe78bSCy Schubert     ASN1_TYPE parameter;
451*7f2fe78bSCy Schubert     ASN1_STRING param_str, pubkey_str;
452*7f2fe78bSCy Schubert 
453*7f2fe78bSCy Schubert     dh = EVP_PKEY_get0_DH(pkey);
454*7f2fe78bSCy Schubert     if (dh == NULL)
455*7f2fe78bSCy Schubert         goto cleanup;
456*7f2fe78bSCy Schubert 
457*7f2fe78bSCy Schubert     dhxparams.p = dh->p;
458*7f2fe78bSCy Schubert     dhxparams.q = dh->q;
459*7f2fe78bSCy Schubert     dhxparams.g = dh->g;
460*7f2fe78bSCy Schubert     dhxparams.j = NULL;
461*7f2fe78bSCy Schubert     dhxparams.vparams = NULL;
462*7f2fe78bSCy Schubert     param_der_len = ASN1_item_i2d((ASN1_VALUE *)&dhxparams, &param_der,
463*7f2fe78bSCy Schubert                                   ASN1_ITEM_rptr(int_dhxparams));
464*7f2fe78bSCy Schubert     if (param_der_len < 0)
465*7f2fe78bSCy Schubert         goto cleanup;
466*7f2fe78bSCy Schubert     param_str.length = param_der_len;
467*7f2fe78bSCy Schubert     param_str.type = V_ASN1_SEQUENCE;
468*7f2fe78bSCy Schubert     param_str.data = param_der;
469*7f2fe78bSCy Schubert     param_str.flags = 0;
470*7f2fe78bSCy Schubert     parameter.type = V_ASN1_SEQUENCE;
471*7f2fe78bSCy Schubert     parameter.value.sequence = &param_str;
472*7f2fe78bSCy Schubert 
473*7f2fe78bSCy Schubert     memset(&algorithm, 0, sizeof(algorithm));
474*7f2fe78bSCy Schubert     algorithm.data = (uint8_t *)dh_oid.data;
475*7f2fe78bSCy Schubert     algorithm.length = dh_oid.length;
476*7f2fe78bSCy Schubert 
477*7f2fe78bSCy Schubert     algor.algorithm = &algorithm;
478*7f2fe78bSCy Schubert     algor.parameter = &parameter;
479*7f2fe78bSCy Schubert 
480*7f2fe78bSCy Schubert     if (!encode_bn_der(dh->pub_key, &pubkey_der, &pubkey_der_len))
481*7f2fe78bSCy Schubert         goto cleanup;
482*7f2fe78bSCy Schubert     pubkey_str.length = pubkey_der_len;
483*7f2fe78bSCy Schubert     pubkey_str.type = V_ASN1_BIT_STRING;
484*7f2fe78bSCy Schubert     pubkey_str.data = pubkey_der;
485*7f2fe78bSCy Schubert     pubkey_str.flags = ASN1_STRING_FLAG_BITS_LEFT;
486*7f2fe78bSCy Schubert 
487*7f2fe78bSCy Schubert     pubkey.algor = &algor;
488*7f2fe78bSCy Schubert     pubkey.public_key = &pubkey_str;
489*7f2fe78bSCy Schubert     len = i2d_X509_PUBKEY(&pubkey, NULL);
490*7f2fe78bSCy Schubert     if (len < 0)
491*7f2fe78bSCy Schubert         goto cleanup;
492*7f2fe78bSCy Schubert     ret = alloc_data(spki_out, len);
493*7f2fe78bSCy Schubert     if (ret)
494*7f2fe78bSCy Schubert         goto cleanup;
495*7f2fe78bSCy Schubert     outptr = (uint8_t *)spki_out->data;
496*7f2fe78bSCy Schubert     i2d_X509_PUBKEY(&pubkey, &outptr);
497*7f2fe78bSCy Schubert 
498*7f2fe78bSCy Schubert cleanup:
499*7f2fe78bSCy Schubert     OPENSSL_free(param_der);
500*7f2fe78bSCy Schubert     free(pubkey_der);
501*7f2fe78bSCy Schubert     return ret;
502*7f2fe78bSCy Schubert }
503*7f2fe78bSCy Schubert 
504*7f2fe78bSCy Schubert static EVP_PKEY *
decode_spki(const krb5_data * spki)505*7f2fe78bSCy Schubert decode_spki(const krb5_data *spki)
506*7f2fe78bSCy Schubert {
507*7f2fe78bSCy Schubert     X509_PUBKEY *pubkey = NULL;
508*7f2fe78bSCy Schubert     const uint8_t *inptr;
509*7f2fe78bSCy Schubert     DH *dh;
510*7f2fe78bSCy Schubert     EVP_PKEY *pkey = NULL, *pkey_ret = NULL;
511*7f2fe78bSCy Schubert     const ASN1_STRING *params;
512*7f2fe78bSCy Schubert     const ASN1_BIT_STRING *public_key;
513*7f2fe78bSCy Schubert     krb5_data d;
514*7f2fe78bSCy Schubert 
515*7f2fe78bSCy Schubert     inptr = (uint8_t *)spki->data;
516*7f2fe78bSCy Schubert     pubkey = d2i_X509_PUBKEY(NULL, &inptr, spki->length);
517*7f2fe78bSCy Schubert     if (pubkey == NULL)
518*7f2fe78bSCy Schubert         goto cleanup;
519*7f2fe78bSCy Schubert 
520*7f2fe78bSCy Schubert     if (pubkey->algor->parameter->type != V_ASN1_SEQUENCE)
521*7f2fe78bSCy Schubert         goto cleanup;
522*7f2fe78bSCy Schubert     params = pubkey->algor->parameter->value.sequence;
523*7f2fe78bSCy Schubert     d = make_data(params->data, params->length);
524*7f2fe78bSCy Schubert     pkey = decode_dh_params(&d);
525*7f2fe78bSCy Schubert     if (pkey == NULL)
526*7f2fe78bSCy Schubert         goto cleanup;
527*7f2fe78bSCy Schubert     dh = EVP_PKEY_get0_DH(pkey);
528*7f2fe78bSCy Schubert     if (dh == NULL)
529*7f2fe78bSCy Schubert         goto cleanup;
530*7f2fe78bSCy Schubert     public_key = pubkey->public_key;
531*7f2fe78bSCy Schubert     dh->pub_key = decode_bn_der(public_key->data, public_key->length);
532*7f2fe78bSCy Schubert     if (dh->pub_key == NULL)
533*7f2fe78bSCy Schubert         goto cleanup;
534*7f2fe78bSCy Schubert 
535*7f2fe78bSCy Schubert     pkey_ret = pkey;
536*7f2fe78bSCy Schubert     pkey = NULL;
537*7f2fe78bSCy Schubert 
538*7f2fe78bSCy Schubert cleanup:
539*7f2fe78bSCy Schubert     X509_PUBKEY_free(pubkey);
540*7f2fe78bSCy Schubert     EVP_PKEY_free(pkey);
541*7f2fe78bSCy Schubert     return pkey_ret;
542*7f2fe78bSCy Schubert }
543*7f2fe78bSCy Schubert 
544*7f2fe78bSCy Schubert #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
545*7f2fe78bSCy Schubert 
546*7f2fe78bSCy Schubert /* Attempt to specify padded Diffie-Hellman result derivation.  Don't error out
547*7f2fe78bSCy Schubert  * if this fails since we also detect short results and adjust them. */
548*7f2fe78bSCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x30000000L
549*7f2fe78bSCy Schubert static void
set_padded_derivation(EVP_PKEY_CTX * ctx)550*7f2fe78bSCy Schubert set_padded_derivation(EVP_PKEY_CTX *ctx)
551*7f2fe78bSCy Schubert {
552*7f2fe78bSCy Schubert     EVP_PKEY_CTX_set_dh_pad(ctx, 1);
553*7f2fe78bSCy Schubert }
554*7f2fe78bSCy Schubert #elif OPENSSL_VERSION_NUMBER >= 0x10100000L
555*7f2fe78bSCy Schubert static void
set_padded_derivation(EVP_PKEY_CTX * ctx)556*7f2fe78bSCy Schubert set_padded_derivation(EVP_PKEY_CTX *ctx)
557*7f2fe78bSCy Schubert {
558*7f2fe78bSCy Schubert     /* We would use EVP_PKEY_CTX_set_dh_pad() but it doesn't work with DHX. */
559*7f2fe78bSCy Schubert     EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_DERIVE,
560*7f2fe78bSCy Schubert                       EVP_PKEY_CTRL_DH_PAD, 1, NULL);
561*7f2fe78bSCy Schubert }
562*7f2fe78bSCy Schubert #else
563*7f2fe78bSCy Schubert static void
set_padded_derivation(EVP_PKEY_CTX * ctx)564*7f2fe78bSCy Schubert set_padded_derivation(EVP_PKEY_CTX *ctx)
565*7f2fe78bSCy Schubert {
566*7f2fe78bSCy Schubert     /* There's no support for padded derivation in 1.0. */
567*7f2fe78bSCy Schubert }
568*7f2fe78bSCy Schubert #endif
569*7f2fe78bSCy Schubert 
570*7f2fe78bSCy Schubert static int
dh_result(EVP_PKEY * pkey,EVP_PKEY * peer,uint8_t ** result_out,unsigned int * len_out)571*7f2fe78bSCy Schubert dh_result(EVP_PKEY *pkey, EVP_PKEY *peer,
572*7f2fe78bSCy Schubert           uint8_t **result_out, unsigned int *len_out)
573*7f2fe78bSCy Schubert {
574*7f2fe78bSCy Schubert     EVP_PKEY_CTX *derive_ctx = NULL;
575*7f2fe78bSCy Schubert     int ok = 0;
576*7f2fe78bSCy Schubert     uint8_t *buf = NULL;
577*7f2fe78bSCy Schubert     size_t len, dh_size = EVP_PKEY_get_size(pkey);
578*7f2fe78bSCy Schubert 
579*7f2fe78bSCy Schubert     *result_out = NULL;
580*7f2fe78bSCy Schubert     *len_out = 0;
581*7f2fe78bSCy Schubert 
582*7f2fe78bSCy Schubert     derive_ctx = EVP_PKEY_CTX_new(pkey, NULL);
583*7f2fe78bSCy Schubert     if (derive_ctx == NULL)
584*7f2fe78bSCy Schubert         goto cleanup;
585*7f2fe78bSCy Schubert     if (EVP_PKEY_derive_init(derive_ctx) <= 0)
586*7f2fe78bSCy Schubert         goto cleanup;
587*7f2fe78bSCy Schubert     set_padded_derivation(derive_ctx);
588*7f2fe78bSCy Schubert     if (EVP_PKEY_derive_set_peer(derive_ctx, peer) <= 0)
589*7f2fe78bSCy Schubert         goto cleanup;
590*7f2fe78bSCy Schubert 
591*7f2fe78bSCy Schubert     buf = malloc(dh_size);
592*7f2fe78bSCy Schubert     if (buf == NULL)
593*7f2fe78bSCy Schubert         goto cleanup;
594*7f2fe78bSCy Schubert     len = dh_size;
595*7f2fe78bSCy Schubert     if (EVP_PKEY_derive(derive_ctx, buf, &len) <= 0)
596*7f2fe78bSCy Schubert         goto cleanup;
597*7f2fe78bSCy Schubert     if (len < dh_size) {        /* only possible without padded derivation */
598*7f2fe78bSCy Schubert         memmove(buf + (dh_size - len), buf, len);
599*7f2fe78bSCy Schubert         memset(buf, 0, dh_size - len);
600*7f2fe78bSCy Schubert     }
601*7f2fe78bSCy Schubert 
602*7f2fe78bSCy Schubert     ok = 1;
603*7f2fe78bSCy Schubert     *result_out = buf;
604*7f2fe78bSCy Schubert     *len_out = dh_size;
605*7f2fe78bSCy Schubert     buf = NULL;
606*7f2fe78bSCy Schubert 
607*7f2fe78bSCy Schubert cleanup:
608*7f2fe78bSCy Schubert     EVP_PKEY_CTX_free(derive_ctx);
609*7f2fe78bSCy Schubert     free(buf);
610*7f2fe78bSCy Schubert     return ok;
611*7f2fe78bSCy Schubert }
612*7f2fe78bSCy Schubert 
613*7f2fe78bSCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x30000000L
614*7f2fe78bSCy Schubert static int
dh_pubkey_der(EVP_PKEY * pkey,uint8_t ** pubkey_out,unsigned int * len_out)615*7f2fe78bSCy Schubert dh_pubkey_der(EVP_PKEY *pkey, uint8_t **pubkey_out, unsigned int *len_out)
616*7f2fe78bSCy Schubert {
617*7f2fe78bSCy Schubert     BIGNUM *pubkey_bn = NULL;
618*7f2fe78bSCy Schubert     int len, ok;
619*7f2fe78bSCy Schubert     uint8_t *buf;
620*7f2fe78bSCy Schubert 
621*7f2fe78bSCy Schubert     if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, &pubkey_bn))
622*7f2fe78bSCy Schubert         return 0;
623*7f2fe78bSCy Schubert     ok = encode_bn_der(pubkey_bn, &buf, &len);
624*7f2fe78bSCy Schubert     BN_free(pubkey_bn);
625*7f2fe78bSCy Schubert     if (ok) {
626*7f2fe78bSCy Schubert         *pubkey_out = buf;
627*7f2fe78bSCy Schubert         *len_out = len;
628*7f2fe78bSCy Schubert     }
629*7f2fe78bSCy Schubert     return ok;
630*7f2fe78bSCy Schubert }
631*7f2fe78bSCy Schubert #else
632*7f2fe78bSCy Schubert static int
dh_pubkey_der(EVP_PKEY * pkey,uint8_t ** pubkey_out,unsigned int * len_out)633*7f2fe78bSCy Schubert dh_pubkey_der(EVP_PKEY *pkey, uint8_t **pubkey_out, unsigned int *len_out)
634*7f2fe78bSCy Schubert {
635*7f2fe78bSCy Schubert     const DH *dh;
636*7f2fe78bSCy Schubert     const BIGNUM *pubkey_bn;
637*7f2fe78bSCy Schubert     uint8_t *buf;
638*7f2fe78bSCy Schubert     int len;
639*7f2fe78bSCy Schubert 
640*7f2fe78bSCy Schubert     dh = EVP_PKEY_get0_DH(pkey);
641*7f2fe78bSCy Schubert     if (dh == NULL)
642*7f2fe78bSCy Schubert         return 0;
643*7f2fe78bSCy Schubert     DH_get0_key(dh, &pubkey_bn, NULL);
644*7f2fe78bSCy Schubert     if (!encode_bn_der(pubkey_bn, &buf, &len))
645*7f2fe78bSCy Schubert         return 0;
646*7f2fe78bSCy Schubert     *pubkey_out = buf;
647*7f2fe78bSCy Schubert     *len_out = len;
648*7f2fe78bSCy Schubert     return 1;
649*7f2fe78bSCy Schubert }
650*7f2fe78bSCy Schubert #endif
651*7f2fe78bSCy Schubert 
652*7f2fe78bSCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x10100000L
653*7f2fe78bSCy Schubert /* OpenSSL 1.1 and later will copy the q parameter when generating keys. */
654*7f2fe78bSCy Schubert static int
copy_q_openssl10(EVP_PKEY * src,EVP_PKEY * dest)655*7f2fe78bSCy Schubert copy_q_openssl10(EVP_PKEY *src, EVP_PKEY *dest)
656*7f2fe78bSCy Schubert {
657*7f2fe78bSCy Schubert     return 1;
658*7f2fe78bSCy Schubert }
659*7f2fe78bSCy Schubert #else
660*7f2fe78bSCy Schubert /* OpenSSL 1.0 won't copy the q parameter, so we have to do it. */
661*7f2fe78bSCy Schubert static int
copy_q_openssl10(EVP_PKEY * src,EVP_PKEY * dest)662*7f2fe78bSCy Schubert copy_q_openssl10(EVP_PKEY *src, EVP_PKEY *dest)
663*7f2fe78bSCy Schubert {
664*7f2fe78bSCy Schubert     DH *dhsrc = EVP_PKEY_get0_DH(src), *dhdest = EVP_PKEY_get0_DH(dest);
665*7f2fe78bSCy Schubert 
666*7f2fe78bSCy Schubert     if (dhsrc == NULL || dhsrc->q == NULL || dhdest == NULL)
667*7f2fe78bSCy Schubert         return 0;
668*7f2fe78bSCy Schubert     if (dhdest->q != NULL)
669*7f2fe78bSCy Schubert         return 1;
670*7f2fe78bSCy Schubert     dhdest->q = BN_dup(dhsrc->q);
671*7f2fe78bSCy Schubert     return dhdest->q != NULL;
672*7f2fe78bSCy Schubert }
673*7f2fe78bSCy Schubert #endif
674*7f2fe78bSCy Schubert 
675*7f2fe78bSCy Schubert static EVP_PKEY *
generate_dh_pkey(EVP_PKEY * params)676*7f2fe78bSCy Schubert generate_dh_pkey(EVP_PKEY *params)
677*7f2fe78bSCy Schubert {
678*7f2fe78bSCy Schubert     EVP_PKEY_CTX *ctx = NULL;
679*7f2fe78bSCy Schubert     EVP_PKEY *pkey = NULL;
680*7f2fe78bSCy Schubert 
681*7f2fe78bSCy Schubert     ctx = EVP_PKEY_CTX_new(params, NULL);
682*7f2fe78bSCy Schubert     if (ctx == NULL)
683*7f2fe78bSCy Schubert         goto cleanup;
684*7f2fe78bSCy Schubert     if (EVP_PKEY_keygen_init(ctx) <= 0)
685*7f2fe78bSCy Schubert         goto cleanup;
686*7f2fe78bSCy Schubert     if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
687*7f2fe78bSCy Schubert         goto cleanup;
688*7f2fe78bSCy Schubert     if (!copy_q_openssl10(params, pkey)) {
689*7f2fe78bSCy Schubert         EVP_PKEY_free(pkey);
690*7f2fe78bSCy Schubert         pkey = NULL;
691*7f2fe78bSCy Schubert     }
692*7f2fe78bSCy Schubert 
693*7f2fe78bSCy Schubert cleanup:
694*7f2fe78bSCy Schubert     EVP_PKEY_CTX_free(ctx);
695*7f2fe78bSCy Schubert     return pkey;
696*7f2fe78bSCy Schubert }
697*7f2fe78bSCy Schubert 
698*7f2fe78bSCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x30000000L
699*7f2fe78bSCy Schubert 
700*7f2fe78bSCy Schubert static EVP_PKEY *
compose_dh_pkey(EVP_PKEY * params,const uint8_t * pubkey_der,size_t der_len)701*7f2fe78bSCy Schubert compose_dh_pkey(EVP_PKEY *params, const uint8_t *pubkey_der, size_t der_len)
702*7f2fe78bSCy Schubert {
703*7f2fe78bSCy Schubert     EVP_PKEY *pkey = NULL, *pkey_ret = NULL;
704*7f2fe78bSCy Schubert     BIGNUM *pubkey_bn = NULL;
705*7f2fe78bSCy Schubert     uint8_t *pubkey_bin = NULL;
706*7f2fe78bSCy Schubert     int binlen;
707*7f2fe78bSCy Schubert 
708*7f2fe78bSCy Schubert     pkey = EVP_PKEY_dup(params);
709*7f2fe78bSCy Schubert     if (pkey == NULL)
710*7f2fe78bSCy Schubert         goto cleanup;
711*7f2fe78bSCy Schubert 
712*7f2fe78bSCy Schubert     pubkey_bn = decode_bn_der(pubkey_der, der_len);
713*7f2fe78bSCy Schubert     if (pubkey_bn == NULL)
714*7f2fe78bSCy Schubert         goto cleanup;
715*7f2fe78bSCy Schubert     binlen = EVP_PKEY_get_size(pkey);
716*7f2fe78bSCy Schubert     pubkey_bin = malloc(binlen);
717*7f2fe78bSCy Schubert     if (pubkey_bin == NULL)
718*7f2fe78bSCy Schubert         goto cleanup;
719*7f2fe78bSCy Schubert     if (BN_bn2binpad(pubkey_bn, pubkey_bin, binlen) != binlen)
720*7f2fe78bSCy Schubert         goto cleanup;
721*7f2fe78bSCy Schubert     if (EVP_PKEY_set1_encoded_public_key(pkey, pubkey_bin, binlen) != 1)
722*7f2fe78bSCy Schubert         goto cleanup;
723*7f2fe78bSCy Schubert 
724*7f2fe78bSCy Schubert     pkey_ret = pkey;
725*7f2fe78bSCy Schubert     pkey = NULL;
726*7f2fe78bSCy Schubert 
727*7f2fe78bSCy Schubert cleanup:
728*7f2fe78bSCy Schubert     EVP_PKEY_free(pkey);
729*7f2fe78bSCy Schubert     BN_free(pubkey_bn);
730*7f2fe78bSCy Schubert     free(pubkey_bin);
731*7f2fe78bSCy Schubert     return pkey_ret;
732*7f2fe78bSCy Schubert }
733*7f2fe78bSCy Schubert 
734*7f2fe78bSCy Schubert #else /* OPENSSL_VERSION_NUMBER < 0x30000000L */
735*7f2fe78bSCy Schubert 
736*7f2fe78bSCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x10100000L
737*7f2fe78bSCy Schubert static DH *
dup_dh_params(DH * src)738*7f2fe78bSCy Schubert dup_dh_params(DH *src)
739*7f2fe78bSCy Schubert {
740*7f2fe78bSCy Schubert     return DHparams_dup(src);
741*7f2fe78bSCy Schubert }
742*7f2fe78bSCy Schubert #else
743*7f2fe78bSCy Schubert /* DHparams_dup() won't copy q in OpenSSL 1.0. */
744*7f2fe78bSCy Schubert static DH *
dup_dh_params(DH * src)745*7f2fe78bSCy Schubert dup_dh_params(DH *src)
746*7f2fe78bSCy Schubert {
747*7f2fe78bSCy Schubert     DH *dh;
748*7f2fe78bSCy Schubert 
749*7f2fe78bSCy Schubert     dh = DH_new();
750*7f2fe78bSCy Schubert     if (dh == NULL)
751*7f2fe78bSCy Schubert         return NULL;
752*7f2fe78bSCy Schubert     dh->p = BN_dup(src->p);
753*7f2fe78bSCy Schubert     dh->q = BN_dup(src->q);
754*7f2fe78bSCy Schubert     dh->g = BN_dup(src->g);
755*7f2fe78bSCy Schubert     if (dh->p == NULL || dh->q == NULL || dh->g == NULL) {
756*7f2fe78bSCy Schubert         DH_free(dh);
757*7f2fe78bSCy Schubert         return NULL;
758*7f2fe78bSCy Schubert     }
759*7f2fe78bSCy Schubert     return dh;
760*7f2fe78bSCy Schubert }
761*7f2fe78bSCy Schubert #endif
762*7f2fe78bSCy Schubert 
763*7f2fe78bSCy Schubert static EVP_PKEY *
compose_dh_pkey(EVP_PKEY * params,const uint8_t * pubkey_der,size_t der_len)764*7f2fe78bSCy Schubert compose_dh_pkey(EVP_PKEY *params, const uint8_t *pubkey_der, size_t der_len)
765*7f2fe78bSCy Schubert {
766*7f2fe78bSCy Schubert     DH *dhparams, *dh = NULL;
767*7f2fe78bSCy Schubert     EVP_PKEY *pkey = NULL;
768*7f2fe78bSCy Schubert     BIGNUM *pubkey_bn = NULL;
769*7f2fe78bSCy Schubert 
770*7f2fe78bSCy Schubert     pubkey_bn = decode_bn_der(pubkey_der, der_len);
771*7f2fe78bSCy Schubert     if (pubkey_bn == NULL)
772*7f2fe78bSCy Schubert         goto cleanup;
773*7f2fe78bSCy Schubert 
774*7f2fe78bSCy Schubert     dhparams = EVP_PKEY_get0_DH(params);
775*7f2fe78bSCy Schubert     if (dhparams == NULL)
776*7f2fe78bSCy Schubert         goto cleanup;
777*7f2fe78bSCy Schubert     dh = dup_dh_params(dhparams);
778*7f2fe78bSCy Schubert     if (dh == NULL)
779*7f2fe78bSCy Schubert         goto cleanup;
780*7f2fe78bSCy Schubert     if (!DH_set0_key(dh, pubkey_bn, NULL))
781*7f2fe78bSCy Schubert         goto cleanup;
782*7f2fe78bSCy Schubert     pubkey_bn = NULL;
783*7f2fe78bSCy Schubert 
784*7f2fe78bSCy Schubert     pkey = dh_to_pkey(&dh);
785*7f2fe78bSCy Schubert 
786*7f2fe78bSCy Schubert cleanup:
787*7f2fe78bSCy Schubert     BN_free(pubkey_bn);
788*7f2fe78bSCy Schubert     DH_free(dh);
789*7f2fe78bSCy Schubert     return pkey;
790*7f2fe78bSCy Schubert }
791*7f2fe78bSCy Schubert 
792*7f2fe78bSCy Schubert #endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
793*7f2fe78bSCy Schubert 
794*7f2fe78bSCy Schubert static struct pkcs11_errstrings {
795*7f2fe78bSCy Schubert     short code;
796*7f2fe78bSCy Schubert     char *text;
797*7f2fe78bSCy Schubert } pkcs11_errstrings[] = {
798*7f2fe78bSCy Schubert     { 0x0,      "ok" },
799*7f2fe78bSCy Schubert     { 0x1,      "cancel" },
800*7f2fe78bSCy Schubert     { 0x2,      "host memory" },
801*7f2fe78bSCy Schubert     { 0x3,      "slot id invalid" },
802*7f2fe78bSCy Schubert     { 0x5,      "general error" },
803*7f2fe78bSCy Schubert     { 0x6,      "function failed" },
804*7f2fe78bSCy Schubert     { 0x7,      "arguments bad" },
805*7f2fe78bSCy Schubert     { 0x8,      "no event" },
806*7f2fe78bSCy Schubert     { 0x9,      "need to create threads" },
807*7f2fe78bSCy Schubert     { 0xa,      "cant lock" },
808*7f2fe78bSCy Schubert     { 0x10,     "attribute read only" },
809*7f2fe78bSCy Schubert     { 0x11,     "attribute sensitive" },
810*7f2fe78bSCy Schubert     { 0x12,     "attribute type invalid" },
811*7f2fe78bSCy Schubert     { 0x13,     "attribute value invalid" },
812*7f2fe78bSCy Schubert     { 0x20,     "data invalid" },
813*7f2fe78bSCy Schubert     { 0x21,     "data len range" },
814*7f2fe78bSCy Schubert     { 0x30,     "device error" },
815*7f2fe78bSCy Schubert     { 0x31,     "device memory" },
816*7f2fe78bSCy Schubert     { 0x32,     "device removed" },
817*7f2fe78bSCy Schubert     { 0x40,     "encrypted data invalid" },
818*7f2fe78bSCy Schubert     { 0x41,     "encrypted data len range" },
819*7f2fe78bSCy Schubert     { 0x50,     "function canceled" },
820*7f2fe78bSCy Schubert     { 0x51,     "function not parallel" },
821*7f2fe78bSCy Schubert     { 0x54,     "function not supported" },
822*7f2fe78bSCy Schubert     { 0x60,     "key handle invalid" },
823*7f2fe78bSCy Schubert     { 0x62,     "key size range" },
824*7f2fe78bSCy Schubert     { 0x63,     "key type inconsistent" },
825*7f2fe78bSCy Schubert     { 0x64,     "key not needed" },
826*7f2fe78bSCy Schubert     { 0x65,     "key changed" },
827*7f2fe78bSCy Schubert     { 0x66,     "key needed" },
828*7f2fe78bSCy Schubert     { 0x67,     "key indigestible" },
829*7f2fe78bSCy Schubert     { 0x68,     "key function not permitted" },
830*7f2fe78bSCy Schubert     { 0x69,     "key not wrappable" },
831*7f2fe78bSCy Schubert     { 0x6a,     "key unextractable" },
832*7f2fe78bSCy Schubert     { 0x70,     "mechanism invalid" },
833*7f2fe78bSCy Schubert     { 0x71,     "mechanism param invalid" },
834*7f2fe78bSCy Schubert     { 0x82,     "object handle invalid" },
835*7f2fe78bSCy Schubert     { 0x90,     "operation active" },
836*7f2fe78bSCy Schubert     { 0x91,     "operation not initialized" },
837*7f2fe78bSCy Schubert     { 0xa0,     "pin incorrect" },
838*7f2fe78bSCy Schubert     { 0xa1,     "pin invalid" },
839*7f2fe78bSCy Schubert     { 0xa2,     "pin len range" },
840*7f2fe78bSCy Schubert     { 0xa3,     "pin expired" },
841*7f2fe78bSCy Schubert     { 0xa4,     "pin locked" },
842*7f2fe78bSCy Schubert     { 0xb0,     "session closed" },
843*7f2fe78bSCy Schubert     { 0xb1,     "session count" },
844*7f2fe78bSCy Schubert     { 0xb3,     "session handle invalid" },
845*7f2fe78bSCy Schubert     { 0xb4,     "session parallel not supported" },
846*7f2fe78bSCy Schubert     { 0xb5,     "session read only" },
847*7f2fe78bSCy Schubert     { 0xb6,     "session exists" },
848*7f2fe78bSCy Schubert     { 0xb7,     "session read only exists" },
849*7f2fe78bSCy Schubert     { 0xb8,     "session read write so exists" },
850*7f2fe78bSCy Schubert     { 0xc0,     "signature invalid" },
851*7f2fe78bSCy Schubert     { 0xc1,     "signature len range" },
852*7f2fe78bSCy Schubert     { 0xd0,     "template incomplete" },
853*7f2fe78bSCy Schubert     { 0xd1,     "template inconsistent" },
854*7f2fe78bSCy Schubert     { 0xe0,     "token not present" },
855*7f2fe78bSCy Schubert     { 0xe1,     "token not recognized" },
856*7f2fe78bSCy Schubert     { 0xe2,     "token write protected" },
857*7f2fe78bSCy Schubert     { 0xf0,     "unwrapping key handle invalid" },
858*7f2fe78bSCy Schubert     { 0xf1,     "unwrapping key size range" },
859*7f2fe78bSCy Schubert     { 0xf2,     "unwrapping key type inconsistent" },
860*7f2fe78bSCy Schubert     { 0x100,    "user already logged in" },
861*7f2fe78bSCy Schubert     { 0x101,    "user not logged in" },
862*7f2fe78bSCy Schubert     { 0x102,    "user pin not initialized" },
863*7f2fe78bSCy Schubert     { 0x103,    "user type invalid" },
864*7f2fe78bSCy Schubert     { 0x104,    "user another already logged in" },
865*7f2fe78bSCy Schubert     { 0x105,    "user too many types" },
866*7f2fe78bSCy Schubert     { 0x110,    "wrapped key invalid" },
867*7f2fe78bSCy Schubert     { 0x112,    "wrapped key len range" },
868*7f2fe78bSCy Schubert     { 0x113,    "wrapping key handle invalid" },
869*7f2fe78bSCy Schubert     { 0x114,    "wrapping key size range" },
870*7f2fe78bSCy Schubert     { 0x115,    "wrapping key type inconsistent" },
871*7f2fe78bSCy Schubert     { 0x120,    "random seed not supported" },
872*7f2fe78bSCy Schubert     { 0x121,    "random no rng" },
873*7f2fe78bSCy Schubert     { 0x130,    "domain params invalid" },
874*7f2fe78bSCy Schubert     { 0x150,    "buffer too small" },
875*7f2fe78bSCy Schubert     { 0x160,    "saved state invalid" },
876*7f2fe78bSCy Schubert     { 0x170,    "information sensitive" },
877*7f2fe78bSCy Schubert     { 0x180,    "state unsaveable" },
878*7f2fe78bSCy Schubert     { 0x190,    "cryptoki not initialized" },
879*7f2fe78bSCy Schubert     { 0x191,    "cryptoki already initialized" },
880*7f2fe78bSCy Schubert     { 0x1a0,    "mutex bad" },
881*7f2fe78bSCy Schubert     { 0x1a1,    "mutex not locked" },
882*7f2fe78bSCy Schubert     { 0x200,    "function rejected" },
883*7f2fe78bSCy Schubert     { -1,       NULL }
884*7f2fe78bSCy Schubert };
885*7f2fe78bSCy Schubert 
886*7f2fe78bSCy Schubert MAKE_INIT_FUNCTION(pkinit_openssl_init);
887*7f2fe78bSCy Schubert 
888*7f2fe78bSCy Schubert static krb5_error_code oerr(krb5_context context, krb5_error_code code,
889*7f2fe78bSCy Schubert                             const char *fmt, ...)
890*7f2fe78bSCy Schubert #if !defined(__cplusplus) && (__GNUC__ > 2)
891*7f2fe78bSCy Schubert     __attribute__((__format__(__printf__, 3, 4)))
892*7f2fe78bSCy Schubert #endif
893*7f2fe78bSCy Schubert     ;
894*7f2fe78bSCy Schubert 
895*7f2fe78bSCy Schubert /*
896*7f2fe78bSCy Schubert  * Set an error string containing the formatted arguments and the first pending
897*7f2fe78bSCy Schubert  * OpenSSL error.  Write the formatted arguments and all pending OpenSSL error
898*7f2fe78bSCy Schubert  * messages to the trace log.  Return code, or KRB5KDC_ERR_PREAUTH_FAILED if
899*7f2fe78bSCy Schubert  * code is 0.
900*7f2fe78bSCy Schubert  */
901*7f2fe78bSCy Schubert static krb5_error_code
oerr(krb5_context context,krb5_error_code code,const char * fmt,...)902*7f2fe78bSCy Schubert oerr(krb5_context context, krb5_error_code code, const char *fmt, ...)
903*7f2fe78bSCy Schubert {
904*7f2fe78bSCy Schubert     unsigned long err;
905*7f2fe78bSCy Schubert     va_list ap;
906*7f2fe78bSCy Schubert     char *str, buf[128];
907*7f2fe78bSCy Schubert     int r;
908*7f2fe78bSCy Schubert 
909*7f2fe78bSCy Schubert     if (!code)
910*7f2fe78bSCy Schubert         code = KRB5KDC_ERR_PREAUTH_FAILED;
911*7f2fe78bSCy Schubert 
912*7f2fe78bSCy Schubert     va_start(ap, fmt);
913*7f2fe78bSCy Schubert     r = vasprintf(&str, fmt, ap);
914*7f2fe78bSCy Schubert     va_end(ap);
915*7f2fe78bSCy Schubert     if (r < 0)
916*7f2fe78bSCy Schubert         return code;
917*7f2fe78bSCy Schubert 
918*7f2fe78bSCy Schubert     err = ERR_peek_error();
919*7f2fe78bSCy Schubert     if (err) {
920*7f2fe78bSCy Schubert         krb5_set_error_message(context, code, _("%s: %s"), str,
921*7f2fe78bSCy Schubert                                ERR_reason_error_string(err));
922*7f2fe78bSCy Schubert     } else {
923*7f2fe78bSCy Schubert         krb5_set_error_message(context, code, "%s", str);
924*7f2fe78bSCy Schubert     }
925*7f2fe78bSCy Schubert 
926*7f2fe78bSCy Schubert     TRACE_PKINIT_OPENSSL_ERROR(context, str);
927*7f2fe78bSCy Schubert     while ((err = ERR_get_error()) != 0) {
928*7f2fe78bSCy Schubert         ERR_error_string_n(err, buf, sizeof(buf));
929*7f2fe78bSCy Schubert         TRACE_PKINIT_OPENSSL_ERROR(context, buf);
930*7f2fe78bSCy Schubert     }
931*7f2fe78bSCy Schubert 
932*7f2fe78bSCy Schubert     free(str);
933*7f2fe78bSCy Schubert     return code;
934*7f2fe78bSCy Schubert }
935*7f2fe78bSCy Schubert 
936*7f2fe78bSCy Schubert /*
937*7f2fe78bSCy Schubert  * Set an appropriate error string containing msg for a certificate
938*7f2fe78bSCy Schubert  * verification failure from certctx.  Write the message and all pending
939*7f2fe78bSCy Schubert  * OpenSSL error messages to the trace log.  Return code, or
940*7f2fe78bSCy Schubert  * KRB5KDC_ERR_PREAUTH_FAILED if code is 0.
941*7f2fe78bSCy Schubert  */
942*7f2fe78bSCy Schubert static krb5_error_code
oerr_cert(krb5_context context,krb5_error_code code,X509_STORE_CTX * certctx,const char * msg)943*7f2fe78bSCy Schubert oerr_cert(krb5_context context, krb5_error_code code, X509_STORE_CTX *certctx,
944*7f2fe78bSCy Schubert           const char *msg)
945*7f2fe78bSCy Schubert {
946*7f2fe78bSCy Schubert     int depth = X509_STORE_CTX_get_error_depth(certctx);
947*7f2fe78bSCy Schubert     int err = X509_STORE_CTX_get_error(certctx);
948*7f2fe78bSCy Schubert     const char *errstr = X509_verify_cert_error_string(err);
949*7f2fe78bSCy Schubert 
950*7f2fe78bSCy Schubert     return oerr(context, code, _("%s (depth %d): %s"), msg, depth, errstr);
951*7f2fe78bSCy Schubert }
952*7f2fe78bSCy Schubert 
953*7f2fe78bSCy Schubert krb5_error_code
pkinit_init_plg_crypto(pkinit_plg_crypto_context * cryptoctx)954*7f2fe78bSCy Schubert pkinit_init_plg_crypto(pkinit_plg_crypto_context *cryptoctx)
955*7f2fe78bSCy Schubert {
956*7f2fe78bSCy Schubert     krb5_error_code retval = ENOMEM;
957*7f2fe78bSCy Schubert     pkinit_plg_crypto_context ctx = NULL;
958*7f2fe78bSCy Schubert 
959*7f2fe78bSCy Schubert     (void)CALL_INIT_FUNCTION(pkinit_openssl_init);
960*7f2fe78bSCy Schubert 
961*7f2fe78bSCy Schubert     ctx = malloc(sizeof(*ctx));
962*7f2fe78bSCy Schubert     if (ctx == NULL)
963*7f2fe78bSCy Schubert         goto out;
964*7f2fe78bSCy Schubert     memset(ctx, 0, sizeof(*ctx));
965*7f2fe78bSCy Schubert 
966*7f2fe78bSCy Schubert     pkiDebug("%s: initializing openssl crypto context at %p\n",
967*7f2fe78bSCy Schubert              __FUNCTION__, ctx);
968*7f2fe78bSCy Schubert     retval = pkinit_init_pkinit_oids(ctx);
969*7f2fe78bSCy Schubert     if (retval)
970*7f2fe78bSCy Schubert         goto out;
971*7f2fe78bSCy Schubert 
972*7f2fe78bSCy Schubert     retval = pkinit_init_dh_params(ctx);
973*7f2fe78bSCy Schubert     if (retval)
974*7f2fe78bSCy Schubert         goto out;
975*7f2fe78bSCy Schubert 
976*7f2fe78bSCy Schubert     *cryptoctx = ctx;
977*7f2fe78bSCy Schubert 
978*7f2fe78bSCy Schubert out:
979*7f2fe78bSCy Schubert     if (retval && ctx != NULL)
980*7f2fe78bSCy Schubert         pkinit_fini_plg_crypto(ctx);
981*7f2fe78bSCy Schubert 
982*7f2fe78bSCy Schubert     return retval;
983*7f2fe78bSCy Schubert }
984*7f2fe78bSCy Schubert 
985*7f2fe78bSCy Schubert void
pkinit_fini_plg_crypto(pkinit_plg_crypto_context cryptoctx)986*7f2fe78bSCy Schubert pkinit_fini_plg_crypto(pkinit_plg_crypto_context cryptoctx)
987*7f2fe78bSCy Schubert {
988*7f2fe78bSCy Schubert     pkiDebug("%s: freeing context at %p\n", __FUNCTION__, cryptoctx);
989*7f2fe78bSCy Schubert 
990*7f2fe78bSCy Schubert     if (cryptoctx == NULL)
991*7f2fe78bSCy Schubert         return;
992*7f2fe78bSCy Schubert     pkinit_fini_pkinit_oids(cryptoctx);
993*7f2fe78bSCy Schubert     pkinit_fini_dh_params(cryptoctx);
994*7f2fe78bSCy Schubert     free(cryptoctx);
995*7f2fe78bSCy Schubert }
996*7f2fe78bSCy Schubert 
997*7f2fe78bSCy Schubert krb5_error_code
pkinit_init_identity_crypto(pkinit_identity_crypto_context * idctx)998*7f2fe78bSCy Schubert pkinit_init_identity_crypto(pkinit_identity_crypto_context *idctx)
999*7f2fe78bSCy Schubert {
1000*7f2fe78bSCy Schubert     krb5_error_code retval = ENOMEM;
1001*7f2fe78bSCy Schubert     pkinit_identity_crypto_context ctx = NULL;
1002*7f2fe78bSCy Schubert 
1003*7f2fe78bSCy Schubert     ctx = malloc(sizeof(*ctx));
1004*7f2fe78bSCy Schubert     if (ctx == NULL)
1005*7f2fe78bSCy Schubert         goto out;
1006*7f2fe78bSCy Schubert     memset(ctx, 0, sizeof(*ctx));
1007*7f2fe78bSCy Schubert 
1008*7f2fe78bSCy Schubert     ctx->identity = NULL;
1009*7f2fe78bSCy Schubert 
1010*7f2fe78bSCy Schubert     retval = pkinit_init_certs(ctx);
1011*7f2fe78bSCy Schubert     if (retval)
1012*7f2fe78bSCy Schubert         goto out;
1013*7f2fe78bSCy Schubert 
1014*7f2fe78bSCy Schubert     retval = pkinit_init_pkcs11(ctx);
1015*7f2fe78bSCy Schubert     if (retval)
1016*7f2fe78bSCy Schubert         goto out;
1017*7f2fe78bSCy Schubert 
1018*7f2fe78bSCy Schubert     pkiDebug("%s: returning ctx at %p\n", __FUNCTION__, ctx);
1019*7f2fe78bSCy Schubert     *idctx = ctx;
1020*7f2fe78bSCy Schubert 
1021*7f2fe78bSCy Schubert out:
1022*7f2fe78bSCy Schubert     if (retval) {
1023*7f2fe78bSCy Schubert         if (ctx)
1024*7f2fe78bSCy Schubert             pkinit_fini_identity_crypto(ctx);
1025*7f2fe78bSCy Schubert     }
1026*7f2fe78bSCy Schubert 
1027*7f2fe78bSCy Schubert     return retval;
1028*7f2fe78bSCy Schubert }
1029*7f2fe78bSCy Schubert 
1030*7f2fe78bSCy Schubert void
pkinit_fini_identity_crypto(pkinit_identity_crypto_context idctx)1031*7f2fe78bSCy Schubert pkinit_fini_identity_crypto(pkinit_identity_crypto_context idctx)
1032*7f2fe78bSCy Schubert {
1033*7f2fe78bSCy Schubert     if (idctx == NULL)
1034*7f2fe78bSCy Schubert         return;
1035*7f2fe78bSCy Schubert 
1036*7f2fe78bSCy Schubert     pkiDebug("%s: freeing ctx at %p\n", __FUNCTION__, idctx);
1037*7f2fe78bSCy Schubert     if (idctx->deferred_ids != NULL)
1038*7f2fe78bSCy Schubert         pkinit_free_deferred_ids(idctx->deferred_ids);
1039*7f2fe78bSCy Schubert     free(idctx->identity);
1040*7f2fe78bSCy Schubert     pkinit_fini_certs(idctx);
1041*7f2fe78bSCy Schubert     pkinit_fini_pkcs11(idctx);
1042*7f2fe78bSCy Schubert     free(idctx);
1043*7f2fe78bSCy Schubert }
1044*7f2fe78bSCy Schubert 
1045*7f2fe78bSCy Schubert krb5_error_code
pkinit_init_req_crypto(pkinit_req_crypto_context * cryptoctx)1046*7f2fe78bSCy Schubert pkinit_init_req_crypto(pkinit_req_crypto_context *cryptoctx)
1047*7f2fe78bSCy Schubert {
1048*7f2fe78bSCy Schubert     krb5_error_code retval = ENOMEM;
1049*7f2fe78bSCy Schubert     pkinit_req_crypto_context ctx = NULL;
1050*7f2fe78bSCy Schubert 
1051*7f2fe78bSCy Schubert     ctx = malloc(sizeof(*ctx));
1052*7f2fe78bSCy Schubert     if (ctx == NULL)
1053*7f2fe78bSCy Schubert         goto out;
1054*7f2fe78bSCy Schubert     memset(ctx, 0, sizeof(*ctx));
1055*7f2fe78bSCy Schubert 
1056*7f2fe78bSCy Schubert     ctx->client_pkey = NULL;
1057*7f2fe78bSCy Schubert     ctx->received_params = NULL;
1058*7f2fe78bSCy Schubert     ctx->received_cert = NULL;
1059*7f2fe78bSCy Schubert 
1060*7f2fe78bSCy Schubert     *cryptoctx = ctx;
1061*7f2fe78bSCy Schubert 
1062*7f2fe78bSCy Schubert     pkiDebug("%s: returning ctx at %p\n", __FUNCTION__, ctx);
1063*7f2fe78bSCy Schubert     retval = 0;
1064*7f2fe78bSCy Schubert out:
1065*7f2fe78bSCy Schubert     if (retval)
1066*7f2fe78bSCy Schubert         free(ctx);
1067*7f2fe78bSCy Schubert 
1068*7f2fe78bSCy Schubert     return retval;
1069*7f2fe78bSCy Schubert }
1070*7f2fe78bSCy Schubert 
1071*7f2fe78bSCy Schubert void
pkinit_fini_req_crypto(pkinit_req_crypto_context req_cryptoctx)1072*7f2fe78bSCy Schubert pkinit_fini_req_crypto(pkinit_req_crypto_context req_cryptoctx)
1073*7f2fe78bSCy Schubert {
1074*7f2fe78bSCy Schubert     if (req_cryptoctx == NULL)
1075*7f2fe78bSCy Schubert         return;
1076*7f2fe78bSCy Schubert 
1077*7f2fe78bSCy Schubert     pkiDebug("%s: freeing ctx at %p\n", __FUNCTION__, req_cryptoctx);
1078*7f2fe78bSCy Schubert     EVP_PKEY_free(req_cryptoctx->client_pkey);
1079*7f2fe78bSCy Schubert     EVP_PKEY_free(req_cryptoctx->received_params);
1080*7f2fe78bSCy Schubert     X509_free(req_cryptoctx->received_cert);
1081*7f2fe78bSCy Schubert 
1082*7f2fe78bSCy Schubert     free(req_cryptoctx);
1083*7f2fe78bSCy Schubert }
1084*7f2fe78bSCy Schubert 
1085*7f2fe78bSCy Schubert static krb5_error_code
pkinit_init_pkinit_oids(pkinit_plg_crypto_context ctx)1086*7f2fe78bSCy Schubert pkinit_init_pkinit_oids(pkinit_plg_crypto_context ctx)
1087*7f2fe78bSCy Schubert {
1088*7f2fe78bSCy Schubert     ctx->id_pkinit_san = OBJ_txt2obj("1.3.6.1.5.2.2", 1);
1089*7f2fe78bSCy Schubert     if (ctx->id_pkinit_san == NULL)
1090*7f2fe78bSCy Schubert         return ENOMEM;
1091*7f2fe78bSCy Schubert 
1092*7f2fe78bSCy Schubert     ctx->id_pkinit_authData = OBJ_txt2obj("1.3.6.1.5.2.3.1", 1);
1093*7f2fe78bSCy Schubert     if (ctx->id_pkinit_authData == NULL)
1094*7f2fe78bSCy Schubert         return ENOMEM;
1095*7f2fe78bSCy Schubert 
1096*7f2fe78bSCy Schubert     ctx->id_pkinit_DHKeyData = OBJ_txt2obj("1.3.6.1.5.2.3.2", 1);
1097*7f2fe78bSCy Schubert     if (ctx->id_pkinit_DHKeyData == NULL)
1098*7f2fe78bSCy Schubert         return ENOMEM;
1099*7f2fe78bSCy Schubert 
1100*7f2fe78bSCy Schubert     ctx->id_pkinit_rkeyData = OBJ_txt2obj("1.3.6.1.5.2.3.3", 1);
1101*7f2fe78bSCy Schubert     if (ctx->id_pkinit_rkeyData == NULL)
1102*7f2fe78bSCy Schubert         return ENOMEM;
1103*7f2fe78bSCy Schubert 
1104*7f2fe78bSCy Schubert     ctx->id_pkinit_KPClientAuth = OBJ_txt2obj("1.3.6.1.5.2.3.4", 1);
1105*7f2fe78bSCy Schubert     if (ctx->id_pkinit_KPClientAuth == NULL)
1106*7f2fe78bSCy Schubert         return ENOMEM;
1107*7f2fe78bSCy Schubert 
1108*7f2fe78bSCy Schubert     ctx->id_pkinit_KPKdc = OBJ_txt2obj("1.3.6.1.5.2.3.5", 1);
1109*7f2fe78bSCy Schubert     if (ctx->id_pkinit_KPKdc == NULL)
1110*7f2fe78bSCy Schubert         return ENOMEM;
1111*7f2fe78bSCy Schubert 
1112*7f2fe78bSCy Schubert     ctx->id_ms_kp_sc_logon = OBJ_txt2obj("1.3.6.1.4.1.311.20.2.2", 1);
1113*7f2fe78bSCy Schubert     if (ctx->id_ms_kp_sc_logon == NULL)
1114*7f2fe78bSCy Schubert         return ENOMEM;
1115*7f2fe78bSCy Schubert 
1116*7f2fe78bSCy Schubert     ctx->id_ms_san_upn = OBJ_txt2obj("1.3.6.1.4.1.311.20.2.3", 1);
1117*7f2fe78bSCy Schubert     if (ctx->id_ms_san_upn == NULL)
1118*7f2fe78bSCy Schubert         return ENOMEM;
1119*7f2fe78bSCy Schubert 
1120*7f2fe78bSCy Schubert     ctx->id_kp_serverAuth = OBJ_txt2obj("1.3.6.1.5.5.7.3.1", 1);
1121*7f2fe78bSCy Schubert     if (ctx->id_kp_serverAuth == NULL)
1122*7f2fe78bSCy Schubert         return ENOMEM;
1123*7f2fe78bSCy Schubert 
1124*7f2fe78bSCy Schubert     return 0;
1125*7f2fe78bSCy Schubert }
1126*7f2fe78bSCy Schubert 
1127*7f2fe78bSCy Schubert static krb5_error_code
get_cert(char * filename,X509 ** retcert)1128*7f2fe78bSCy Schubert get_cert(char *filename, X509 **retcert)
1129*7f2fe78bSCy Schubert {
1130*7f2fe78bSCy Schubert     X509 *cert = NULL;
1131*7f2fe78bSCy Schubert     BIO *tmp = NULL;
1132*7f2fe78bSCy Schubert     int code;
1133*7f2fe78bSCy Schubert     krb5_error_code retval;
1134*7f2fe78bSCy Schubert 
1135*7f2fe78bSCy Schubert     if (filename == NULL || retcert == NULL)
1136*7f2fe78bSCy Schubert         return EINVAL;
1137*7f2fe78bSCy Schubert 
1138*7f2fe78bSCy Schubert     *retcert = NULL;
1139*7f2fe78bSCy Schubert 
1140*7f2fe78bSCy Schubert     tmp = BIO_new(BIO_s_file());
1141*7f2fe78bSCy Schubert     if (tmp == NULL)
1142*7f2fe78bSCy Schubert         return ENOMEM;
1143*7f2fe78bSCy Schubert 
1144*7f2fe78bSCy Schubert     code = BIO_read_filename(tmp, filename);
1145*7f2fe78bSCy Schubert     if (code == 0) {
1146*7f2fe78bSCy Schubert         retval = errno;
1147*7f2fe78bSCy Schubert         goto cleanup;
1148*7f2fe78bSCy Schubert     }
1149*7f2fe78bSCy Schubert 
1150*7f2fe78bSCy Schubert     cert = (X509 *) PEM_read_bio_X509(tmp, NULL, NULL, NULL);
1151*7f2fe78bSCy Schubert     if (cert == NULL) {
1152*7f2fe78bSCy Schubert         retval = EIO;
1153*7f2fe78bSCy Schubert         pkiDebug("failed to read certificate from %s\n", filename);
1154*7f2fe78bSCy Schubert         goto cleanup;
1155*7f2fe78bSCy Schubert     }
1156*7f2fe78bSCy Schubert     *retcert = cert;
1157*7f2fe78bSCy Schubert     retval = 0;
1158*7f2fe78bSCy Schubert cleanup:
1159*7f2fe78bSCy Schubert     if (tmp != NULL)
1160*7f2fe78bSCy Schubert         BIO_free(tmp);
1161*7f2fe78bSCy Schubert     return retval;
1162*7f2fe78bSCy Schubert }
1163*7f2fe78bSCy Schubert 
1164*7f2fe78bSCy Schubert struct get_key_cb_data {
1165*7f2fe78bSCy Schubert     krb5_context context;
1166*7f2fe78bSCy Schubert     pkinit_identity_crypto_context id_cryptoctx;
1167*7f2fe78bSCy Schubert     const char *fsname;
1168*7f2fe78bSCy Schubert     char *filename;
1169*7f2fe78bSCy Schubert     const char *password;
1170*7f2fe78bSCy Schubert };
1171*7f2fe78bSCy Schubert 
1172*7f2fe78bSCy Schubert static int
get_key_cb(char * buf,int size,int rwflag,void * userdata)1173*7f2fe78bSCy Schubert get_key_cb(char *buf, int size, int rwflag, void *userdata)
1174*7f2fe78bSCy Schubert {
1175*7f2fe78bSCy Schubert     struct get_key_cb_data *data = userdata;
1176*7f2fe78bSCy Schubert     pkinit_identity_crypto_context id_cryptoctx;
1177*7f2fe78bSCy Schubert     krb5_data rdat;
1178*7f2fe78bSCy Schubert     krb5_prompt kprompt;
1179*7f2fe78bSCy Schubert     krb5_prompt_type prompt_type;
1180*7f2fe78bSCy Schubert     krb5_error_code retval;
1181*7f2fe78bSCy Schubert     char *prompt;
1182*7f2fe78bSCy Schubert 
1183*7f2fe78bSCy Schubert     if (data->id_cryptoctx->defer_id_prompt) {
1184*7f2fe78bSCy Schubert         /* Supply the identity name to be passed to a responder callback. */
1185*7f2fe78bSCy Schubert         pkinit_set_deferred_id(&data->id_cryptoctx->deferred_ids,
1186*7f2fe78bSCy Schubert                                data->fsname, 0, NULL);
1187*7f2fe78bSCy Schubert         return -1;
1188*7f2fe78bSCy Schubert     }
1189*7f2fe78bSCy Schubert     if (data->password == NULL) {
1190*7f2fe78bSCy Schubert         /* We don't already have a password to use, so prompt for one. */
1191*7f2fe78bSCy Schubert         if (data->id_cryptoctx->prompter == NULL)
1192*7f2fe78bSCy Schubert             return -1;
1193*7f2fe78bSCy Schubert         if (asprintf(&prompt, "%s %s", _("Pass phrase for"),
1194*7f2fe78bSCy Schubert                      data->filename) < 0)
1195*7f2fe78bSCy Schubert             return -1;
1196*7f2fe78bSCy Schubert         rdat.data = buf;
1197*7f2fe78bSCy Schubert         rdat.length = size;
1198*7f2fe78bSCy Schubert         kprompt.prompt = prompt;
1199*7f2fe78bSCy Schubert         kprompt.hidden = 1;
1200*7f2fe78bSCy Schubert         kprompt.reply = &rdat;
1201*7f2fe78bSCy Schubert         prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
1202*7f2fe78bSCy Schubert 
1203*7f2fe78bSCy Schubert         /* PROMPTER_INVOCATION */
1204*7f2fe78bSCy Schubert         k5int_set_prompt_types(data->context, &prompt_type);
1205*7f2fe78bSCy Schubert         id_cryptoctx = data->id_cryptoctx;
1206*7f2fe78bSCy Schubert         retval = (data->id_cryptoctx->prompter)(data->context,
1207*7f2fe78bSCy Schubert                                                 id_cryptoctx->prompter_data,
1208*7f2fe78bSCy Schubert                                                 NULL, NULL, 1, &kprompt);
1209*7f2fe78bSCy Schubert         k5int_set_prompt_types(data->context, 0);
1210*7f2fe78bSCy Schubert         free(prompt);
1211*7f2fe78bSCy Schubert         if (retval != 0)
1212*7f2fe78bSCy Schubert             return -1;
1213*7f2fe78bSCy Schubert     } else {
1214*7f2fe78bSCy Schubert         /* Just use the already-supplied password. */
1215*7f2fe78bSCy Schubert         rdat.length = strlen(data->password);
1216*7f2fe78bSCy Schubert         if ((int)rdat.length >= size)
1217*7f2fe78bSCy Schubert             return -1;
1218*7f2fe78bSCy Schubert         snprintf(buf, size, "%s", data->password);
1219*7f2fe78bSCy Schubert     }
1220*7f2fe78bSCy Schubert     return (int)rdat.length;
1221*7f2fe78bSCy Schubert }
1222*7f2fe78bSCy Schubert 
1223*7f2fe78bSCy Schubert static krb5_error_code
get_key(krb5_context context,pkinit_identity_crypto_context id_cryptoctx,char * filename,const char * fsname,EVP_PKEY ** retkey,const char * password)1224*7f2fe78bSCy Schubert get_key(krb5_context context, pkinit_identity_crypto_context id_cryptoctx,
1225*7f2fe78bSCy Schubert         char *filename, const char *fsname, EVP_PKEY **retkey,
1226*7f2fe78bSCy Schubert         const char *password)
1227*7f2fe78bSCy Schubert {
1228*7f2fe78bSCy Schubert     EVP_PKEY *pkey = NULL;
1229*7f2fe78bSCy Schubert     BIO *tmp = NULL;
1230*7f2fe78bSCy Schubert     struct get_key_cb_data cb_data;
1231*7f2fe78bSCy Schubert     int code;
1232*7f2fe78bSCy Schubert     krb5_error_code retval;
1233*7f2fe78bSCy Schubert 
1234*7f2fe78bSCy Schubert     if (filename == NULL || retkey == NULL)
1235*7f2fe78bSCy Schubert         return EINVAL;
1236*7f2fe78bSCy Schubert 
1237*7f2fe78bSCy Schubert     tmp = BIO_new(BIO_s_file());
1238*7f2fe78bSCy Schubert     if (tmp == NULL)
1239*7f2fe78bSCy Schubert         return ENOMEM;
1240*7f2fe78bSCy Schubert 
1241*7f2fe78bSCy Schubert     code = BIO_read_filename(tmp, filename);
1242*7f2fe78bSCy Schubert     if (code == 0) {
1243*7f2fe78bSCy Schubert         retval = errno;
1244*7f2fe78bSCy Schubert         goto cleanup;
1245*7f2fe78bSCy Schubert     }
1246*7f2fe78bSCy Schubert     cb_data.context = context;
1247*7f2fe78bSCy Schubert     cb_data.id_cryptoctx = id_cryptoctx;
1248*7f2fe78bSCy Schubert     cb_data.filename = filename;
1249*7f2fe78bSCy Schubert     cb_data.fsname = fsname;
1250*7f2fe78bSCy Schubert     cb_data.password = password;
1251*7f2fe78bSCy Schubert     pkey = PEM_read_bio_PrivateKey(tmp, NULL, get_key_cb, &cb_data);
1252*7f2fe78bSCy Schubert     if (pkey == NULL && !id_cryptoctx->defer_id_prompt) {
1253*7f2fe78bSCy Schubert         retval = EIO;
1254*7f2fe78bSCy Schubert         pkiDebug("failed to read private key from %s\n", filename);
1255*7f2fe78bSCy Schubert         goto cleanup;
1256*7f2fe78bSCy Schubert     }
1257*7f2fe78bSCy Schubert     *retkey = pkey;
1258*7f2fe78bSCy Schubert     retval = 0;
1259*7f2fe78bSCy Schubert cleanup:
1260*7f2fe78bSCy Schubert     if (tmp != NULL)
1261*7f2fe78bSCy Schubert         BIO_free(tmp);
1262*7f2fe78bSCy Schubert     return retval;
1263*7f2fe78bSCy Schubert }
1264*7f2fe78bSCy Schubert 
1265*7f2fe78bSCy Schubert static void
pkinit_fini_pkinit_oids(pkinit_plg_crypto_context ctx)1266*7f2fe78bSCy Schubert pkinit_fini_pkinit_oids(pkinit_plg_crypto_context ctx)
1267*7f2fe78bSCy Schubert {
1268*7f2fe78bSCy Schubert     if (ctx == NULL)
1269*7f2fe78bSCy Schubert         return;
1270*7f2fe78bSCy Schubert     ASN1_OBJECT_free(ctx->id_pkinit_san);
1271*7f2fe78bSCy Schubert     ASN1_OBJECT_free(ctx->id_pkinit_authData);
1272*7f2fe78bSCy Schubert     ASN1_OBJECT_free(ctx->id_pkinit_DHKeyData);
1273*7f2fe78bSCy Schubert     ASN1_OBJECT_free(ctx->id_pkinit_rkeyData);
1274*7f2fe78bSCy Schubert     ASN1_OBJECT_free(ctx->id_pkinit_KPClientAuth);
1275*7f2fe78bSCy Schubert     ASN1_OBJECT_free(ctx->id_pkinit_KPKdc);
1276*7f2fe78bSCy Schubert     ASN1_OBJECT_free(ctx->id_ms_kp_sc_logon);
1277*7f2fe78bSCy Schubert     ASN1_OBJECT_free(ctx->id_ms_san_upn);
1278*7f2fe78bSCy Schubert     ASN1_OBJECT_free(ctx->id_kp_serverAuth);
1279*7f2fe78bSCy Schubert }
1280*7f2fe78bSCy Schubert 
1281*7f2fe78bSCy Schubert static krb5_error_code
pkinit_init_dh_params(pkinit_plg_crypto_context plgctx)1282*7f2fe78bSCy Schubert pkinit_init_dh_params(pkinit_plg_crypto_context plgctx)
1283*7f2fe78bSCy Schubert {
1284*7f2fe78bSCy Schubert     krb5_error_code retval = ENOMEM;
1285*7f2fe78bSCy Schubert 
1286*7f2fe78bSCy Schubert     plgctx->dh_1024 = decode_dh_params(&oakley_1024);
1287*7f2fe78bSCy Schubert     if (plgctx->dh_1024 == NULL)
1288*7f2fe78bSCy Schubert         goto cleanup;
1289*7f2fe78bSCy Schubert 
1290*7f2fe78bSCy Schubert     plgctx->dh_2048 = decode_dh_params(&oakley_2048);
1291*7f2fe78bSCy Schubert     if (plgctx->dh_2048 == NULL)
1292*7f2fe78bSCy Schubert         goto cleanup;
1293*7f2fe78bSCy Schubert 
1294*7f2fe78bSCy Schubert     plgctx->dh_4096 = decode_dh_params(&oakley_4096);
1295*7f2fe78bSCy Schubert     if (plgctx->dh_4096 == NULL)
1296*7f2fe78bSCy Schubert         goto cleanup;
1297*7f2fe78bSCy Schubert 
1298*7f2fe78bSCy Schubert     retval = 0;
1299*7f2fe78bSCy Schubert 
1300*7f2fe78bSCy Schubert cleanup:
1301*7f2fe78bSCy Schubert     if (retval)
1302*7f2fe78bSCy Schubert         pkinit_fini_dh_params(plgctx);
1303*7f2fe78bSCy Schubert 
1304*7f2fe78bSCy Schubert     return retval;
1305*7f2fe78bSCy Schubert }
1306*7f2fe78bSCy Schubert 
1307*7f2fe78bSCy Schubert static void
pkinit_fini_dh_params(pkinit_plg_crypto_context plgctx)1308*7f2fe78bSCy Schubert pkinit_fini_dh_params(pkinit_plg_crypto_context plgctx)
1309*7f2fe78bSCy Schubert {
1310*7f2fe78bSCy Schubert     EVP_PKEY_free(plgctx->dh_1024);
1311*7f2fe78bSCy Schubert     EVP_PKEY_free(plgctx->dh_2048);
1312*7f2fe78bSCy Schubert     EVP_PKEY_free(plgctx->dh_4096);
1313*7f2fe78bSCy Schubert     plgctx->dh_1024 = plgctx->dh_2048 = plgctx->dh_4096 = NULL;
1314*7f2fe78bSCy Schubert }
1315*7f2fe78bSCy Schubert 
1316*7f2fe78bSCy Schubert static krb5_error_code
pkinit_init_certs(pkinit_identity_crypto_context ctx)1317*7f2fe78bSCy Schubert pkinit_init_certs(pkinit_identity_crypto_context ctx)
1318*7f2fe78bSCy Schubert {
1319*7f2fe78bSCy Schubert     krb5_error_code retval = ENOMEM;
1320*7f2fe78bSCy Schubert     int i;
1321*7f2fe78bSCy Schubert 
1322*7f2fe78bSCy Schubert     for (i = 0; i < MAX_CREDS_ALLOWED; i++)
1323*7f2fe78bSCy Schubert         ctx->creds[i] = NULL;
1324*7f2fe78bSCy Schubert     ctx->my_certs = NULL;
1325*7f2fe78bSCy Schubert     ctx->cert_index = 0;
1326*7f2fe78bSCy Schubert     ctx->my_key = NULL;
1327*7f2fe78bSCy Schubert     ctx->trustedCAs = NULL;
1328*7f2fe78bSCy Schubert     ctx->intermediateCAs = NULL;
1329*7f2fe78bSCy Schubert     ctx->revoked = NULL;
1330*7f2fe78bSCy Schubert 
1331*7f2fe78bSCy Schubert     retval = 0;
1332*7f2fe78bSCy Schubert     return retval;
1333*7f2fe78bSCy Schubert }
1334*7f2fe78bSCy Schubert 
1335*7f2fe78bSCy Schubert static void
pkinit_fini_certs(pkinit_identity_crypto_context ctx)1336*7f2fe78bSCy Schubert pkinit_fini_certs(pkinit_identity_crypto_context ctx)
1337*7f2fe78bSCy Schubert {
1338*7f2fe78bSCy Schubert     if (ctx == NULL)
1339*7f2fe78bSCy Schubert         return;
1340*7f2fe78bSCy Schubert 
1341*7f2fe78bSCy Schubert     if (ctx->my_certs != NULL)
1342*7f2fe78bSCy Schubert         sk_X509_pop_free(ctx->my_certs, X509_free);
1343*7f2fe78bSCy Schubert 
1344*7f2fe78bSCy Schubert     if (ctx->my_key != NULL)
1345*7f2fe78bSCy Schubert         EVP_PKEY_free(ctx->my_key);
1346*7f2fe78bSCy Schubert 
1347*7f2fe78bSCy Schubert     if (ctx->trustedCAs != NULL)
1348*7f2fe78bSCy Schubert         sk_X509_pop_free(ctx->trustedCAs, X509_free);
1349*7f2fe78bSCy Schubert 
1350*7f2fe78bSCy Schubert     if (ctx->intermediateCAs != NULL)
1351*7f2fe78bSCy Schubert         sk_X509_pop_free(ctx->intermediateCAs, X509_free);
1352*7f2fe78bSCy Schubert 
1353*7f2fe78bSCy Schubert     if (ctx->revoked != NULL)
1354*7f2fe78bSCy Schubert         sk_X509_CRL_pop_free(ctx->revoked, X509_CRL_free);
1355*7f2fe78bSCy Schubert }
1356*7f2fe78bSCy Schubert 
1357*7f2fe78bSCy Schubert static krb5_error_code
pkinit_init_pkcs11(pkinit_identity_crypto_context ctx)1358*7f2fe78bSCy Schubert pkinit_init_pkcs11(pkinit_identity_crypto_context ctx)
1359*7f2fe78bSCy Schubert {
1360*7f2fe78bSCy Schubert     krb5_error_code retval = ENOMEM;
1361*7f2fe78bSCy Schubert 
1362*7f2fe78bSCy Schubert #ifndef WITHOUT_PKCS11
1363*7f2fe78bSCy Schubert     ctx->p11_module_name = strdup(PKCS11_MODNAME);
1364*7f2fe78bSCy Schubert     if (ctx->p11_module_name == NULL)
1365*7f2fe78bSCy Schubert         return retval;
1366*7f2fe78bSCy Schubert     ctx->p11_module = NULL;
1367*7f2fe78bSCy Schubert     ctx->slotid = PK_NOSLOT;
1368*7f2fe78bSCy Schubert     ctx->token_label = NULL;
1369*7f2fe78bSCy Schubert     ctx->cert_label = NULL;
1370*7f2fe78bSCy Schubert     ctx->session = CK_INVALID_HANDLE;
1371*7f2fe78bSCy Schubert     ctx->p11 = NULL;
1372*7f2fe78bSCy Schubert #endif
1373*7f2fe78bSCy Schubert     ctx->pkcs11_method = 0;
1374*7f2fe78bSCy Schubert 
1375*7f2fe78bSCy Schubert     retval = 0;
1376*7f2fe78bSCy Schubert     return retval;
1377*7f2fe78bSCy Schubert }
1378*7f2fe78bSCy Schubert 
1379*7f2fe78bSCy Schubert static void
pkinit_fini_pkcs11(pkinit_identity_crypto_context ctx)1380*7f2fe78bSCy Schubert pkinit_fini_pkcs11(pkinit_identity_crypto_context ctx)
1381*7f2fe78bSCy Schubert {
1382*7f2fe78bSCy Schubert #ifndef WITHOUT_PKCS11
1383*7f2fe78bSCy Schubert     if (ctx == NULL)
1384*7f2fe78bSCy Schubert         return;
1385*7f2fe78bSCy Schubert 
1386*7f2fe78bSCy Schubert     if (ctx->p11 != NULL) {
1387*7f2fe78bSCy Schubert         if (ctx->session != CK_INVALID_HANDLE) {
1388*7f2fe78bSCy Schubert             ctx->p11->C_CloseSession(ctx->session);
1389*7f2fe78bSCy Schubert             ctx->session = CK_INVALID_HANDLE;
1390*7f2fe78bSCy Schubert         }
1391*7f2fe78bSCy Schubert         ctx->p11->C_Finalize(NULL_PTR);
1392*7f2fe78bSCy Schubert         ctx->p11 = NULL;
1393*7f2fe78bSCy Schubert     }
1394*7f2fe78bSCy Schubert     if (ctx->p11_module != NULL) {
1395*7f2fe78bSCy Schubert         krb5int_close_plugin(ctx->p11_module);
1396*7f2fe78bSCy Schubert         ctx->p11_module = NULL;
1397*7f2fe78bSCy Schubert     }
1398*7f2fe78bSCy Schubert     free(ctx->p11_module_name);
1399*7f2fe78bSCy Schubert     free(ctx->token_label);
1400*7f2fe78bSCy Schubert     free(ctx->cert_id);
1401*7f2fe78bSCy Schubert     free(ctx->cert_label);
1402*7f2fe78bSCy Schubert #endif
1403*7f2fe78bSCy Schubert }
1404*7f2fe78bSCy Schubert 
1405*7f2fe78bSCy Schubert krb5_error_code
pkinit_identity_set_prompter(pkinit_identity_crypto_context id_cryptoctx,krb5_prompter_fct prompter,void * prompter_data)1406*7f2fe78bSCy Schubert pkinit_identity_set_prompter(pkinit_identity_crypto_context id_cryptoctx,
1407*7f2fe78bSCy Schubert                              krb5_prompter_fct prompter,
1408*7f2fe78bSCy Schubert                              void *prompter_data)
1409*7f2fe78bSCy Schubert {
1410*7f2fe78bSCy Schubert     id_cryptoctx->prompter = prompter;
1411*7f2fe78bSCy Schubert     id_cryptoctx->prompter_data = prompter_data;
1412*7f2fe78bSCy Schubert 
1413*7f2fe78bSCy Schubert     return 0;
1414*7f2fe78bSCy Schubert }
1415*7f2fe78bSCy Schubert 
1416*7f2fe78bSCy Schubert /* Create a CMS ContentInfo of type oid containing the octet string in data. */
1417*7f2fe78bSCy Schubert static krb5_error_code
create_contentinfo(krb5_context context,ASN1_OBJECT * oid,unsigned char * data,size_t data_len,PKCS7 ** p7_out)1418*7f2fe78bSCy Schubert create_contentinfo(krb5_context context, ASN1_OBJECT *oid,
1419*7f2fe78bSCy Schubert                    unsigned char *data, size_t data_len, PKCS7 **p7_out)
1420*7f2fe78bSCy Schubert {
1421*7f2fe78bSCy Schubert     PKCS7 *p7 = NULL;
1422*7f2fe78bSCy Schubert     ASN1_OCTET_STRING *ostr = NULL;
1423*7f2fe78bSCy Schubert 
1424*7f2fe78bSCy Schubert     *p7_out = NULL;
1425*7f2fe78bSCy Schubert 
1426*7f2fe78bSCy Schubert     ostr = ASN1_OCTET_STRING_new();
1427*7f2fe78bSCy Schubert     if (ostr == NULL)
1428*7f2fe78bSCy Schubert         goto oom;
1429*7f2fe78bSCy Schubert     if (!ASN1_OCTET_STRING_set(ostr, (unsigned char *)data, data_len))
1430*7f2fe78bSCy Schubert         goto oom;
1431*7f2fe78bSCy Schubert 
1432*7f2fe78bSCy Schubert     p7 = PKCS7_new();
1433*7f2fe78bSCy Schubert     if (p7 == NULL)
1434*7f2fe78bSCy Schubert         goto oom;
1435*7f2fe78bSCy Schubert     p7->type = OBJ_dup(oid);
1436*7f2fe78bSCy Schubert     if (p7->type == NULL)
1437*7f2fe78bSCy Schubert         goto oom;
1438*7f2fe78bSCy Schubert 
1439*7f2fe78bSCy Schubert     p7->d.other = ASN1_TYPE_new();
1440*7f2fe78bSCy Schubert     if (p7->d.other == NULL)
1441*7f2fe78bSCy Schubert         goto oom;
1442*7f2fe78bSCy Schubert     p7->d.other->type = V_ASN1_OCTET_STRING;
1443*7f2fe78bSCy Schubert     p7->d.other->value.octet_string = ostr;
1444*7f2fe78bSCy Schubert 
1445*7f2fe78bSCy Schubert     *p7_out = p7;
1446*7f2fe78bSCy Schubert     return 0;
1447*7f2fe78bSCy Schubert 
1448*7f2fe78bSCy Schubert oom:
1449*7f2fe78bSCy Schubert     if (ostr != NULL)
1450*7f2fe78bSCy Schubert         ASN1_OCTET_STRING_free(ostr);
1451*7f2fe78bSCy Schubert     if (p7 != NULL)
1452*7f2fe78bSCy Schubert         PKCS7_free(p7);
1453*7f2fe78bSCy Schubert     return ENOMEM;
1454*7f2fe78bSCy Schubert }
1455*7f2fe78bSCy Schubert 
1456*7f2fe78bSCy Schubert krb5_error_code
cms_contentinfo_create(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,int cms_msg_type,unsigned char * data,unsigned int data_len,unsigned char ** out_data,unsigned int * out_data_len)1457*7f2fe78bSCy Schubert cms_contentinfo_create(krb5_context context,                          /* IN */
1458*7f2fe78bSCy Schubert                        pkinit_plg_crypto_context plg_cryptoctx,       /* IN */
1459*7f2fe78bSCy Schubert                        pkinit_req_crypto_context req_cryptoctx,       /* IN */
1460*7f2fe78bSCy Schubert                        pkinit_identity_crypto_context id_cryptoctx,   /* IN */
1461*7f2fe78bSCy Schubert                        int cms_msg_type,
1462*7f2fe78bSCy Schubert                        unsigned char *data, unsigned int data_len,
1463*7f2fe78bSCy Schubert                        unsigned char **out_data, unsigned int *out_data_len)
1464*7f2fe78bSCy Schubert {
1465*7f2fe78bSCy Schubert     krb5_error_code retval = ENOMEM;
1466*7f2fe78bSCy Schubert     ASN1_OBJECT *oid;
1467*7f2fe78bSCy Schubert     PKCS7 *p7 = NULL;
1468*7f2fe78bSCy Schubert     unsigned char *p;
1469*7f2fe78bSCy Schubert 
1470*7f2fe78bSCy Schubert     /* Pick the correct oid for the eContentInfo. */
1471*7f2fe78bSCy Schubert     oid = pkinit_pkcs7type2oid(plg_cryptoctx, cms_msg_type);
1472*7f2fe78bSCy Schubert     if (oid == NULL)
1473*7f2fe78bSCy Schubert         goto cleanup;
1474*7f2fe78bSCy Schubert     retval = create_contentinfo(context, oid, data, data_len, &p7);
1475*7f2fe78bSCy Schubert     if (retval != 0)
1476*7f2fe78bSCy Schubert         goto cleanup;
1477*7f2fe78bSCy Schubert     *out_data_len = i2d_PKCS7(p7, NULL);
1478*7f2fe78bSCy Schubert     if (!(*out_data_len)) {
1479*7f2fe78bSCy Schubert         retval = oerr(context, 0, _("Failed to DER encode PKCS7"));
1480*7f2fe78bSCy Schubert         goto cleanup;
1481*7f2fe78bSCy Schubert     }
1482*7f2fe78bSCy Schubert     retval = ENOMEM;
1483*7f2fe78bSCy Schubert     if ((p = *out_data = malloc(*out_data_len)) == NULL)
1484*7f2fe78bSCy Schubert         goto cleanup;
1485*7f2fe78bSCy Schubert 
1486*7f2fe78bSCy Schubert     /* DER encode PKCS7 data */
1487*7f2fe78bSCy Schubert     retval = i2d_PKCS7(p7, &p);
1488*7f2fe78bSCy Schubert     if (!retval) {
1489*7f2fe78bSCy Schubert         retval = oerr(context, 0, _("Failed to DER encode PKCS7"));
1490*7f2fe78bSCy Schubert         goto cleanup;
1491*7f2fe78bSCy Schubert     }
1492*7f2fe78bSCy Schubert     retval = 0;
1493*7f2fe78bSCy Schubert cleanup:
1494*7f2fe78bSCy Schubert     if (p7)
1495*7f2fe78bSCy Schubert         PKCS7_free(p7);
1496*7f2fe78bSCy Schubert     return retval;
1497*7f2fe78bSCy Schubert }
1498*7f2fe78bSCy Schubert 
1499*7f2fe78bSCy Schubert 
1500*7f2fe78bSCy Schubert 
1501*7f2fe78bSCy Schubert krb5_error_code
cms_signeddata_create(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,int cms_msg_type,unsigned char * data,unsigned int data_len,unsigned char ** signed_data,unsigned int * signed_data_len)1502*7f2fe78bSCy Schubert cms_signeddata_create(krb5_context context,
1503*7f2fe78bSCy Schubert                       pkinit_plg_crypto_context plg_cryptoctx,
1504*7f2fe78bSCy Schubert                       pkinit_req_crypto_context req_cryptoctx,
1505*7f2fe78bSCy Schubert                       pkinit_identity_crypto_context id_cryptoctx,
1506*7f2fe78bSCy Schubert                       int cms_msg_type,
1507*7f2fe78bSCy Schubert                       unsigned char *data,
1508*7f2fe78bSCy Schubert                       unsigned int data_len,
1509*7f2fe78bSCy Schubert                       unsigned char **signed_data,
1510*7f2fe78bSCy Schubert                       unsigned int *signed_data_len)
1511*7f2fe78bSCy Schubert {
1512*7f2fe78bSCy Schubert     krb5_error_code retval = ENOMEM;
1513*7f2fe78bSCy Schubert     PKCS7  *p7 = NULL, *inner_p7 = NULL;
1514*7f2fe78bSCy Schubert     PKCS7_SIGNED *p7s = NULL;
1515*7f2fe78bSCy Schubert     PKCS7_SIGNER_INFO *p7si = NULL;
1516*7f2fe78bSCy Schubert     unsigned char *p;
1517*7f2fe78bSCy Schubert     STACK_OF(X509) * cert_stack = NULL;
1518*7f2fe78bSCy Schubert     ASN1_OCTET_STRING *digest_attr = NULL;
1519*7f2fe78bSCy Schubert     EVP_MD_CTX *ctx;
1520*7f2fe78bSCy Schubert     const EVP_MD *md_tmp = NULL;
1521*7f2fe78bSCy Schubert     unsigned char md_data[EVP_MAX_MD_SIZE], md_data2[EVP_MAX_MD_SIZE];
1522*7f2fe78bSCy Schubert     unsigned char *digestInfo_buf = NULL, *abuf = NULL;
1523*7f2fe78bSCy Schubert     unsigned int md_len, md_len2, alen, digestInfo_len;
1524*7f2fe78bSCy Schubert     STACK_OF(X509_ATTRIBUTE) * sk;
1525*7f2fe78bSCy Schubert     unsigned char *sig = NULL;
1526*7f2fe78bSCy Schubert     unsigned int sig_len = 0;
1527*7f2fe78bSCy Schubert     X509_ALGOR *alg = NULL;
1528*7f2fe78bSCy Schubert     ASN1_OCTET_STRING *digest = NULL;
1529*7f2fe78bSCy Schubert     unsigned int alg_len = 0, digest_len = 0;
1530*7f2fe78bSCy Schubert     unsigned char *y = NULL;
1531*7f2fe78bSCy Schubert     X509 *cert = NULL;
1532*7f2fe78bSCy Schubert     ASN1_OBJECT *oid = NULL, *oid_copy;
1533*7f2fe78bSCy Schubert 
1534*7f2fe78bSCy Schubert     /* Start creating PKCS7 data. */
1535*7f2fe78bSCy Schubert     if ((p7 = PKCS7_new()) == NULL)
1536*7f2fe78bSCy Schubert         goto cleanup;
1537*7f2fe78bSCy Schubert     p7->type = OBJ_nid2obj(NID_pkcs7_signed);
1538*7f2fe78bSCy Schubert 
1539*7f2fe78bSCy Schubert     if ((p7s = PKCS7_SIGNED_new()) == NULL)
1540*7f2fe78bSCy Schubert         goto cleanup;
1541*7f2fe78bSCy Schubert     p7->d.sign = p7s;
1542*7f2fe78bSCy Schubert     if (!ASN1_INTEGER_set(p7s->version, 3))
1543*7f2fe78bSCy Schubert         goto cleanup;
1544*7f2fe78bSCy Schubert 
1545*7f2fe78bSCy Schubert     /* pick the correct oid for the eContentInfo */
1546*7f2fe78bSCy Schubert     oid = pkinit_pkcs7type2oid(plg_cryptoctx, cms_msg_type);
1547*7f2fe78bSCy Schubert     if (oid == NULL)
1548*7f2fe78bSCy Schubert         goto cleanup;
1549*7f2fe78bSCy Schubert 
1550*7f2fe78bSCy Schubert     if (id_cryptoctx->my_certs != NULL) {
1551*7f2fe78bSCy Schubert         X509_STORE *certstore = NULL;
1552*7f2fe78bSCy Schubert         X509_STORE_CTX *certctx;
1553*7f2fe78bSCy Schubert         STACK_OF(X509) *certstack = NULL;
1554*7f2fe78bSCy Schubert         char buf[DN_BUF_LEN];
1555*7f2fe78bSCy Schubert         unsigned int i = 0, size = 0;
1556*7f2fe78bSCy Schubert 
1557*7f2fe78bSCy Schubert         /* create a cert chain */
1558*7f2fe78bSCy Schubert         if ((cert_stack = sk_X509_new_null()) == NULL)
1559*7f2fe78bSCy Schubert             goto cleanup;
1560*7f2fe78bSCy Schubert 
1561*7f2fe78bSCy Schubert         cert = sk_X509_value(id_cryptoctx->my_certs, id_cryptoctx->cert_index);
1562*7f2fe78bSCy Schubert 
1563*7f2fe78bSCy Schubert         certstore = X509_STORE_new();
1564*7f2fe78bSCy Schubert         if (certstore == NULL)
1565*7f2fe78bSCy Schubert             goto cleanup;
1566*7f2fe78bSCy Schubert         pkiDebug("building certificate chain\n");
1567*7f2fe78bSCy Schubert         X509_STORE_set_verify_cb(certstore, openssl_callback);
1568*7f2fe78bSCy Schubert         certctx = X509_STORE_CTX_new();
1569*7f2fe78bSCy Schubert         if (certctx == NULL)
1570*7f2fe78bSCy Schubert             goto cleanup;
1571*7f2fe78bSCy Schubert         X509_STORE_CTX_init(certctx, certstore, cert,
1572*7f2fe78bSCy Schubert                             id_cryptoctx->intermediateCAs);
1573*7f2fe78bSCy Schubert         X509_STORE_CTX_trusted_stack(certctx, id_cryptoctx->trustedCAs);
1574*7f2fe78bSCy Schubert         if (!X509_verify_cert(certctx)) {
1575*7f2fe78bSCy Schubert             retval = oerr_cert(context, 0, certctx,
1576*7f2fe78bSCy Schubert                                _("Failed to verify own certificate"));
1577*7f2fe78bSCy Schubert             goto cleanup;
1578*7f2fe78bSCy Schubert         }
1579*7f2fe78bSCy Schubert         certstack = X509_STORE_CTX_get1_chain(certctx);
1580*7f2fe78bSCy Schubert         size = sk_X509_num(certstack);
1581*7f2fe78bSCy Schubert         for (i = 0; i < size - 1; i++) {
1582*7f2fe78bSCy Schubert             X509 *x = sk_X509_value(certstack, i);
1583*7f2fe78bSCy Schubert             X509_NAME_oneline(X509_get_subject_name(x), buf, sizeof(buf));
1584*7f2fe78bSCy Schubert             TRACE_PKINIT_CERT_CHAIN_NAME(context, (int)i, buf);
1585*7f2fe78bSCy Schubert             sk_X509_push(cert_stack, X509_dup(x));
1586*7f2fe78bSCy Schubert         }
1587*7f2fe78bSCy Schubert         X509_STORE_CTX_free(certctx);
1588*7f2fe78bSCy Schubert         X509_STORE_free(certstore);
1589*7f2fe78bSCy Schubert         sk_X509_pop_free(certstack, X509_free);
1590*7f2fe78bSCy Schubert 
1591*7f2fe78bSCy Schubert         p7s->cert = cert_stack;
1592*7f2fe78bSCy Schubert 
1593*7f2fe78bSCy Schubert         /* fill-in PKCS7_SIGNER_INFO */
1594*7f2fe78bSCy Schubert         if ((p7si = PKCS7_SIGNER_INFO_new()) == NULL)
1595*7f2fe78bSCy Schubert             goto cleanup;
1596*7f2fe78bSCy Schubert         if (!ASN1_INTEGER_set(p7si->version, 1))
1597*7f2fe78bSCy Schubert             goto cleanup;
1598*7f2fe78bSCy Schubert         if (!X509_NAME_set(&p7si->issuer_and_serial->issuer,
1599*7f2fe78bSCy Schubert                            X509_get_issuer_name(cert)))
1600*7f2fe78bSCy Schubert             goto cleanup;
1601*7f2fe78bSCy Schubert         /* because ASN1_INTEGER_set is used to set a 'long' we will do
1602*7f2fe78bSCy Schubert          * things the ugly way. */
1603*7f2fe78bSCy Schubert         ASN1_INTEGER_free(p7si->issuer_and_serial->serial);
1604*7f2fe78bSCy Schubert         if (!(p7si->issuer_and_serial->serial =
1605*7f2fe78bSCy Schubert               ASN1_INTEGER_dup(X509_get_serialNumber(cert))))
1606*7f2fe78bSCy Schubert             goto cleanup;
1607*7f2fe78bSCy Schubert 
1608*7f2fe78bSCy Schubert         /* will not fill-out EVP_PKEY because it's on the smartcard */
1609*7f2fe78bSCy Schubert 
1610*7f2fe78bSCy Schubert         /* Set digest algs */
1611*7f2fe78bSCy Schubert         p7si->digest_alg->algorithm = OBJ_nid2obj(NID_sha256);
1612*7f2fe78bSCy Schubert 
1613*7f2fe78bSCy Schubert         if (p7si->digest_alg->parameter != NULL)
1614*7f2fe78bSCy Schubert             ASN1_TYPE_free(p7si->digest_alg->parameter);
1615*7f2fe78bSCy Schubert         if ((p7si->digest_alg->parameter = ASN1_TYPE_new()) == NULL)
1616*7f2fe78bSCy Schubert             goto cleanup;
1617*7f2fe78bSCy Schubert         p7si->digest_alg->parameter->type = V_ASN1_NULL;
1618*7f2fe78bSCy Schubert 
1619*7f2fe78bSCy Schubert         /* Set sig algs */
1620*7f2fe78bSCy Schubert         if (p7si->digest_enc_alg->parameter != NULL)
1621*7f2fe78bSCy Schubert             ASN1_TYPE_free(p7si->digest_enc_alg->parameter);
1622*7f2fe78bSCy Schubert         p7si->digest_enc_alg->algorithm =
1623*7f2fe78bSCy Schubert             OBJ_nid2obj(NID_sha256WithRSAEncryption);
1624*7f2fe78bSCy Schubert         if (!(p7si->digest_enc_alg->parameter = ASN1_TYPE_new()))
1625*7f2fe78bSCy Schubert             goto cleanup;
1626*7f2fe78bSCy Schubert         p7si->digest_enc_alg->parameter->type = V_ASN1_NULL;
1627*7f2fe78bSCy Schubert 
1628*7f2fe78bSCy Schubert         /* add signed attributes */
1629*7f2fe78bSCy Schubert         /* compute sha256 digest over the EncapsulatedContentInfo */
1630*7f2fe78bSCy Schubert         ctx = EVP_MD_CTX_new();
1631*7f2fe78bSCy Schubert         if (ctx == NULL)
1632*7f2fe78bSCy Schubert             goto cleanup;
1633*7f2fe78bSCy Schubert         EVP_DigestInit_ex(ctx, EVP_sha256(), NULL);
1634*7f2fe78bSCy Schubert         EVP_DigestUpdate(ctx, data, data_len);
1635*7f2fe78bSCy Schubert         md_tmp = EVP_MD_CTX_get0_md(ctx);
1636*7f2fe78bSCy Schubert         EVP_DigestFinal_ex(ctx, md_data, &md_len);
1637*7f2fe78bSCy Schubert         EVP_MD_CTX_free(ctx);
1638*7f2fe78bSCy Schubert 
1639*7f2fe78bSCy Schubert         /* create a message digest attr */
1640*7f2fe78bSCy Schubert         digest_attr = ASN1_OCTET_STRING_new();
1641*7f2fe78bSCy Schubert         ASN1_OCTET_STRING_set(digest_attr, md_data, (int)md_len);
1642*7f2fe78bSCy Schubert         PKCS7_add_signed_attribute(p7si, NID_pkcs9_messageDigest,
1643*7f2fe78bSCy Schubert                                    V_ASN1_OCTET_STRING, (char *)digest_attr);
1644*7f2fe78bSCy Schubert 
1645*7f2fe78bSCy Schubert         /* create a content-type attr */
1646*7f2fe78bSCy Schubert         oid_copy = OBJ_dup(oid);
1647*7f2fe78bSCy Schubert         if (oid_copy == NULL)
1648*7f2fe78bSCy Schubert             goto cleanup2;
1649*7f2fe78bSCy Schubert         PKCS7_add_signed_attribute(p7si, NID_pkcs9_contentType,
1650*7f2fe78bSCy Schubert                                    V_ASN1_OBJECT, oid_copy);
1651*7f2fe78bSCy Schubert 
1652*7f2fe78bSCy Schubert         /* create the signature over signed attributes. get DER encoded value */
1653*7f2fe78bSCy Schubert         /* This is the place where smartcard signature needs to be calculated */
1654*7f2fe78bSCy Schubert         sk = p7si->auth_attr;
1655*7f2fe78bSCy Schubert         alen = ASN1_item_i2d((ASN1_VALUE *)sk, &abuf,
1656*7f2fe78bSCy Schubert                              ASN1_ITEM_rptr(PKCS7_ATTR_SIGN));
1657*7f2fe78bSCy Schubert         if (abuf == NULL)
1658*7f2fe78bSCy Schubert             goto cleanup2;
1659*7f2fe78bSCy Schubert 
1660*7f2fe78bSCy Schubert #ifndef WITHOUT_PKCS11
1661*7f2fe78bSCy Schubert         /*
1662*7f2fe78bSCy Schubert          * Some tokens can only do RSAEncryption without a hash.  To compute
1663*7f2fe78bSCy Schubert          * sha256WithRSAEncryption, encode the algorithm ID for the hash
1664*7f2fe78bSCy Schubert          * function and the hash value into an ASN.1 value of type DigestInfo:
1665*7f2fe78bSCy Schubert          * DigestInfo ::= SEQUENCE {
1666*7f2fe78bSCy Schubert          *   digestAlgorithm  AlgorithmIdentifier,
1667*7f2fe78bSCy Schubert          *   digest  OCTET STRING
1668*7f2fe78bSCy Schubert          * }
1669*7f2fe78bSCy Schubert          */
1670*7f2fe78bSCy Schubert         if (id_cryptoctx->pkcs11_method == 1 &&
1671*7f2fe78bSCy Schubert             id_cryptoctx->mech == CKM_RSA_PKCS) {
1672*7f2fe78bSCy Schubert             pkiDebug("mech = CKM_RSA_PKCS\n");
1673*7f2fe78bSCy Schubert             ctx = EVP_MD_CTX_new();
1674*7f2fe78bSCy Schubert             if (ctx == NULL)
1675*7f2fe78bSCy Schubert                 goto cleanup;
1676*7f2fe78bSCy Schubert             EVP_DigestInit_ex(ctx, md_tmp, NULL);
1677*7f2fe78bSCy Schubert             EVP_DigestUpdate(ctx, abuf, alen);
1678*7f2fe78bSCy Schubert             EVP_DigestFinal_ex(ctx, md_data2, &md_len2);
1679*7f2fe78bSCy Schubert             EVP_MD_CTX_free(ctx);
1680*7f2fe78bSCy Schubert 
1681*7f2fe78bSCy Schubert             alg = X509_ALGOR_new();
1682*7f2fe78bSCy Schubert             if (alg == NULL)
1683*7f2fe78bSCy Schubert                 goto cleanup2;
1684*7f2fe78bSCy Schubert             X509_ALGOR_set0(alg, OBJ_nid2obj(NID_sha256), V_ASN1_NULL, NULL);
1685*7f2fe78bSCy Schubert             alg_len = i2d_X509_ALGOR(alg, NULL);
1686*7f2fe78bSCy Schubert 
1687*7f2fe78bSCy Schubert             digest = ASN1_OCTET_STRING_new();
1688*7f2fe78bSCy Schubert             if (digest == NULL)
1689*7f2fe78bSCy Schubert                 goto cleanup2;
1690*7f2fe78bSCy Schubert             ASN1_OCTET_STRING_set(digest, md_data2, (int)md_len2);
1691*7f2fe78bSCy Schubert             digest_len = i2d_ASN1_OCTET_STRING(digest, NULL);
1692*7f2fe78bSCy Schubert 
1693*7f2fe78bSCy Schubert             digestInfo_len = ASN1_object_size(1, (int)(alg_len + digest_len),
1694*7f2fe78bSCy Schubert                                               V_ASN1_SEQUENCE);
1695*7f2fe78bSCy Schubert             y = digestInfo_buf = malloc(digestInfo_len);
1696*7f2fe78bSCy Schubert             if (digestInfo_buf == NULL)
1697*7f2fe78bSCy Schubert                 goto cleanup2;
1698*7f2fe78bSCy Schubert             ASN1_put_object(&y, 1, (int)(alg_len + digest_len), V_ASN1_SEQUENCE,
1699*7f2fe78bSCy Schubert                             V_ASN1_UNIVERSAL);
1700*7f2fe78bSCy Schubert             i2d_X509_ALGOR(alg, &y);
1701*7f2fe78bSCy Schubert             i2d_ASN1_OCTET_STRING(digest, &y);
1702*7f2fe78bSCy Schubert #ifdef DEBUG_SIG
1703*7f2fe78bSCy Schubert             pkiDebug("signing buffer\n");
1704*7f2fe78bSCy Schubert             print_buffer(digestInfo_buf, digestInfo_len);
1705*7f2fe78bSCy Schubert             print_buffer_bin(digestInfo_buf, digestInfo_len, "/tmp/pkcs7_tosign");
1706*7f2fe78bSCy Schubert #endif
1707*7f2fe78bSCy Schubert             retval = pkinit_sign_data(context, id_cryptoctx, digestInfo_buf,
1708*7f2fe78bSCy Schubert                                       digestInfo_len, &sig, &sig_len);
1709*7f2fe78bSCy Schubert         } else
1710*7f2fe78bSCy Schubert #endif
1711*7f2fe78bSCy Schubert         {
1712*7f2fe78bSCy Schubert             pkiDebug("mech = %s\n",
1713*7f2fe78bSCy Schubert                      id_cryptoctx->pkcs11_method == 1 ? "CKM_SHA256_RSA_PKCS" : "FS");
1714*7f2fe78bSCy Schubert             retval = pkinit_sign_data(context, id_cryptoctx, abuf, alen,
1715*7f2fe78bSCy Schubert                                       &sig, &sig_len);
1716*7f2fe78bSCy Schubert         }
1717*7f2fe78bSCy Schubert #ifdef DEBUG_SIG
1718*7f2fe78bSCy Schubert         print_buffer(sig, sig_len);
1719*7f2fe78bSCy Schubert #endif
1720*7f2fe78bSCy Schubert         free(abuf);
1721*7f2fe78bSCy Schubert         if (retval)
1722*7f2fe78bSCy Schubert             goto cleanup2;
1723*7f2fe78bSCy Schubert 
1724*7f2fe78bSCy Schubert         /* Add signature */
1725*7f2fe78bSCy Schubert         if (!ASN1_STRING_set(p7si->enc_digest, (unsigned char *) sig,
1726*7f2fe78bSCy Schubert                              (int)sig_len)) {
1727*7f2fe78bSCy Schubert             retval = oerr(context, 0, _("Failed to add digest attribute"));
1728*7f2fe78bSCy Schubert             goto cleanup2;
1729*7f2fe78bSCy Schubert         }
1730*7f2fe78bSCy Schubert         /* adder signer_info to pkcs7 signed */
1731*7f2fe78bSCy Schubert         if (!PKCS7_add_signer(p7, p7si))
1732*7f2fe78bSCy Schubert             goto cleanup2;
1733*7f2fe78bSCy Schubert     } /* we have a certificate */
1734*7f2fe78bSCy Schubert 
1735*7f2fe78bSCy Schubert     /* start on adding data to the pkcs7 signed */
1736*7f2fe78bSCy Schubert     retval = create_contentinfo(context, oid, data, data_len, &inner_p7);
1737*7f2fe78bSCy Schubert     if (p7s->contents != NULL)
1738*7f2fe78bSCy Schubert         PKCS7_free(p7s->contents);
1739*7f2fe78bSCy Schubert     p7s->contents = inner_p7;
1740*7f2fe78bSCy Schubert 
1741*7f2fe78bSCy Schubert     *signed_data_len = i2d_PKCS7(p7, NULL);
1742*7f2fe78bSCy Schubert     if (!(*signed_data_len)) {
1743*7f2fe78bSCy Schubert         retval = oerr(context, 0, _("Failed to DER encode PKCS7"));
1744*7f2fe78bSCy Schubert         goto cleanup2;
1745*7f2fe78bSCy Schubert     }
1746*7f2fe78bSCy Schubert     retval = ENOMEM;
1747*7f2fe78bSCy Schubert     if ((p = *signed_data = malloc(*signed_data_len)) == NULL)
1748*7f2fe78bSCy Schubert         goto cleanup2;
1749*7f2fe78bSCy Schubert 
1750*7f2fe78bSCy Schubert     /* DER encode PKCS7 data */
1751*7f2fe78bSCy Schubert     retval = i2d_PKCS7(p7, &p);
1752*7f2fe78bSCy Schubert     if (!retval) {
1753*7f2fe78bSCy Schubert         retval = oerr(context, 0, _("Failed to DER encode PKCS7"));
1754*7f2fe78bSCy Schubert         goto cleanup2;
1755*7f2fe78bSCy Schubert     }
1756*7f2fe78bSCy Schubert     retval = 0;
1757*7f2fe78bSCy Schubert 
1758*7f2fe78bSCy Schubert #ifdef DEBUG_ASN1
1759*7f2fe78bSCy Schubert     if (cms_msg_type == CMS_SIGN_CLIENT) {
1760*7f2fe78bSCy Schubert         print_buffer_bin(*signed_data, *signed_data_len,
1761*7f2fe78bSCy Schubert                          "/tmp/client_pkcs7_signeddata");
1762*7f2fe78bSCy Schubert     } else {
1763*7f2fe78bSCy Schubert         print_buffer_bin(*signed_data, *signed_data_len,
1764*7f2fe78bSCy Schubert                          "/tmp/kdc_pkcs7_signeddata");
1765*7f2fe78bSCy Schubert     }
1766*7f2fe78bSCy Schubert #endif
1767*7f2fe78bSCy Schubert 
1768*7f2fe78bSCy Schubert cleanup2:
1769*7f2fe78bSCy Schubert     if (p7si) {
1770*7f2fe78bSCy Schubert #ifndef WITHOUT_PKCS11
1771*7f2fe78bSCy Schubert         if (id_cryptoctx->pkcs11_method == 1 &&
1772*7f2fe78bSCy Schubert             id_cryptoctx->mech == CKM_RSA_PKCS) {
1773*7f2fe78bSCy Schubert             free(digestInfo_buf);
1774*7f2fe78bSCy Schubert             if (digest != NULL)
1775*7f2fe78bSCy Schubert                 ASN1_OCTET_STRING_free(digest);
1776*7f2fe78bSCy Schubert         }
1777*7f2fe78bSCy Schubert #endif
1778*7f2fe78bSCy Schubert         if (alg != NULL)
1779*7f2fe78bSCy Schubert             X509_ALGOR_free(alg);
1780*7f2fe78bSCy Schubert     }
1781*7f2fe78bSCy Schubert cleanup:
1782*7f2fe78bSCy Schubert     if (p7 != NULL)
1783*7f2fe78bSCy Schubert         PKCS7_free(p7);
1784*7f2fe78bSCy Schubert     free(sig);
1785*7f2fe78bSCy Schubert 
1786*7f2fe78bSCy Schubert     return retval;
1787*7f2fe78bSCy Schubert }
1788*7f2fe78bSCy Schubert 
1789*7f2fe78bSCy Schubert krb5_error_code
cms_signeddata_verify(krb5_context context,pkinit_plg_crypto_context plgctx,pkinit_req_crypto_context reqctx,pkinit_identity_crypto_context idctx,int cms_msg_type,int require_crl_checking,unsigned char * signed_data,unsigned int signed_data_len,unsigned char ** data,unsigned int * data_len,unsigned char ** authz_data,unsigned int * authz_data_len,int * is_signed)1790*7f2fe78bSCy Schubert cms_signeddata_verify(krb5_context context,
1791*7f2fe78bSCy Schubert                       pkinit_plg_crypto_context plgctx,
1792*7f2fe78bSCy Schubert                       pkinit_req_crypto_context reqctx,
1793*7f2fe78bSCy Schubert                       pkinit_identity_crypto_context idctx,
1794*7f2fe78bSCy Schubert                       int cms_msg_type,
1795*7f2fe78bSCy Schubert                       int require_crl_checking,
1796*7f2fe78bSCy Schubert                       unsigned char *signed_data,
1797*7f2fe78bSCy Schubert                       unsigned int signed_data_len,
1798*7f2fe78bSCy Schubert                       unsigned char **data,
1799*7f2fe78bSCy Schubert                       unsigned int *data_len,
1800*7f2fe78bSCy Schubert                       unsigned char **authz_data,
1801*7f2fe78bSCy Schubert                       unsigned int *authz_data_len,
1802*7f2fe78bSCy Schubert                       int *is_signed)
1803*7f2fe78bSCy Schubert {
1804*7f2fe78bSCy Schubert     /*
1805*7f2fe78bSCy Schubert      * Warning: Since most openssl functions do not set retval, large chunks of
1806*7f2fe78bSCy Schubert      * this function assume that retval is always a failure and may go to
1807*7f2fe78bSCy Schubert      * cleanup without setting retval explicitly. Make sure retval is not set
1808*7f2fe78bSCy Schubert      * to 0 or errors such as signature verification failure may be converted
1809*7f2fe78bSCy Schubert      * to success with significant security consequences.
1810*7f2fe78bSCy Schubert      */
1811*7f2fe78bSCy Schubert     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
1812*7f2fe78bSCy Schubert     CMS_ContentInfo *cms = NULL;
1813*7f2fe78bSCy Schubert     BIO *out = NULL;
1814*7f2fe78bSCy Schubert     int flags = CMS_NO_SIGNER_CERT_VERIFY;
1815*7f2fe78bSCy Schubert     int valid_oid = 0;
1816*7f2fe78bSCy Schubert     unsigned int i = 0;
1817*7f2fe78bSCy Schubert     unsigned int vflags = 0, size = 0;
1818*7f2fe78bSCy Schubert     const unsigned char *p = signed_data;
1819*7f2fe78bSCy Schubert     STACK_OF(CMS_SignerInfo) *si_sk = NULL;
1820*7f2fe78bSCy Schubert     CMS_SignerInfo *si = NULL;
1821*7f2fe78bSCy Schubert     X509 *x = NULL;
1822*7f2fe78bSCy Schubert     X509_STORE *store = NULL;
1823*7f2fe78bSCy Schubert     X509_STORE_CTX *cert_ctx;
1824*7f2fe78bSCy Schubert     STACK_OF(X509) *signerCerts = NULL;
1825*7f2fe78bSCy Schubert     STACK_OF(X509) *intermediateCAs = NULL;
1826*7f2fe78bSCy Schubert     STACK_OF(X509_CRL) *signerRevoked = NULL;
1827*7f2fe78bSCy Schubert     STACK_OF(X509_CRL) *revoked = NULL;
1828*7f2fe78bSCy Schubert     STACK_OF(X509) *verified_chain = NULL;
1829*7f2fe78bSCy Schubert     ASN1_OBJECT *oid = NULL;
1830*7f2fe78bSCy Schubert     const ASN1_OBJECT *type = NULL, *etype = NULL;
1831*7f2fe78bSCy Schubert     ASN1_OCTET_STRING **octets;
1832*7f2fe78bSCy Schubert     krb5_external_principal_identifier **krb5_verified_chain = NULL;
1833*7f2fe78bSCy Schubert     krb5_data *authz = NULL;
1834*7f2fe78bSCy Schubert     char buf[DN_BUF_LEN];
1835*7f2fe78bSCy Schubert 
1836*7f2fe78bSCy Schubert #ifdef DEBUG_ASN1
1837*7f2fe78bSCy Schubert     print_buffer_bin(signed_data, signed_data_len,
1838*7f2fe78bSCy Schubert                      "/tmp/client_received_pkcs7_signeddata");
1839*7f2fe78bSCy Schubert #endif
1840*7f2fe78bSCy Schubert     if (is_signed)
1841*7f2fe78bSCy Schubert         *is_signed = 1;
1842*7f2fe78bSCy Schubert 
1843*7f2fe78bSCy Schubert     oid = pkinit_pkcs7type2oid(plgctx, cms_msg_type);
1844*7f2fe78bSCy Schubert     if (oid == NULL)
1845*7f2fe78bSCy Schubert         goto cleanup;
1846*7f2fe78bSCy Schubert 
1847*7f2fe78bSCy Schubert     /* decode received CMS message */
1848*7f2fe78bSCy Schubert     if ((cms = d2i_CMS_ContentInfo(NULL, &p, (int)signed_data_len)) == NULL) {
1849*7f2fe78bSCy Schubert         retval = oerr(context, 0, _("Failed to decode CMS message"));
1850*7f2fe78bSCy Schubert         goto cleanup;
1851*7f2fe78bSCy Schubert     }
1852*7f2fe78bSCy Schubert     etype = CMS_get0_eContentType(cms);
1853*7f2fe78bSCy Schubert 
1854*7f2fe78bSCy Schubert     /*
1855*7f2fe78bSCy Schubert      * Prior to 1.10 the MIT client incorrectly emitted the pkinit structure
1856*7f2fe78bSCy Schubert      * directly in a CMS ContentInfo rather than using SignedData with no
1857*7f2fe78bSCy Schubert      * signers. Handle that case.
1858*7f2fe78bSCy Schubert      */
1859*7f2fe78bSCy Schubert     type = CMS_get0_type(cms);
1860*7f2fe78bSCy Schubert     if (is_signed && !OBJ_cmp(type, oid)) {
1861*7f2fe78bSCy Schubert         unsigned char *d;
1862*7f2fe78bSCy Schubert         *is_signed = 0;
1863*7f2fe78bSCy Schubert         octets = CMS_get0_content(cms);
1864*7f2fe78bSCy Schubert         if (!octets || ((*octets)->type != V_ASN1_OCTET_STRING)) {
1865*7f2fe78bSCy Schubert             retval = KRB5KDC_ERR_PREAUTH_FAILED;
1866*7f2fe78bSCy Schubert             krb5_set_error_message(context, retval,
1867*7f2fe78bSCy Schubert                                    _("Invalid pkinit packet: octet string "
1868*7f2fe78bSCy Schubert                                      "expected"));
1869*7f2fe78bSCy Schubert             goto cleanup;
1870*7f2fe78bSCy Schubert         }
1871*7f2fe78bSCy Schubert         *data_len = ASN1_STRING_length(*octets);
1872*7f2fe78bSCy Schubert         d = malloc(*data_len);
1873*7f2fe78bSCy Schubert         if (d == NULL) {
1874*7f2fe78bSCy Schubert             retval = ENOMEM;
1875*7f2fe78bSCy Schubert             goto cleanup;
1876*7f2fe78bSCy Schubert         }
1877*7f2fe78bSCy Schubert         memcpy(d, ASN1_STRING_get0_data(*octets), *data_len);
1878*7f2fe78bSCy Schubert         *data = d;
1879*7f2fe78bSCy Schubert         goto out;
1880*7f2fe78bSCy Schubert     } else {
1881*7f2fe78bSCy Schubert         /* Verify that the received message is CMS SignedData message. */
1882*7f2fe78bSCy Schubert         if (OBJ_obj2nid(type) != NID_pkcs7_signed) {
1883*7f2fe78bSCy Schubert             pkiDebug("Expected id-signedData CMS msg (received type = %d)\n",
1884*7f2fe78bSCy Schubert                      OBJ_obj2nid(type));
1885*7f2fe78bSCy Schubert             krb5_set_error_message(context, retval, _("wrong oid\n"));
1886*7f2fe78bSCy Schubert             goto cleanup;
1887*7f2fe78bSCy Schubert         }
1888*7f2fe78bSCy Schubert     }
1889*7f2fe78bSCy Schubert 
1890*7f2fe78bSCy Schubert     /* setup to verify X509 certificate used to sign CMS message */
1891*7f2fe78bSCy Schubert     if (!(store = X509_STORE_new()))
1892*7f2fe78bSCy Schubert         goto cleanup;
1893*7f2fe78bSCy Schubert 
1894*7f2fe78bSCy Schubert     /* check if we are inforcing CRL checking */
1895*7f2fe78bSCy Schubert     vflags = X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL;
1896*7f2fe78bSCy Schubert     if (require_crl_checking)
1897*7f2fe78bSCy Schubert         X509_STORE_set_verify_cb(store, openssl_callback);
1898*7f2fe78bSCy Schubert     else
1899*7f2fe78bSCy Schubert         X509_STORE_set_verify_cb(store, openssl_callback_ignore_crls);
1900*7f2fe78bSCy Schubert     X509_STORE_set_flags(store, vflags);
1901*7f2fe78bSCy Schubert 
1902*7f2fe78bSCy Schubert     /*
1903*7f2fe78bSCy Schubert      * Get the signer's information from the CMS message.  Match signer ID
1904*7f2fe78bSCy Schubert      * against anchors and intermediate CAs in case no certs are present in the
1905*7f2fe78bSCy Schubert      * SignedData.  If we start sending kdcPkId values in requests, we'll need
1906*7f2fe78bSCy Schubert      * to match against the source of that information too.
1907*7f2fe78bSCy Schubert      */
1908*7f2fe78bSCy Schubert     CMS_set1_signers_certs(cms, NULL, 0);
1909*7f2fe78bSCy Schubert     CMS_set1_signers_certs(cms, idctx->trustedCAs, CMS_NOINTERN);
1910*7f2fe78bSCy Schubert     CMS_set1_signers_certs(cms, idctx->intermediateCAs, CMS_NOINTERN);
1911*7f2fe78bSCy Schubert     if (((si_sk = CMS_get0_SignerInfos(cms)) == NULL) ||
1912*7f2fe78bSCy Schubert         ((si = sk_CMS_SignerInfo_value(si_sk, 0)) == NULL)) {
1913*7f2fe78bSCy Schubert         /* Not actually signed; anonymous case */
1914*7f2fe78bSCy Schubert         if (!is_signed)
1915*7f2fe78bSCy Schubert             goto cleanup;
1916*7f2fe78bSCy Schubert         *is_signed = 0;
1917*7f2fe78bSCy Schubert         /* We cannot use CMS_dataInit because there may be no digest */
1918*7f2fe78bSCy Schubert         octets = CMS_get0_content(cms);
1919*7f2fe78bSCy Schubert         if (octets)
1920*7f2fe78bSCy Schubert             out = BIO_new_mem_buf((*octets)->data, (*octets)->length);
1921*7f2fe78bSCy Schubert         if (out == NULL)
1922*7f2fe78bSCy Schubert             goto cleanup;
1923*7f2fe78bSCy Schubert     } else {
1924*7f2fe78bSCy Schubert         CMS_SignerInfo_get0_algs(si, NULL, &x, NULL, NULL);
1925*7f2fe78bSCy Schubert         if (x == NULL)
1926*7f2fe78bSCy Schubert             goto cleanup;
1927*7f2fe78bSCy Schubert 
1928*7f2fe78bSCy Schubert         /* create available CRL information (get local CRLs and include CRLs
1929*7f2fe78bSCy Schubert          * received in the CMS message
1930*7f2fe78bSCy Schubert          */
1931*7f2fe78bSCy Schubert         signerRevoked = CMS_get1_crls(cms);
1932*7f2fe78bSCy Schubert         if (idctx->revoked == NULL)
1933*7f2fe78bSCy Schubert             revoked = signerRevoked;
1934*7f2fe78bSCy Schubert         else if (signerRevoked == NULL)
1935*7f2fe78bSCy Schubert             revoked = idctx->revoked;
1936*7f2fe78bSCy Schubert         else {
1937*7f2fe78bSCy Schubert             size = sk_X509_CRL_num(idctx->revoked);
1938*7f2fe78bSCy Schubert             revoked = sk_X509_CRL_new_null();
1939*7f2fe78bSCy Schubert             for (i = 0; i < size; i++)
1940*7f2fe78bSCy Schubert                 sk_X509_CRL_push(revoked, sk_X509_CRL_value(idctx->revoked, i));
1941*7f2fe78bSCy Schubert             size = sk_X509_CRL_num(signerRevoked);
1942*7f2fe78bSCy Schubert             for (i = 0; i < size; i++)
1943*7f2fe78bSCy Schubert                 sk_X509_CRL_push(revoked, sk_X509_CRL_value(signerRevoked, i));
1944*7f2fe78bSCy Schubert         }
1945*7f2fe78bSCy Schubert 
1946*7f2fe78bSCy Schubert         /* create available intermediate CAs chains (get local intermediateCAs and
1947*7f2fe78bSCy Schubert          * include the CA chain received in the CMS message
1948*7f2fe78bSCy Schubert          */
1949*7f2fe78bSCy Schubert         signerCerts = CMS_get1_certs(cms);
1950*7f2fe78bSCy Schubert         if (idctx->intermediateCAs == NULL)
1951*7f2fe78bSCy Schubert             intermediateCAs = signerCerts;
1952*7f2fe78bSCy Schubert         else if (signerCerts == NULL)
1953*7f2fe78bSCy Schubert             intermediateCAs = idctx->intermediateCAs;
1954*7f2fe78bSCy Schubert         else {
1955*7f2fe78bSCy Schubert             size = sk_X509_num(idctx->intermediateCAs);
1956*7f2fe78bSCy Schubert             intermediateCAs = sk_X509_new_null();
1957*7f2fe78bSCy Schubert             for (i = 0; i < size; i++) {
1958*7f2fe78bSCy Schubert                 sk_X509_push(intermediateCAs,
1959*7f2fe78bSCy Schubert                              sk_X509_value(idctx->intermediateCAs, i));
1960*7f2fe78bSCy Schubert             }
1961*7f2fe78bSCy Schubert             size = sk_X509_num(signerCerts);
1962*7f2fe78bSCy Schubert             for (i = 0; i < size; i++) {
1963*7f2fe78bSCy Schubert                 sk_X509_push(intermediateCAs, sk_X509_value(signerCerts, i));
1964*7f2fe78bSCy Schubert             }
1965*7f2fe78bSCy Schubert         }
1966*7f2fe78bSCy Schubert 
1967*7f2fe78bSCy Schubert         /* initialize x509 context with the received certificate and
1968*7f2fe78bSCy Schubert          * trusted and intermediate CA chains and CRLs
1969*7f2fe78bSCy Schubert          */
1970*7f2fe78bSCy Schubert         cert_ctx = X509_STORE_CTX_new();
1971*7f2fe78bSCy Schubert         if (cert_ctx == NULL)
1972*7f2fe78bSCy Schubert             goto cleanup;
1973*7f2fe78bSCy Schubert         if (!X509_STORE_CTX_init(cert_ctx, store, x, intermediateCAs))
1974*7f2fe78bSCy Schubert             goto cleanup;
1975*7f2fe78bSCy Schubert 
1976*7f2fe78bSCy Schubert         X509_STORE_CTX_set0_crls(cert_ctx, revoked);
1977*7f2fe78bSCy Schubert 
1978*7f2fe78bSCy Schubert         /* add trusted CAs certificates for cert verification */
1979*7f2fe78bSCy Schubert         if (idctx->trustedCAs != NULL)
1980*7f2fe78bSCy Schubert             X509_STORE_CTX_trusted_stack(cert_ctx, idctx->trustedCAs);
1981*7f2fe78bSCy Schubert         else {
1982*7f2fe78bSCy Schubert             pkiDebug("unable to find any trusted CAs\n");
1983*7f2fe78bSCy Schubert             goto cleanup;
1984*7f2fe78bSCy Schubert         }
1985*7f2fe78bSCy Schubert #ifdef DEBUG_CERTCHAIN
1986*7f2fe78bSCy Schubert         if (intermediateCAs != NULL) {
1987*7f2fe78bSCy Schubert             size = sk_X509_num(intermediateCAs);
1988*7f2fe78bSCy Schubert             pkiDebug("untrusted cert chain of size %d\n", size);
1989*7f2fe78bSCy Schubert             for (i = 0; i < size; i++) {
1990*7f2fe78bSCy Schubert                 X509_NAME_oneline(X509_get_subject_name(
1991*7f2fe78bSCy Schubert                                       sk_X509_value(intermediateCAs, i)), buf, sizeof(buf));
1992*7f2fe78bSCy Schubert                 pkiDebug("cert #%d: %s\n", i, buf);
1993*7f2fe78bSCy Schubert             }
1994*7f2fe78bSCy Schubert         }
1995*7f2fe78bSCy Schubert         if (idctx->trustedCAs != NULL) {
1996*7f2fe78bSCy Schubert             size = sk_X509_num(idctx->trustedCAs);
1997*7f2fe78bSCy Schubert             pkiDebug("trusted cert chain of size %d\n", size);
1998*7f2fe78bSCy Schubert             for (i = 0; i < size; i++) {
1999*7f2fe78bSCy Schubert                 X509_NAME_oneline(X509_get_subject_name(
2000*7f2fe78bSCy Schubert                                       sk_X509_value(idctx->trustedCAs, i)), buf, sizeof(buf));
2001*7f2fe78bSCy Schubert                 pkiDebug("cert #%d: %s\n", i, buf);
2002*7f2fe78bSCy Schubert             }
2003*7f2fe78bSCy Schubert         }
2004*7f2fe78bSCy Schubert         if (revoked != NULL) {
2005*7f2fe78bSCy Schubert             size = sk_X509_CRL_num(revoked);
2006*7f2fe78bSCy Schubert             pkiDebug("CRL chain of size %d\n", size);
2007*7f2fe78bSCy Schubert             for (i = 0; i < size; i++) {
2008*7f2fe78bSCy Schubert                 X509_CRL *crl = sk_X509_CRL_value(revoked, i);
2009*7f2fe78bSCy Schubert                 X509_NAME_oneline(X509_CRL_get_issuer(crl), buf, sizeof(buf));
2010*7f2fe78bSCy Schubert                 pkiDebug("crls by CA #%d: %s\n", i , buf);
2011*7f2fe78bSCy Schubert             }
2012*7f2fe78bSCy Schubert         }
2013*7f2fe78bSCy Schubert #endif
2014*7f2fe78bSCy Schubert 
2015*7f2fe78bSCy Schubert         i = X509_verify_cert(cert_ctx);
2016*7f2fe78bSCy Schubert         if (i <= 0) {
2017*7f2fe78bSCy Schubert             int j = X509_STORE_CTX_get_error(cert_ctx);
2018*7f2fe78bSCy Schubert             X509 *cert;
2019*7f2fe78bSCy Schubert 
2020*7f2fe78bSCy Schubert             cert = X509_STORE_CTX_get_current_cert(cert_ctx);
2021*7f2fe78bSCy Schubert             reqctx->received_cert = X509_dup(cert);
2022*7f2fe78bSCy Schubert             switch(j) {
2023*7f2fe78bSCy Schubert             case X509_V_ERR_CERT_REVOKED:
2024*7f2fe78bSCy Schubert                 retval = KRB5KDC_ERR_REVOKED_CERTIFICATE;
2025*7f2fe78bSCy Schubert                 break;
2026*7f2fe78bSCy Schubert             case X509_V_ERR_UNABLE_TO_GET_CRL:
2027*7f2fe78bSCy Schubert                 retval = KRB5KDC_ERR_REVOCATION_STATUS_UNKNOWN;
2028*7f2fe78bSCy Schubert                 break;
2029*7f2fe78bSCy Schubert             case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
2030*7f2fe78bSCy Schubert             case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
2031*7f2fe78bSCy Schubert                 retval = KRB5KDC_ERR_CANT_VERIFY_CERTIFICATE;
2032*7f2fe78bSCy Schubert                 break;
2033*7f2fe78bSCy Schubert             default:
2034*7f2fe78bSCy Schubert                 retval = KRB5KDC_ERR_INVALID_CERTIFICATE;
2035*7f2fe78bSCy Schubert             }
2036*7f2fe78bSCy Schubert             (void)oerr_cert(context, retval, cert_ctx,
2037*7f2fe78bSCy Schubert                             _("Failed to verify received certificate"));
2038*7f2fe78bSCy Schubert             if (reqctx->received_cert == NULL)
2039*7f2fe78bSCy Schubert                 strlcpy(buf, "(none)", sizeof(buf));
2040*7f2fe78bSCy Schubert             else
2041*7f2fe78bSCy Schubert                 X509_NAME_oneline(X509_get_subject_name(reqctx->received_cert),
2042*7f2fe78bSCy Schubert                                   buf, sizeof(buf));
2043*7f2fe78bSCy Schubert             pkiDebug("problem with cert DN = %s (error=%d) %s\n", buf, j,
2044*7f2fe78bSCy Schubert                      X509_verify_cert_error_string(j));
2045*7f2fe78bSCy Schubert #ifdef DEBUG_CERTCHAIN
2046*7f2fe78bSCy Schubert             size = sk_X509_num(signerCerts);
2047*7f2fe78bSCy Schubert             pkiDebug("received cert chain of size %d\n", size);
2048*7f2fe78bSCy Schubert             for (j = 0; j < size; j++) {
2049*7f2fe78bSCy Schubert                 X509 *tmp_cert = sk_X509_value(signerCerts, j);
2050*7f2fe78bSCy Schubert                 X509_NAME_oneline(X509_get_subject_name(tmp_cert), buf, sizeof(buf));
2051*7f2fe78bSCy Schubert                 pkiDebug("cert #%d: %s\n", j, buf);
2052*7f2fe78bSCy Schubert             }
2053*7f2fe78bSCy Schubert #endif
2054*7f2fe78bSCy Schubert         } else {
2055*7f2fe78bSCy Schubert             /* retrieve verified certificate chain */
2056*7f2fe78bSCy Schubert             if (cms_msg_type == CMS_SIGN_CLIENT)
2057*7f2fe78bSCy Schubert                 verified_chain = X509_STORE_CTX_get1_chain(cert_ctx);
2058*7f2fe78bSCy Schubert         }
2059*7f2fe78bSCy Schubert         X509_STORE_CTX_free(cert_ctx);
2060*7f2fe78bSCy Schubert         if (i <= 0)
2061*7f2fe78bSCy Schubert             goto cleanup;
2062*7f2fe78bSCy Schubert         out = BIO_new(BIO_s_mem());
2063*7f2fe78bSCy Schubert         if (CMS_verify(cms, NULL, store, NULL, out, flags) == 0) {
2064*7f2fe78bSCy Schubert             if (ERR_peek_last_error() == CMS_R_VERIFICATION_FAILURE)
2065*7f2fe78bSCy Schubert                 retval = KRB5KDC_ERR_INVALID_SIG;
2066*7f2fe78bSCy Schubert             else
2067*7f2fe78bSCy Schubert                 retval = KRB5KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED;
2068*7f2fe78bSCy Schubert             (void)oerr(context, retval, _("Failed to verify CMS message"));
2069*7f2fe78bSCy Schubert             goto cleanup;
2070*7f2fe78bSCy Schubert         }
2071*7f2fe78bSCy Schubert     } /* message was signed */
2072*7f2fe78bSCy Schubert     if (!OBJ_cmp(etype, oid))
2073*7f2fe78bSCy Schubert         valid_oid = 1;
2074*7f2fe78bSCy Schubert 
2075*7f2fe78bSCy Schubert     if (valid_oid)
2076*7f2fe78bSCy Schubert         pkiDebug("CMS Verification successful\n");
2077*7f2fe78bSCy Schubert     else {
2078*7f2fe78bSCy Schubert         pkiDebug("wrong oid in eContentType\n");
2079*7f2fe78bSCy Schubert         print_buffer(OBJ_get0_data(etype), OBJ_length(etype));
2080*7f2fe78bSCy Schubert         retval = KRB5KDC_ERR_PREAUTH_FAILED;
2081*7f2fe78bSCy Schubert         krb5_set_error_message(context, retval, "wrong oid\n");
2082*7f2fe78bSCy Schubert         goto cleanup;
2083*7f2fe78bSCy Schubert     }
2084*7f2fe78bSCy Schubert 
2085*7f2fe78bSCy Schubert     /* transfer the data from CMS message into return buffer */
2086*7f2fe78bSCy Schubert     for (size = 0;;) {
2087*7f2fe78bSCy Schubert         int remain;
2088*7f2fe78bSCy Schubert         retval = ENOMEM;
2089*7f2fe78bSCy Schubert         if ((*data = realloc(*data, size + 1024 * 10)) == NULL)
2090*7f2fe78bSCy Schubert             goto cleanup;
2091*7f2fe78bSCy Schubert         remain = BIO_read(out, &((*data)[size]), 1024 * 10);
2092*7f2fe78bSCy Schubert         if (remain <= 0)
2093*7f2fe78bSCy Schubert             break;
2094*7f2fe78bSCy Schubert         else
2095*7f2fe78bSCy Schubert             size += remain;
2096*7f2fe78bSCy Schubert     }
2097*7f2fe78bSCy Schubert     *data_len = size;
2098*7f2fe78bSCy Schubert 
2099*7f2fe78bSCy Schubert     if (x) {
2100*7f2fe78bSCy Schubert         reqctx->received_cert = X509_dup(x);
2101*7f2fe78bSCy Schubert 
2102*7f2fe78bSCy Schubert         /* generate authorization data */
2103*7f2fe78bSCy Schubert         if (cms_msg_type == CMS_SIGN_CLIENT) {
2104*7f2fe78bSCy Schubert 
2105*7f2fe78bSCy Schubert             if (authz_data == NULL || authz_data_len == NULL)
2106*7f2fe78bSCy Schubert                 goto out;
2107*7f2fe78bSCy Schubert 
2108*7f2fe78bSCy Schubert             *authz_data = NULL;
2109*7f2fe78bSCy Schubert             retval = create_identifiers_from_stack(verified_chain,
2110*7f2fe78bSCy Schubert                                                    &krb5_verified_chain);
2111*7f2fe78bSCy Schubert             if (retval) {
2112*7f2fe78bSCy Schubert                 pkiDebug("create_identifiers_from_stack failed\n");
2113*7f2fe78bSCy Schubert                 goto cleanup;
2114*7f2fe78bSCy Schubert             }
2115*7f2fe78bSCy Schubert 
2116*7f2fe78bSCy Schubert             retval = k5int_encode_krb5_td_trusted_certifiers((krb5_external_principal_identifier *const *)krb5_verified_chain, &authz);
2117*7f2fe78bSCy Schubert             if (retval) {
2118*7f2fe78bSCy Schubert                 pkiDebug("encode_krb5_td_trusted_certifiers failed\n");
2119*7f2fe78bSCy Schubert                 goto cleanup;
2120*7f2fe78bSCy Schubert             }
2121*7f2fe78bSCy Schubert #ifdef DEBUG_ASN1
2122*7f2fe78bSCy Schubert             print_buffer_bin((unsigned char *)authz->data, authz->length,
2123*7f2fe78bSCy Schubert                              "/tmp/kdc_ad_initial_verified_cas");
2124*7f2fe78bSCy Schubert #endif
2125*7f2fe78bSCy Schubert             *authz_data = malloc(authz->length);
2126*7f2fe78bSCy Schubert             if (*authz_data == NULL) {
2127*7f2fe78bSCy Schubert                 retval = ENOMEM;
2128*7f2fe78bSCy Schubert                 goto cleanup;
2129*7f2fe78bSCy Schubert             }
2130*7f2fe78bSCy Schubert             memcpy(*authz_data, authz->data, authz->length);
2131*7f2fe78bSCy Schubert             *authz_data_len = authz->length;
2132*7f2fe78bSCy Schubert         }
2133*7f2fe78bSCy Schubert     }
2134*7f2fe78bSCy Schubert out:
2135*7f2fe78bSCy Schubert     retval = 0;
2136*7f2fe78bSCy Schubert 
2137*7f2fe78bSCy Schubert cleanup:
2138*7f2fe78bSCy Schubert     if (out != NULL)
2139*7f2fe78bSCy Schubert         BIO_free(out);
2140*7f2fe78bSCy Schubert     if (store != NULL)
2141*7f2fe78bSCy Schubert         X509_STORE_free(store);
2142*7f2fe78bSCy Schubert     if (cms != NULL) {
2143*7f2fe78bSCy Schubert         if (signerCerts != NULL)
2144*7f2fe78bSCy Schubert             sk_X509_pop_free(signerCerts, X509_free);
2145*7f2fe78bSCy Schubert         if (idctx->intermediateCAs != NULL && signerCerts)
2146*7f2fe78bSCy Schubert             sk_X509_free(intermediateCAs);
2147*7f2fe78bSCy Schubert         if (signerRevoked != NULL)
2148*7f2fe78bSCy Schubert             sk_X509_CRL_pop_free(signerRevoked, X509_CRL_free);
2149*7f2fe78bSCy Schubert         if (idctx->revoked != NULL && signerRevoked)
2150*7f2fe78bSCy Schubert             sk_X509_CRL_free(revoked);
2151*7f2fe78bSCy Schubert         CMS_ContentInfo_free(cms);
2152*7f2fe78bSCy Schubert     }
2153*7f2fe78bSCy Schubert     if (verified_chain != NULL)
2154*7f2fe78bSCy Schubert         sk_X509_pop_free(verified_chain, X509_free);
2155*7f2fe78bSCy Schubert     if (krb5_verified_chain != NULL)
2156*7f2fe78bSCy Schubert         free_krb5_external_principal_identifier(&krb5_verified_chain);
2157*7f2fe78bSCy Schubert     if (authz != NULL)
2158*7f2fe78bSCy Schubert         krb5_free_data(context, authz);
2159*7f2fe78bSCy Schubert 
2160*7f2fe78bSCy Schubert     return retval;
2161*7f2fe78bSCy Schubert }
2162*7f2fe78bSCy Schubert 
2163*7f2fe78bSCy Schubert krb5_error_code
cms_envelopeddata_create(krb5_context context,pkinit_plg_crypto_context plgctx,pkinit_req_crypto_context reqctx,pkinit_identity_crypto_context idctx,krb5_preauthtype pa_type,unsigned char * key_pack,unsigned int key_pack_len,unsigned char ** out,unsigned int * out_len)2164*7f2fe78bSCy Schubert cms_envelopeddata_create(krb5_context context,
2165*7f2fe78bSCy Schubert                          pkinit_plg_crypto_context plgctx,
2166*7f2fe78bSCy Schubert                          pkinit_req_crypto_context reqctx,
2167*7f2fe78bSCy Schubert                          pkinit_identity_crypto_context idctx,
2168*7f2fe78bSCy Schubert                          krb5_preauthtype pa_type,
2169*7f2fe78bSCy Schubert                          unsigned char *key_pack,
2170*7f2fe78bSCy Schubert                          unsigned int key_pack_len,
2171*7f2fe78bSCy Schubert                          unsigned char **out,
2172*7f2fe78bSCy Schubert                          unsigned int *out_len)
2173*7f2fe78bSCy Schubert {
2174*7f2fe78bSCy Schubert 
2175*7f2fe78bSCy Schubert     krb5_error_code retval = ENOMEM;
2176*7f2fe78bSCy Schubert     PKCS7 *p7 = NULL;
2177*7f2fe78bSCy Schubert     BIO *in = NULL;
2178*7f2fe78bSCy Schubert     unsigned char *p = NULL, *signed_data = NULL, *enc_data = NULL;
2179*7f2fe78bSCy Schubert     int signed_data_len = 0, enc_data_len = 0, flags = PKCS7_BINARY;
2180*7f2fe78bSCy Schubert     STACK_OF(X509) *encerts = NULL;
2181*7f2fe78bSCy Schubert     const EVP_CIPHER *cipher = NULL;
2182*7f2fe78bSCy Schubert 
2183*7f2fe78bSCy Schubert     retval = cms_signeddata_create(context, plgctx, reqctx, idctx,
2184*7f2fe78bSCy Schubert                                    CMS_ENVEL_SERVER, key_pack, key_pack_len,
2185*7f2fe78bSCy Schubert                                    &signed_data,
2186*7f2fe78bSCy Schubert                                    (unsigned int *)&signed_data_len);
2187*7f2fe78bSCy Schubert     if (retval) {
2188*7f2fe78bSCy Schubert         pkiDebug("failed to create pkcs7 signed data\n");
2189*7f2fe78bSCy Schubert         goto cleanup;
2190*7f2fe78bSCy Schubert     }
2191*7f2fe78bSCy Schubert 
2192*7f2fe78bSCy Schubert     /* check we have client's certificate */
2193*7f2fe78bSCy Schubert     if (reqctx->received_cert == NULL) {
2194*7f2fe78bSCy Schubert         retval = KRB5KDC_ERR_PREAUTH_FAILED;
2195*7f2fe78bSCy Schubert         goto cleanup;
2196*7f2fe78bSCy Schubert     }
2197*7f2fe78bSCy Schubert     encerts = sk_X509_new_null();
2198*7f2fe78bSCy Schubert     sk_X509_push(encerts, reqctx->received_cert);
2199*7f2fe78bSCy Schubert 
2200*7f2fe78bSCy Schubert     cipher = EVP_des_ede3_cbc();
2201*7f2fe78bSCy Schubert     in = BIO_new(BIO_s_mem());
2202*7f2fe78bSCy Schubert     prepare_enc_data(signed_data, signed_data_len, &enc_data,
2203*7f2fe78bSCy Schubert                      &enc_data_len);
2204*7f2fe78bSCy Schubert     retval = BIO_write(in, enc_data, enc_data_len);
2205*7f2fe78bSCy Schubert     if (retval != enc_data_len) {
2206*7f2fe78bSCy Schubert         pkiDebug("BIO_write only wrote %d\n", retval);
2207*7f2fe78bSCy Schubert         goto cleanup;
2208*7f2fe78bSCy Schubert     }
2209*7f2fe78bSCy Schubert 
2210*7f2fe78bSCy Schubert     p7 = PKCS7_encrypt(encerts, in, cipher, flags);
2211*7f2fe78bSCy Schubert     if (p7 == NULL) {
2212*7f2fe78bSCy Schubert         retval = oerr(context, 0, _("Failed to encrypt PKCS7 object"));
2213*7f2fe78bSCy Schubert         goto cleanup;
2214*7f2fe78bSCy Schubert     }
2215*7f2fe78bSCy Schubert     p7->d.enveloped->enc_data->content_type = OBJ_nid2obj(NID_pkcs7_signed);
2216*7f2fe78bSCy Schubert 
2217*7f2fe78bSCy Schubert     *out_len = i2d_PKCS7(p7, NULL);
2218*7f2fe78bSCy Schubert     if (!*out_len || (p = *out = malloc(*out_len)) == NULL) {
2219*7f2fe78bSCy Schubert         retval = ENOMEM;
2220*7f2fe78bSCy Schubert         goto cleanup;
2221*7f2fe78bSCy Schubert     }
2222*7f2fe78bSCy Schubert     retval = i2d_PKCS7(p7, &p);
2223*7f2fe78bSCy Schubert     if (!retval) {
2224*7f2fe78bSCy Schubert         retval = oerr(context, 0, _("Failed to DER encode PKCS7"));
2225*7f2fe78bSCy Schubert         goto cleanup;
2226*7f2fe78bSCy Schubert     }
2227*7f2fe78bSCy Schubert     retval = 0;
2228*7f2fe78bSCy Schubert 
2229*7f2fe78bSCy Schubert #ifdef DEBUG_ASN1
2230*7f2fe78bSCy Schubert     print_buffer_bin(*out, *out_len, "/tmp/kdc_enveloped_data");
2231*7f2fe78bSCy Schubert #endif
2232*7f2fe78bSCy Schubert 
2233*7f2fe78bSCy Schubert cleanup:
2234*7f2fe78bSCy Schubert     if (p7 != NULL)
2235*7f2fe78bSCy Schubert         PKCS7_free(p7);
2236*7f2fe78bSCy Schubert     if (in != NULL)
2237*7f2fe78bSCy Schubert         BIO_free(in);
2238*7f2fe78bSCy Schubert     free(signed_data);
2239*7f2fe78bSCy Schubert     free(enc_data);
2240*7f2fe78bSCy Schubert     if (encerts != NULL)
2241*7f2fe78bSCy Schubert         sk_X509_free(encerts);
2242*7f2fe78bSCy Schubert 
2243*7f2fe78bSCy Schubert     return retval;
2244*7f2fe78bSCy Schubert }
2245*7f2fe78bSCy Schubert 
2246*7f2fe78bSCy Schubert krb5_error_code
cms_envelopeddata_verify(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,krb5_preauthtype pa_type,int require_crl_checking,unsigned char * enveloped_data,unsigned int enveloped_data_len,unsigned char ** data,unsigned int * data_len)2247*7f2fe78bSCy Schubert cms_envelopeddata_verify(krb5_context context,
2248*7f2fe78bSCy Schubert                          pkinit_plg_crypto_context plg_cryptoctx,
2249*7f2fe78bSCy Schubert                          pkinit_req_crypto_context req_cryptoctx,
2250*7f2fe78bSCy Schubert                          pkinit_identity_crypto_context id_cryptoctx,
2251*7f2fe78bSCy Schubert                          krb5_preauthtype pa_type,
2252*7f2fe78bSCy Schubert                          int require_crl_checking,
2253*7f2fe78bSCy Schubert                          unsigned char *enveloped_data,
2254*7f2fe78bSCy Schubert                          unsigned int enveloped_data_len,
2255*7f2fe78bSCy Schubert                          unsigned char **data,
2256*7f2fe78bSCy Schubert                          unsigned int *data_len)
2257*7f2fe78bSCy Schubert {
2258*7f2fe78bSCy Schubert     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
2259*7f2fe78bSCy Schubert     PKCS7 *p7 = NULL;
2260*7f2fe78bSCy Schubert     const unsigned char *p = enveloped_data;
2261*7f2fe78bSCy Schubert     unsigned int tmp_buf_len = 0, tmp_buf2_len = 0, vfy_buf_len = 0;
2262*7f2fe78bSCy Schubert     unsigned char *tmp_buf = NULL, *tmp_buf2 = NULL, *vfy_buf = NULL;
2263*7f2fe78bSCy Schubert 
2264*7f2fe78bSCy Schubert #ifdef DEBUG_ASN1
2265*7f2fe78bSCy Schubert     print_buffer_bin(enveloped_data, enveloped_data_len,
2266*7f2fe78bSCy Schubert                      "/tmp/client_envelopeddata");
2267*7f2fe78bSCy Schubert #endif
2268*7f2fe78bSCy Schubert     /* decode received PKCS7 message */
2269*7f2fe78bSCy Schubert     if ((p7 = d2i_PKCS7(NULL, &p, (int)enveloped_data_len)) == NULL) {
2270*7f2fe78bSCy Schubert         retval = oerr(context, 0, _("Failed to decode PKCS7"));
2271*7f2fe78bSCy Schubert         goto cleanup;
2272*7f2fe78bSCy Schubert     }
2273*7f2fe78bSCy Schubert 
2274*7f2fe78bSCy Schubert     /* verify that the received message is PKCS7 EnvelopedData message */
2275*7f2fe78bSCy Schubert     if (OBJ_obj2nid(p7->type) != NID_pkcs7_enveloped ||
2276*7f2fe78bSCy Schubert         p7->d.enveloped == NULL ||
2277*7f2fe78bSCy Schubert         p7->d.enveloped->enc_data->enc_data == NULL) {
2278*7f2fe78bSCy Schubert         pkiDebug("Expected id-enveloped PKCS7 msg (received type = %d)\n",
2279*7f2fe78bSCy Schubert                  OBJ_obj2nid(p7->type));
2280*7f2fe78bSCy Schubert         krb5_set_error_message(context, retval, "wrong oid\n");
2281*7f2fe78bSCy Schubert         goto cleanup;
2282*7f2fe78bSCy Schubert     }
2283*7f2fe78bSCy Schubert 
2284*7f2fe78bSCy Schubert     /* decrypt received PKCS7 message */
2285*7f2fe78bSCy Schubert     if (pkcs7_decrypt(context, id_cryptoctx, p7, &tmp_buf, &tmp_buf_len)) {
2286*7f2fe78bSCy Schubert         pkiDebug("PKCS7 decryption successful\n");
2287*7f2fe78bSCy Schubert     } else {
2288*7f2fe78bSCy Schubert         retval = oerr(context, 0, _("Failed to decrypt PKCS7 message"));
2289*7f2fe78bSCy Schubert         goto cleanup;
2290*7f2fe78bSCy Schubert     }
2291*7f2fe78bSCy Schubert 
2292*7f2fe78bSCy Schubert #ifdef DEBUG_ASN1
2293*7f2fe78bSCy Schubert     print_buffer_bin(tmp_buf, tmp_buf_len, "/tmp/client_enc_keypack");
2294*7f2fe78bSCy Schubert #endif
2295*7f2fe78bSCy Schubert     /* verify PKCS7 SignedData message */
2296*7f2fe78bSCy Schubert     /* Wrap the signed data to make decoding easier in the verify routine. */
2297*7f2fe78bSCy Schubert     retval = wrap_signeddata(tmp_buf, tmp_buf_len, &tmp_buf2, &tmp_buf2_len);
2298*7f2fe78bSCy Schubert     if (retval) {
2299*7f2fe78bSCy Schubert         pkiDebug("failed to encode signeddata\n");
2300*7f2fe78bSCy Schubert         goto cleanup;
2301*7f2fe78bSCy Schubert     }
2302*7f2fe78bSCy Schubert     vfy_buf = tmp_buf2;
2303*7f2fe78bSCy Schubert     vfy_buf_len = tmp_buf2_len;
2304*7f2fe78bSCy Schubert 
2305*7f2fe78bSCy Schubert #ifdef DEBUG_ASN1
2306*7f2fe78bSCy Schubert     print_buffer_bin(vfy_buf, vfy_buf_len, "/tmp/client_enc_keypack2");
2307*7f2fe78bSCy Schubert #endif
2308*7f2fe78bSCy Schubert 
2309*7f2fe78bSCy Schubert     retval = cms_signeddata_verify(context, plg_cryptoctx, req_cryptoctx,
2310*7f2fe78bSCy Schubert                                    id_cryptoctx, CMS_ENVEL_SERVER,
2311*7f2fe78bSCy Schubert                                    require_crl_checking,
2312*7f2fe78bSCy Schubert                                    vfy_buf, vfy_buf_len,
2313*7f2fe78bSCy Schubert                                    data, data_len, NULL, NULL, NULL);
2314*7f2fe78bSCy Schubert 
2315*7f2fe78bSCy Schubert     if (!retval)
2316*7f2fe78bSCy Schubert         pkiDebug("PKCS7 Verification Success\n");
2317*7f2fe78bSCy Schubert     else {
2318*7f2fe78bSCy Schubert         pkiDebug("PKCS7 Verification Failure\n");
2319*7f2fe78bSCy Schubert         goto cleanup;
2320*7f2fe78bSCy Schubert     }
2321*7f2fe78bSCy Schubert 
2322*7f2fe78bSCy Schubert     retval = 0;
2323*7f2fe78bSCy Schubert 
2324*7f2fe78bSCy Schubert cleanup:
2325*7f2fe78bSCy Schubert 
2326*7f2fe78bSCy Schubert     if (p7 != NULL)
2327*7f2fe78bSCy Schubert         PKCS7_free(p7);
2328*7f2fe78bSCy Schubert     free(tmp_buf);
2329*7f2fe78bSCy Schubert     free(tmp_buf2);
2330*7f2fe78bSCy Schubert 
2331*7f2fe78bSCy Schubert     return retval;
2332*7f2fe78bSCy Schubert }
2333*7f2fe78bSCy Schubert 
2334*7f2fe78bSCy Schubert static krb5_error_code
crypto_retrieve_X509_sans(krb5_context context,pkinit_plg_crypto_context plgctx,pkinit_req_crypto_context reqctx,X509 * cert,krb5_principal ** princs_ret,char *** upn_ret,unsigned char *** dns_ret)2335*7f2fe78bSCy Schubert crypto_retrieve_X509_sans(krb5_context context,
2336*7f2fe78bSCy Schubert                           pkinit_plg_crypto_context plgctx,
2337*7f2fe78bSCy Schubert                           pkinit_req_crypto_context reqctx,
2338*7f2fe78bSCy Schubert                           X509 *cert,
2339*7f2fe78bSCy Schubert                           krb5_principal **princs_ret, char ***upn_ret,
2340*7f2fe78bSCy Schubert                           unsigned char ***dns_ret)
2341*7f2fe78bSCy Schubert {
2342*7f2fe78bSCy Schubert     krb5_error_code retval = EINVAL;
2343*7f2fe78bSCy Schubert     char buf[DN_BUF_LEN];
2344*7f2fe78bSCy Schubert     int p = 0, u = 0, d = 0, ret = 0, l;
2345*7f2fe78bSCy Schubert     krb5_principal *princs = NULL;
2346*7f2fe78bSCy Schubert     char **upns = NULL;
2347*7f2fe78bSCy Schubert     unsigned char **dnss = NULL;
2348*7f2fe78bSCy Schubert     unsigned int i, num_sans = 0;
2349*7f2fe78bSCy Schubert     X509_EXTENSION *ext = NULL;
2350*7f2fe78bSCy Schubert     GENERAL_NAMES *ialt = NULL;
2351*7f2fe78bSCy Schubert     GENERAL_NAME *gen = NULL;
2352*7f2fe78bSCy Schubert 
2353*7f2fe78bSCy Schubert     if (princs_ret != NULL)
2354*7f2fe78bSCy Schubert         *princs_ret = NULL;
2355*7f2fe78bSCy Schubert     if (upn_ret != NULL)
2356*7f2fe78bSCy Schubert         *upn_ret = NULL;
2357*7f2fe78bSCy Schubert     if (dns_ret != NULL)
2358*7f2fe78bSCy Schubert         *dns_ret = NULL;
2359*7f2fe78bSCy Schubert 
2360*7f2fe78bSCy Schubert     if (princs_ret == NULL && upn_ret == NULL && dns_ret == NULL) {
2361*7f2fe78bSCy Schubert         pkiDebug("%s: nowhere to return any values!\n", __FUNCTION__);
2362*7f2fe78bSCy Schubert         return retval;
2363*7f2fe78bSCy Schubert     }
2364*7f2fe78bSCy Schubert 
2365*7f2fe78bSCy Schubert     if (cert == NULL) {
2366*7f2fe78bSCy Schubert         pkiDebug("%s: no certificate!\n", __FUNCTION__);
2367*7f2fe78bSCy Schubert         return retval;
2368*7f2fe78bSCy Schubert     }
2369*7f2fe78bSCy Schubert 
2370*7f2fe78bSCy Schubert     X509_NAME_oneline(X509_get_subject_name(cert),
2371*7f2fe78bSCy Schubert                       buf, sizeof(buf));
2372*7f2fe78bSCy Schubert 
2373*7f2fe78bSCy Schubert     l = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1);
2374*7f2fe78bSCy Schubert     if (l < 0)
2375*7f2fe78bSCy Schubert         return 0;
2376*7f2fe78bSCy Schubert 
2377*7f2fe78bSCy Schubert     if (!(ext = X509_get_ext(cert, l)) || !(ialt = X509V3_EXT_d2i(ext))) {
2378*7f2fe78bSCy Schubert         TRACE_PKINIT_SAN_CERT_NONE(context, buf);
2379*7f2fe78bSCy Schubert         goto cleanup;
2380*7f2fe78bSCy Schubert     }
2381*7f2fe78bSCy Schubert     num_sans = sk_GENERAL_NAME_num(ialt);
2382*7f2fe78bSCy Schubert 
2383*7f2fe78bSCy Schubert     /* OK, we're likely returning something. Allocate return values */
2384*7f2fe78bSCy Schubert     if (princs_ret != NULL) {
2385*7f2fe78bSCy Schubert         princs = calloc(num_sans + 1, sizeof(krb5_principal));
2386*7f2fe78bSCy Schubert         if (princs == NULL) {
2387*7f2fe78bSCy Schubert             retval = ENOMEM;
2388*7f2fe78bSCy Schubert             goto cleanup;
2389*7f2fe78bSCy Schubert         }
2390*7f2fe78bSCy Schubert     }
2391*7f2fe78bSCy Schubert     if (upn_ret != NULL) {
2392*7f2fe78bSCy Schubert         upns = calloc(num_sans + 1, sizeof(*upns));
2393*7f2fe78bSCy Schubert         if (upns == NULL) {
2394*7f2fe78bSCy Schubert             retval = ENOMEM;
2395*7f2fe78bSCy Schubert             goto cleanup;
2396*7f2fe78bSCy Schubert         }
2397*7f2fe78bSCy Schubert     }
2398*7f2fe78bSCy Schubert     if (dns_ret != NULL) {
2399*7f2fe78bSCy Schubert         dnss = calloc(num_sans + 1, sizeof(*dnss));
2400*7f2fe78bSCy Schubert         if (dnss == NULL) {
2401*7f2fe78bSCy Schubert             retval = ENOMEM;
2402*7f2fe78bSCy Schubert             goto cleanup;
2403*7f2fe78bSCy Schubert         }
2404*7f2fe78bSCy Schubert     }
2405*7f2fe78bSCy Schubert 
2406*7f2fe78bSCy Schubert     for (i = 0; i < num_sans; i++) {
2407*7f2fe78bSCy Schubert         krb5_data name = { 0, 0, NULL };
2408*7f2fe78bSCy Schubert 
2409*7f2fe78bSCy Schubert         gen = sk_GENERAL_NAME_value(ialt, i);
2410*7f2fe78bSCy Schubert         switch (gen->type) {
2411*7f2fe78bSCy Schubert         case GEN_OTHERNAME:
2412*7f2fe78bSCy Schubert             name.length = gen->d.otherName->value->value.sequence->length;
2413*7f2fe78bSCy Schubert             name.data = (char *)gen->d.otherName->value->value.sequence->data;
2414*7f2fe78bSCy Schubert             if (princs != NULL &&
2415*7f2fe78bSCy Schubert                 OBJ_cmp(plgctx->id_pkinit_san,
2416*7f2fe78bSCy Schubert                         gen->d.otherName->type_id) == 0) {
2417*7f2fe78bSCy Schubert #ifdef DEBUG_ASN1
2418*7f2fe78bSCy Schubert                 print_buffer_bin((unsigned char *)name.data, name.length,
2419*7f2fe78bSCy Schubert                                  "/tmp/pkinit_san");
2420*7f2fe78bSCy Schubert #endif
2421*7f2fe78bSCy Schubert                 ret = k5int_decode_krb5_principal_name(&name, &princs[p]);
2422*7f2fe78bSCy Schubert                 if (ret) {
2423*7f2fe78bSCy Schubert                     pkiDebug("%s: failed decoding pkinit san value\n",
2424*7f2fe78bSCy Schubert                              __FUNCTION__);
2425*7f2fe78bSCy Schubert                 } else {
2426*7f2fe78bSCy Schubert                     p++;
2427*7f2fe78bSCy Schubert                 }
2428*7f2fe78bSCy Schubert             } else if (upns != NULL &&
2429*7f2fe78bSCy Schubert                        OBJ_cmp(plgctx->id_ms_san_upn,
2430*7f2fe78bSCy Schubert                                gen->d.otherName->type_id) == 0) {
2431*7f2fe78bSCy Schubert                 /* Prevent abuse of embedded null characters. */
2432*7f2fe78bSCy Schubert                 if (memchr(name.data, '\0', name.length))
2433*7f2fe78bSCy Schubert                     break;
2434*7f2fe78bSCy Schubert                 upns[u] = k5memdup0(name.data, name.length, &ret);
2435*7f2fe78bSCy Schubert                 if (upns[u] == NULL)
2436*7f2fe78bSCy Schubert                     goto cleanup;
2437*7f2fe78bSCy Schubert                 u++;
2438*7f2fe78bSCy Schubert             } else {
2439*7f2fe78bSCy Schubert                 pkiDebug("%s: unrecognized othername oid in SAN\n",
2440*7f2fe78bSCy Schubert                          __FUNCTION__);
2441*7f2fe78bSCy Schubert                 continue;
2442*7f2fe78bSCy Schubert             }
2443*7f2fe78bSCy Schubert 
2444*7f2fe78bSCy Schubert             break;
2445*7f2fe78bSCy Schubert         case GEN_DNS:
2446*7f2fe78bSCy Schubert             if (dnss != NULL) {
2447*7f2fe78bSCy Schubert                 /* Prevent abuse of embedded null characters. */
2448*7f2fe78bSCy Schubert                 if (memchr(gen->d.dNSName->data, '\0', gen->d.dNSName->length))
2449*7f2fe78bSCy Schubert                     break;
2450*7f2fe78bSCy Schubert                 pkiDebug("%s: found dns name = %s\n", __FUNCTION__,
2451*7f2fe78bSCy Schubert                          gen->d.dNSName->data);
2452*7f2fe78bSCy Schubert                 dnss[d] = (unsigned char *)
2453*7f2fe78bSCy Schubert                     strdup((char *)gen->d.dNSName->data);
2454*7f2fe78bSCy Schubert                 if (dnss[d] == NULL) {
2455*7f2fe78bSCy Schubert                     pkiDebug("%s: failed to duplicate dns name\n",
2456*7f2fe78bSCy Schubert                              __FUNCTION__);
2457*7f2fe78bSCy Schubert                 } else {
2458*7f2fe78bSCy Schubert                     d++;
2459*7f2fe78bSCy Schubert                 }
2460*7f2fe78bSCy Schubert             }
2461*7f2fe78bSCy Schubert             break;
2462*7f2fe78bSCy Schubert         default:
2463*7f2fe78bSCy Schubert             pkiDebug("%s: SAN type = %d expecting %d\n", __FUNCTION__,
2464*7f2fe78bSCy Schubert                      gen->type, GEN_OTHERNAME);
2465*7f2fe78bSCy Schubert         }
2466*7f2fe78bSCy Schubert     }
2467*7f2fe78bSCy Schubert     sk_GENERAL_NAME_pop_free(ialt, GENERAL_NAME_free);
2468*7f2fe78bSCy Schubert 
2469*7f2fe78bSCy Schubert     TRACE_PKINIT_SAN_CERT_COUNT(context, (int)num_sans, p, u, d, buf);
2470*7f2fe78bSCy Schubert 
2471*7f2fe78bSCy Schubert     retval = 0;
2472*7f2fe78bSCy Schubert     if (princs != NULL && *princs != NULL) {
2473*7f2fe78bSCy Schubert         *princs_ret = princs;
2474*7f2fe78bSCy Schubert         princs = NULL;
2475*7f2fe78bSCy Schubert     }
2476*7f2fe78bSCy Schubert     if (upns != NULL && *upns != NULL) {
2477*7f2fe78bSCy Schubert         *upn_ret = upns;
2478*7f2fe78bSCy Schubert         upns = NULL;
2479*7f2fe78bSCy Schubert     }
2480*7f2fe78bSCy Schubert     if (dnss != NULL && *dnss != NULL) {
2481*7f2fe78bSCy Schubert         *dns_ret = dnss;
2482*7f2fe78bSCy Schubert         dnss = NULL;
2483*7f2fe78bSCy Schubert     }
2484*7f2fe78bSCy Schubert 
2485*7f2fe78bSCy Schubert cleanup:
2486*7f2fe78bSCy Schubert     for (i = 0; princs != NULL && princs[i] != NULL; i++)
2487*7f2fe78bSCy Schubert         krb5_free_principal(context, princs[i]);
2488*7f2fe78bSCy Schubert     free(princs);
2489*7f2fe78bSCy Schubert     for (i = 0; upns != NULL && upns[i] != NULL; i++)
2490*7f2fe78bSCy Schubert         free(upns[i]);
2491*7f2fe78bSCy Schubert     free(upns);
2492*7f2fe78bSCy Schubert     for (i = 0; dnss != NULL && dnss[i] != NULL; i++)
2493*7f2fe78bSCy Schubert         free(dnss[i]);
2494*7f2fe78bSCy Schubert     free(dnss);
2495*7f2fe78bSCy Schubert     return retval;
2496*7f2fe78bSCy Schubert }
2497*7f2fe78bSCy Schubert 
2498*7f2fe78bSCy Schubert krb5_error_code
crypto_retrieve_signer_identity(krb5_context context,pkinit_identity_crypto_context id_cryptoctx,const char ** identity)2499*7f2fe78bSCy Schubert crypto_retrieve_signer_identity(krb5_context context,
2500*7f2fe78bSCy Schubert                                 pkinit_identity_crypto_context id_cryptoctx,
2501*7f2fe78bSCy Schubert                                 const char **identity)
2502*7f2fe78bSCy Schubert {
2503*7f2fe78bSCy Schubert     *identity = id_cryptoctx->identity;
2504*7f2fe78bSCy Schubert     if (*identity == NULL)
2505*7f2fe78bSCy Schubert         return ENOENT;
2506*7f2fe78bSCy Schubert     return 0;
2507*7f2fe78bSCy Schubert }
2508*7f2fe78bSCy Schubert 
2509*7f2fe78bSCy Schubert krb5_error_code
crypto_retrieve_cert_sans(krb5_context context,pkinit_plg_crypto_context plgctx,pkinit_req_crypto_context reqctx,pkinit_identity_crypto_context idctx,krb5_principal ** princs_ret,char *** upn_ret,unsigned char *** dns_ret)2510*7f2fe78bSCy Schubert crypto_retrieve_cert_sans(krb5_context context,
2511*7f2fe78bSCy Schubert                           pkinit_plg_crypto_context plgctx,
2512*7f2fe78bSCy Schubert                           pkinit_req_crypto_context reqctx,
2513*7f2fe78bSCy Schubert                           pkinit_identity_crypto_context idctx,
2514*7f2fe78bSCy Schubert                           krb5_principal **princs_ret, char ***upn_ret,
2515*7f2fe78bSCy Schubert                           unsigned char ***dns_ret)
2516*7f2fe78bSCy Schubert {
2517*7f2fe78bSCy Schubert     krb5_error_code retval = EINVAL;
2518*7f2fe78bSCy Schubert 
2519*7f2fe78bSCy Schubert     if (reqctx->received_cert == NULL) {
2520*7f2fe78bSCy Schubert         pkiDebug("%s: No certificate!\n", __FUNCTION__);
2521*7f2fe78bSCy Schubert         return retval;
2522*7f2fe78bSCy Schubert     }
2523*7f2fe78bSCy Schubert 
2524*7f2fe78bSCy Schubert     return crypto_retrieve_X509_sans(context, plgctx, reqctx,
2525*7f2fe78bSCy Schubert                                      reqctx->received_cert, princs_ret,
2526*7f2fe78bSCy Schubert                                      upn_ret, dns_ret);
2527*7f2fe78bSCy Schubert }
2528*7f2fe78bSCy Schubert 
2529*7f2fe78bSCy Schubert krb5_error_code
crypto_check_cert_eku(krb5_context context,pkinit_plg_crypto_context plgctx,pkinit_req_crypto_context reqctx,pkinit_identity_crypto_context idctx,int checking_kdc_cert,int allow_secondary_usage,int * valid_eku)2530*7f2fe78bSCy Schubert crypto_check_cert_eku(krb5_context context,
2531*7f2fe78bSCy Schubert                       pkinit_plg_crypto_context plgctx,
2532*7f2fe78bSCy Schubert                       pkinit_req_crypto_context reqctx,
2533*7f2fe78bSCy Schubert                       pkinit_identity_crypto_context idctx,
2534*7f2fe78bSCy Schubert                       int checking_kdc_cert,
2535*7f2fe78bSCy Schubert                       int allow_secondary_usage,
2536*7f2fe78bSCy Schubert                       int *valid_eku)
2537*7f2fe78bSCy Schubert {
2538*7f2fe78bSCy Schubert     char buf[DN_BUF_LEN];
2539*7f2fe78bSCy Schubert     int found_eku = 0;
2540*7f2fe78bSCy Schubert     krb5_error_code retval = EINVAL;
2541*7f2fe78bSCy Schubert     int i;
2542*7f2fe78bSCy Schubert 
2543*7f2fe78bSCy Schubert     *valid_eku = 0;
2544*7f2fe78bSCy Schubert     if (reqctx->received_cert == NULL)
2545*7f2fe78bSCy Schubert         goto cleanup;
2546*7f2fe78bSCy Schubert 
2547*7f2fe78bSCy Schubert     X509_NAME_oneline(X509_get_subject_name(reqctx->received_cert),
2548*7f2fe78bSCy Schubert                       buf, sizeof(buf));
2549*7f2fe78bSCy Schubert 
2550*7f2fe78bSCy Schubert     if ((i = X509_get_ext_by_NID(reqctx->received_cert,
2551*7f2fe78bSCy Schubert                                  NID_ext_key_usage, -1)) >= 0) {
2552*7f2fe78bSCy Schubert         EXTENDED_KEY_USAGE *extusage;
2553*7f2fe78bSCy Schubert 
2554*7f2fe78bSCy Schubert         extusage = X509_get_ext_d2i(reqctx->received_cert, NID_ext_key_usage,
2555*7f2fe78bSCy Schubert                                     NULL, NULL);
2556*7f2fe78bSCy Schubert         if (extusage) {
2557*7f2fe78bSCy Schubert             pkiDebug("%s: found eku info in the cert\n", __FUNCTION__);
2558*7f2fe78bSCy Schubert             for (i = 0; found_eku == 0 && i < sk_ASN1_OBJECT_num(extusage); i++) {
2559*7f2fe78bSCy Schubert                 ASN1_OBJECT *tmp_oid;
2560*7f2fe78bSCy Schubert 
2561*7f2fe78bSCy Schubert                 tmp_oid = sk_ASN1_OBJECT_value(extusage, i);
2562*7f2fe78bSCy Schubert                 pkiDebug("%s: checking eku %d of %d, allow_secondary = %d\n",
2563*7f2fe78bSCy Schubert                          __FUNCTION__, i+1, sk_ASN1_OBJECT_num(extusage),
2564*7f2fe78bSCy Schubert                          allow_secondary_usage);
2565*7f2fe78bSCy Schubert                 if (checking_kdc_cert) {
2566*7f2fe78bSCy Schubert                     if ((OBJ_cmp(tmp_oid, plgctx->id_pkinit_KPKdc) == 0)
2567*7f2fe78bSCy Schubert                         || (allow_secondary_usage
2568*7f2fe78bSCy Schubert                             && OBJ_cmp(tmp_oid, plgctx->id_kp_serverAuth) == 0))
2569*7f2fe78bSCy Schubert                         found_eku = 1;
2570*7f2fe78bSCy Schubert                 } else {
2571*7f2fe78bSCy Schubert                     if ((OBJ_cmp(tmp_oid, plgctx->id_pkinit_KPClientAuth) == 0)
2572*7f2fe78bSCy Schubert                         || (allow_secondary_usage
2573*7f2fe78bSCy Schubert                             && OBJ_cmp(tmp_oid, plgctx->id_ms_kp_sc_logon) == 0))
2574*7f2fe78bSCy Schubert                         found_eku = 1;
2575*7f2fe78bSCy Schubert                 }
2576*7f2fe78bSCy Schubert             }
2577*7f2fe78bSCy Schubert         }
2578*7f2fe78bSCy Schubert         EXTENDED_KEY_USAGE_free(extusage);
2579*7f2fe78bSCy Schubert 
2580*7f2fe78bSCy Schubert         if (found_eku) {
2581*7f2fe78bSCy Schubert             ASN1_BIT_STRING *usage = NULL;
2582*7f2fe78bSCy Schubert 
2583*7f2fe78bSCy Schubert             /* check that digitalSignature KeyUsage is present */
2584*7f2fe78bSCy Schubert             X509_check_ca(reqctx->received_cert);
2585*7f2fe78bSCy Schubert             if ((usage = X509_get_ext_d2i(reqctx->received_cert,
2586*7f2fe78bSCy Schubert                                           NID_key_usage, NULL, NULL))) {
2587*7f2fe78bSCy Schubert 
2588*7f2fe78bSCy Schubert                 if (!ku_reject(reqctx->received_cert,
2589*7f2fe78bSCy Schubert                                X509v3_KU_DIGITAL_SIGNATURE)) {
2590*7f2fe78bSCy Schubert                     TRACE_PKINIT_EKU(context);
2591*7f2fe78bSCy Schubert                     *valid_eku = 1;
2592*7f2fe78bSCy Schubert                 } else
2593*7f2fe78bSCy Schubert                     TRACE_PKINIT_EKU_NO_KU(context);
2594*7f2fe78bSCy Schubert             }
2595*7f2fe78bSCy Schubert             ASN1_BIT_STRING_free(usage);
2596*7f2fe78bSCy Schubert         }
2597*7f2fe78bSCy Schubert     }
2598*7f2fe78bSCy Schubert     retval = 0;
2599*7f2fe78bSCy Schubert cleanup:
2600*7f2fe78bSCy Schubert     pkiDebug("%s: returning retval %d, valid_eku %d\n",
2601*7f2fe78bSCy Schubert              __FUNCTION__, retval, *valid_eku);
2602*7f2fe78bSCy Schubert     return retval;
2603*7f2fe78bSCy Schubert }
2604*7f2fe78bSCy Schubert 
2605*7f2fe78bSCy Schubert krb5_error_code
pkinit_octetstring2key(krb5_context context,krb5_enctype etype,unsigned char * key,unsigned int dh_key_len,krb5_keyblock * key_block)2606*7f2fe78bSCy Schubert pkinit_octetstring2key(krb5_context context,
2607*7f2fe78bSCy Schubert                        krb5_enctype etype,
2608*7f2fe78bSCy Schubert                        unsigned char *key,
2609*7f2fe78bSCy Schubert                        unsigned int dh_key_len,
2610*7f2fe78bSCy Schubert                        krb5_keyblock *key_block)
2611*7f2fe78bSCy Schubert {
2612*7f2fe78bSCy Schubert     krb5_error_code retval;
2613*7f2fe78bSCy Schubert     unsigned char *buf = NULL;
2614*7f2fe78bSCy Schubert     unsigned char md[SHA_DIGEST_LENGTH];
2615*7f2fe78bSCy Schubert     unsigned char counter;
2616*7f2fe78bSCy Schubert     size_t keybytes, keylength, offset;
2617*7f2fe78bSCy Schubert     krb5_data random_data;
2618*7f2fe78bSCy Schubert     EVP_MD_CTX *sha1_ctx = NULL;
2619*7f2fe78bSCy Schubert 
2620*7f2fe78bSCy Schubert     buf = k5alloc(dh_key_len, &retval);
2621*7f2fe78bSCy Schubert     if (buf == NULL)
2622*7f2fe78bSCy Schubert         goto cleanup;
2623*7f2fe78bSCy Schubert 
2624*7f2fe78bSCy Schubert     sha1_ctx = EVP_MD_CTX_new();
2625*7f2fe78bSCy Schubert     if (sha1_ctx == NULL) {
2626*7f2fe78bSCy Schubert         retval = KRB5_CRYPTO_INTERNAL;
2627*7f2fe78bSCy Schubert         goto cleanup;
2628*7f2fe78bSCy Schubert     }
2629*7f2fe78bSCy Schubert 
2630*7f2fe78bSCy Schubert     counter = 0;
2631*7f2fe78bSCy Schubert     offset = 0;
2632*7f2fe78bSCy Schubert     do {
2633*7f2fe78bSCy Schubert         if (!EVP_DigestInit(sha1_ctx, EVP_sha1()) ||
2634*7f2fe78bSCy Schubert             !EVP_DigestUpdate(sha1_ctx, &counter, 1) ||
2635*7f2fe78bSCy Schubert             !EVP_DigestUpdate(sha1_ctx, key, dh_key_len) ||
2636*7f2fe78bSCy Schubert             !EVP_DigestFinal(sha1_ctx, md, NULL)) {
2637*7f2fe78bSCy Schubert             retval = KRB5_CRYPTO_INTERNAL;
2638*7f2fe78bSCy Schubert             goto cleanup;
2639*7f2fe78bSCy Schubert         }
2640*7f2fe78bSCy Schubert 
2641*7f2fe78bSCy Schubert         if (dh_key_len - offset < sizeof(md))
2642*7f2fe78bSCy Schubert             memcpy(buf + offset, md, dh_key_len - offset);
2643*7f2fe78bSCy Schubert         else
2644*7f2fe78bSCy Schubert             memcpy(buf + offset, md, sizeof(md));
2645*7f2fe78bSCy Schubert 
2646*7f2fe78bSCy Schubert         offset += sizeof(md);
2647*7f2fe78bSCy Schubert         counter++;
2648*7f2fe78bSCy Schubert     } while (offset < dh_key_len);
2649*7f2fe78bSCy Schubert 
2650*7f2fe78bSCy Schubert     key_block->magic = 0;
2651*7f2fe78bSCy Schubert     key_block->enctype = etype;
2652*7f2fe78bSCy Schubert 
2653*7f2fe78bSCy Schubert     retval = krb5_c_keylengths(context, etype, &keybytes, &keylength);
2654*7f2fe78bSCy Schubert     if (retval)
2655*7f2fe78bSCy Schubert         goto cleanup;
2656*7f2fe78bSCy Schubert 
2657*7f2fe78bSCy Schubert     key_block->length = keylength;
2658*7f2fe78bSCy Schubert     key_block->contents = k5alloc(keylength, &retval);
2659*7f2fe78bSCy Schubert     if (key_block->contents == NULL)
2660*7f2fe78bSCy Schubert         goto cleanup;
2661*7f2fe78bSCy Schubert 
2662*7f2fe78bSCy Schubert     random_data.length = keybytes;
2663*7f2fe78bSCy Schubert     random_data.data = (char *)buf;
2664*7f2fe78bSCy Schubert 
2665*7f2fe78bSCy Schubert     retval = krb5_c_random_to_key(context, etype, &random_data, key_block);
2666*7f2fe78bSCy Schubert 
2667*7f2fe78bSCy Schubert cleanup:
2668*7f2fe78bSCy Schubert     EVP_MD_CTX_free(sha1_ctx);
2669*7f2fe78bSCy Schubert     free(buf);
2670*7f2fe78bSCy Schubert     /* If this is an error return, free the allocated keyblock, if any */
2671*7f2fe78bSCy Schubert     if (retval) {
2672*7f2fe78bSCy Schubert         krb5_free_keyblock_contents(context, key_block);
2673*7f2fe78bSCy Schubert     }
2674*7f2fe78bSCy Schubert 
2675*7f2fe78bSCy Schubert     return retval;
2676*7f2fe78bSCy Schubert }
2677*7f2fe78bSCy Schubert 
2678*7f2fe78bSCy Schubert 
2679*7f2fe78bSCy Schubert /* Return the OpenSSL descriptor for the given RFC 5652 OID specified in RFC
2680*7f2fe78bSCy Schubert  * 8636.  RFC 8636 defines a SHA384 variant, but we don't use it. */
2681*7f2fe78bSCy Schubert static const EVP_MD *
algid_to_md(const krb5_data * alg_id)2682*7f2fe78bSCy Schubert algid_to_md(const krb5_data *alg_id)
2683*7f2fe78bSCy Schubert {
2684*7f2fe78bSCy Schubert     if (data_eq(*alg_id, sha1_id))
2685*7f2fe78bSCy Schubert         return EVP_sha1();
2686*7f2fe78bSCy Schubert     if (data_eq(*alg_id, sha256_id))
2687*7f2fe78bSCy Schubert         return EVP_sha256();
2688*7f2fe78bSCy Schubert     if (data_eq(*alg_id, sha512_id))
2689*7f2fe78bSCy Schubert         return EVP_sha512();
2690*7f2fe78bSCy Schubert     return NULL;
2691*7f2fe78bSCy Schubert }
2692*7f2fe78bSCy Schubert 
2693*7f2fe78bSCy Schubert #if OPENSSL_VERSION_NUMBER >= 0x30000000L
2694*7f2fe78bSCy Schubert 
2695*7f2fe78bSCy Schubert #define sskdf openssl_sskdf
2696*7f2fe78bSCy Schubert static krb5_error_code
openssl_sskdf(krb5_context context,const EVP_MD * md,krb5_data * key,krb5_data * info,size_t len,krb5_data * out)2697*7f2fe78bSCy Schubert openssl_sskdf(krb5_context context, const EVP_MD *md, krb5_data *key,
2698*7f2fe78bSCy Schubert               krb5_data *info, size_t len, krb5_data *out)
2699*7f2fe78bSCy Schubert {
2700*7f2fe78bSCy Schubert     krb5_error_code ret;
2701*7f2fe78bSCy Schubert     EVP_KDF *kdf = NULL;
2702*7f2fe78bSCy Schubert     EVP_KDF_CTX *kctx = NULL;
2703*7f2fe78bSCy Schubert     OSSL_PARAM params[4], *p = params;
2704*7f2fe78bSCy Schubert 
2705*7f2fe78bSCy Schubert     ret = alloc_data(out, len);
2706*7f2fe78bSCy Schubert     if (ret)
2707*7f2fe78bSCy Schubert         goto cleanup;
2708*7f2fe78bSCy Schubert 
2709*7f2fe78bSCy Schubert     kdf = EVP_KDF_fetch(NULL, "SSKDF", NULL);
2710*7f2fe78bSCy Schubert     if (kdf == NULL) {
2711*7f2fe78bSCy Schubert         ret = oerr(context, KRB5_CRYPTO_INTERNAL, _("Failed to fetch SSKDF"));
2712*7f2fe78bSCy Schubert         goto cleanup;
2713*7f2fe78bSCy Schubert     }
2714*7f2fe78bSCy Schubert 
2715*7f2fe78bSCy Schubert     kctx = EVP_KDF_CTX_new(kdf);
2716*7f2fe78bSCy Schubert     if (!kctx) {
2717*7f2fe78bSCy Schubert         ret = oerr(context, KRB5_CRYPTO_INTERNAL,
2718*7f2fe78bSCy Schubert                    _("Failed to instantiate SSKDF"));
2719*7f2fe78bSCy Schubert         goto cleanup;
2720*7f2fe78bSCy Schubert     }
2721*7f2fe78bSCy Schubert 
2722*7f2fe78bSCy Schubert     *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST,
2723*7f2fe78bSCy Schubert                                             (char *)EVP_MD_get0_name(md), 0);
2724*7f2fe78bSCy Schubert     *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY,
2725*7f2fe78bSCy Schubert                                              key->data, key->length);
2726*7f2fe78bSCy Schubert     *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO,
2727*7f2fe78bSCy Schubert                                              info->data, info->length);
2728*7f2fe78bSCy Schubert     *p = OSSL_PARAM_construct_end();
2729*7f2fe78bSCy Schubert     if (EVP_KDF_derive(kctx, (uint8_t *)out->data, len, params) <= 0) {
2730*7f2fe78bSCy Schubert         ret = oerr(context, KRB5_CRYPTO_INTERNAL,
2731*7f2fe78bSCy Schubert                    _("Failed to derive key using SSKDF"));
2732*7f2fe78bSCy Schubert         goto cleanup;
2733*7f2fe78bSCy Schubert     }
2734*7f2fe78bSCy Schubert 
2735*7f2fe78bSCy Schubert     ret = 0;
2736*7f2fe78bSCy Schubert 
2737*7f2fe78bSCy Schubert cleanup:
2738*7f2fe78bSCy Schubert     EVP_KDF_free(kdf);
2739*7f2fe78bSCy Schubert     EVP_KDF_CTX_free(kctx);
2740*7f2fe78bSCy Schubert     return ret;
2741*7f2fe78bSCy Schubert }
2742*7f2fe78bSCy Schubert 
2743*7f2fe78bSCy Schubert #else /* OPENSSL_VERSION_NUMBER < 0x30000000L */
2744*7f2fe78bSCy Schubert 
2745*7f2fe78bSCy Schubert #define sskdf builtin_sskdf
2746*7f2fe78bSCy Schubert static krb5_error_code
builtin_sskdf(krb5_context context,const EVP_MD * md,krb5_data * key,krb5_data * info,size_t len,krb5_data * out)2747*7f2fe78bSCy Schubert builtin_sskdf(krb5_context context, const EVP_MD *md, krb5_data *key,
2748*7f2fe78bSCy Schubert               krb5_data *info, size_t len, krb5_data *out)
2749*7f2fe78bSCy Schubert {
2750*7f2fe78bSCy Schubert     krb5_error_code ret;
2751*7f2fe78bSCy Schubert     uint32_t counter = 1, reps;
2752*7f2fe78bSCy Schubert     uint8_t be_counter[4], *outptr;
2753*7f2fe78bSCy Schubert     EVP_MD_CTX *ctx = NULL;
2754*7f2fe78bSCy Schubert     unsigned int s, hash_len;
2755*7f2fe78bSCy Schubert 
2756*7f2fe78bSCy Schubert     hash_len = EVP_MD_size(md);
2757*7f2fe78bSCy Schubert 
2758*7f2fe78bSCy Schubert     /* 1.  reps = keydatalen (K) / hash length (H) rounded up. */
2759*7f2fe78bSCy Schubert     reps = (len + hash_len - 1) / hash_len;
2760*7f2fe78bSCy Schubert 
2761*7f2fe78bSCy Schubert     /* Allocate enough space in the random data buffer to hash directly into
2762*7f2fe78bSCy Schubert      * it, even if the last hash will make it bigger than the key length. */
2763*7f2fe78bSCy Schubert     ret = alloc_data(out, reps * hash_len);
2764*7f2fe78bSCy Schubert     if (ret)
2765*7f2fe78bSCy Schubert         goto cleanup;
2766*7f2fe78bSCy Schubert     out->length = len;
2767*7f2fe78bSCy Schubert 
2768*7f2fe78bSCy Schubert     /*
2769*7f2fe78bSCy Schubert      * 2.  Initialize a 32-bit, big-endian bit string counter as 1.
2770*7f2fe78bSCy Schubert      * 3.  For i = 1 to reps by 1, do the following:
2771*7f2fe78bSCy Schubert      *     -   Compute Hashi = H(counter || Z || OtherInfo).
2772*7f2fe78bSCy Schubert      *     -   Increment counter (modulo 2^32)
2773*7f2fe78bSCy Schubert      * 4.  Set key = Hash1 || Hash2 || ... so that length of key is K
2774*7f2fe78bSCy Schubert      *     bytes.
2775*7f2fe78bSCy Schubert      */
2776*7f2fe78bSCy Schubert     outptr = (uint8_t *)out->data;
2777*7f2fe78bSCy Schubert     for (counter = 1; counter <= reps; counter++) {
2778*7f2fe78bSCy Schubert         store_32_be(counter, be_counter);
2779*7f2fe78bSCy Schubert 
2780*7f2fe78bSCy Schubert         ctx = EVP_MD_CTX_new();
2781*7f2fe78bSCy Schubert         if (ctx == NULL) {
2782*7f2fe78bSCy Schubert             ret = KRB5_CRYPTO_INTERNAL;
2783*7f2fe78bSCy Schubert             goto cleanup;
2784*7f2fe78bSCy Schubert         }
2785*7f2fe78bSCy Schubert 
2786*7f2fe78bSCy Schubert         /* -   Compute Hashi = H(counter || Z || OtherInfo). */
2787*7f2fe78bSCy Schubert         if (!EVP_DigestInit(ctx, md) ||
2788*7f2fe78bSCy Schubert             !EVP_DigestUpdate(ctx, be_counter, 4) ||
2789*7f2fe78bSCy Schubert             !EVP_DigestUpdate(ctx, key->data, key->length) ||
2790*7f2fe78bSCy Schubert             !EVP_DigestUpdate(ctx, info->data, info->length) ||
2791*7f2fe78bSCy Schubert             !EVP_DigestFinal(ctx, outptr, &s)) {
2792*7f2fe78bSCy Schubert             ret = oerr(context, KRB5_CRYPTO_INTERNAL,
2793*7f2fe78bSCy Schubert                        _("Failed to compute digest"));
2794*7f2fe78bSCy Schubert             goto cleanup;
2795*7f2fe78bSCy Schubert         }
2796*7f2fe78bSCy Schubert 
2797*7f2fe78bSCy Schubert         assert(s == hash_len);
2798*7f2fe78bSCy Schubert         outptr += s;
2799*7f2fe78bSCy Schubert 
2800*7f2fe78bSCy Schubert         EVP_MD_CTX_free(ctx);
2801*7f2fe78bSCy Schubert         ctx = NULL;
2802*7f2fe78bSCy Schubert     }
2803*7f2fe78bSCy Schubert 
2804*7f2fe78bSCy Schubert cleanup:
2805*7f2fe78bSCy Schubert     EVP_MD_CTX_free(ctx);
2806*7f2fe78bSCy Schubert     return ret;
2807*7f2fe78bSCy Schubert }
2808*7f2fe78bSCy Schubert 
2809*7f2fe78bSCy Schubert #endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
2810*7f2fe78bSCy Schubert 
2811*7f2fe78bSCy Schubert /* id-pkinit-kdf family, as specified by RFC 8636. */
2812*7f2fe78bSCy Schubert krb5_error_code
pkinit_alg_agility_kdf(krb5_context context,krb5_data * secret,krb5_data * alg_oid,krb5_const_principal party_u_info,krb5_const_principal party_v_info,krb5_enctype enctype,krb5_data * as_req,krb5_data * pk_as_rep,krb5_keyblock * key_block)2813*7f2fe78bSCy Schubert pkinit_alg_agility_kdf(krb5_context context, krb5_data *secret,
2814*7f2fe78bSCy Schubert                        krb5_data *alg_oid, krb5_const_principal party_u_info,
2815*7f2fe78bSCy Schubert                        krb5_const_principal party_v_info,
2816*7f2fe78bSCy Schubert                        krb5_enctype enctype, krb5_data *as_req,
2817*7f2fe78bSCy Schubert                        krb5_data *pk_as_rep, krb5_keyblock *key_block)
2818*7f2fe78bSCy Schubert {
2819*7f2fe78bSCy Schubert     krb5_error_code ret;
2820*7f2fe78bSCy Schubert     size_t rand_len = 0, key_len = 0;
2821*7f2fe78bSCy Schubert     const EVP_MD *md;
2822*7f2fe78bSCy Schubert     krb5_sp80056a_other_info other_info_fields;
2823*7f2fe78bSCy Schubert     krb5_pkinit_supp_pub_info supp_pub_info_fields;
2824*7f2fe78bSCy Schubert     krb5_data *other_info = NULL, *supp_pub_info = NULL;
2825*7f2fe78bSCy Schubert     krb5_data random_data = empty_data();
2826*7f2fe78bSCy Schubert     krb5_algorithm_identifier alg_id;
2827*7f2fe78bSCy Schubert     char *hash_name = NULL;
2828*7f2fe78bSCy Schubert 
2829*7f2fe78bSCy Schubert     ret = krb5_c_keylengths(context, enctype, &rand_len, &key_len);
2830*7f2fe78bSCy Schubert     if (ret)
2831*7f2fe78bSCy Schubert         goto cleanup;
2832*7f2fe78bSCy Schubert 
2833*7f2fe78bSCy Schubert     /* Allocate and initialize the key block. */
2834*7f2fe78bSCy Schubert     key_block->magic = 0;
2835*7f2fe78bSCy Schubert     key_block->enctype = enctype;
2836*7f2fe78bSCy Schubert     key_block->length = key_len;
2837*7f2fe78bSCy Schubert     key_block->contents = k5calloc(key_block->length, 1, &ret);
2838*7f2fe78bSCy Schubert     if (key_block->contents == NULL)
2839*7f2fe78bSCy Schubert         goto cleanup;
2840*7f2fe78bSCy Schubert 
2841*7f2fe78bSCy Schubert     /* If this is anonymous pkinit, use the anonymous principle for
2842*7f2fe78bSCy Schubert      * party_u_info. */
2843*7f2fe78bSCy Schubert     if (party_u_info &&
2844*7f2fe78bSCy Schubert         krb5_principal_compare_any_realm(context, party_u_info,
2845*7f2fe78bSCy Schubert                                          krb5_anonymous_principal())) {
2846*7f2fe78bSCy Schubert         party_u_info = (krb5_principal)krb5_anonymous_principal();
2847*7f2fe78bSCy Schubert     }
2848*7f2fe78bSCy Schubert 
2849*7f2fe78bSCy Schubert     md = algid_to_md(alg_oid);
2850*7f2fe78bSCy Schubert     if (md == NULL) {
2851*7f2fe78bSCy Schubert         krb5_set_error_message(context, KRB5_ERR_BAD_S2K_PARAMS,
2852*7f2fe78bSCy Schubert                                "Bad algorithm ID passed to PK-INIT KDF.");
2853*7f2fe78bSCy Schubert         return KRB5_ERR_BAD_S2K_PARAMS;
2854*7f2fe78bSCy Schubert     }
2855*7f2fe78bSCy Schubert 
2856*7f2fe78bSCy Schubert     /* Encode the ASN.1 octet string for "SuppPubInfo". */
2857*7f2fe78bSCy Schubert     supp_pub_info_fields.enctype = enctype;
2858*7f2fe78bSCy Schubert     supp_pub_info_fields.as_req = *as_req;
2859*7f2fe78bSCy Schubert     supp_pub_info_fields.pk_as_rep = *pk_as_rep;
2860*7f2fe78bSCy Schubert     ret = encode_krb5_pkinit_supp_pub_info(&supp_pub_info_fields,
2861*7f2fe78bSCy Schubert                                            &supp_pub_info);
2862*7f2fe78bSCy Schubert     if (ret)
2863*7f2fe78bSCy Schubert         goto cleanup;
2864*7f2fe78bSCy Schubert 
2865*7f2fe78bSCy Schubert     /* Now encode the ASN.1 octet string for "OtherInfo". */
2866*7f2fe78bSCy Schubert     memset(&alg_id, 0, sizeof(alg_id));
2867*7f2fe78bSCy Schubert     alg_id.algorithm = *alg_oid;
2868*7f2fe78bSCy Schubert     other_info_fields.algorithm_identifier = alg_id;
2869*7f2fe78bSCy Schubert     other_info_fields.party_u_info = (krb5_principal)party_u_info;
2870*7f2fe78bSCy Schubert     other_info_fields.party_v_info = (krb5_principal)party_v_info;
2871*7f2fe78bSCy Schubert     other_info_fields.supp_pub_info = *supp_pub_info;
2872*7f2fe78bSCy Schubert     ret = encode_krb5_sp80056a_other_info(&other_info_fields, &other_info);
2873*7f2fe78bSCy Schubert     if (ret)
2874*7f2fe78bSCy Schubert         goto cleanup;
2875*7f2fe78bSCy Schubert 
2876*7f2fe78bSCy Schubert     ret = sskdf(context, md, secret, other_info, rand_len, &random_data);
2877*7f2fe78bSCy Schubert     if (ret)
2878*7f2fe78bSCy Schubert         goto cleanup;
2879*7f2fe78bSCy Schubert 
2880*7f2fe78bSCy Schubert     ret = krb5_c_random_to_key(context, enctype, &random_data, key_block);
2881*7f2fe78bSCy Schubert 
2882*7f2fe78bSCy Schubert cleanup:
2883*7f2fe78bSCy Schubert     if (ret)
2884*7f2fe78bSCy Schubert         krb5_free_keyblock_contents(context, key_block);
2885*7f2fe78bSCy Schubert     free(hash_name);
2886*7f2fe78bSCy Schubert     zapfree(random_data.data, random_data.length);
2887*7f2fe78bSCy Schubert     krb5_free_data(context, other_info);
2888*7f2fe78bSCy Schubert     krb5_free_data(context, supp_pub_info);
2889*7f2fe78bSCy Schubert     return ret;
2890*7f2fe78bSCy Schubert }
2891*7f2fe78bSCy Schubert 
2892*7f2fe78bSCy Schubert krb5_error_code
client_create_dh(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context cryptoctx,pkinit_identity_crypto_context id_cryptoctx,int dh_size,krb5_data * spki_out)2893*7f2fe78bSCy Schubert client_create_dh(krb5_context context,
2894*7f2fe78bSCy Schubert                  pkinit_plg_crypto_context plg_cryptoctx,
2895*7f2fe78bSCy Schubert                  pkinit_req_crypto_context cryptoctx,
2896*7f2fe78bSCy Schubert                  pkinit_identity_crypto_context id_cryptoctx,
2897*7f2fe78bSCy Schubert                  int dh_size, krb5_data *spki_out)
2898*7f2fe78bSCy Schubert {
2899*7f2fe78bSCy Schubert     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
2900*7f2fe78bSCy Schubert     EVP_PKEY *params = NULL, *pkey = NULL;
2901*7f2fe78bSCy Schubert 
2902*7f2fe78bSCy Schubert     *spki_out = empty_data();
2903*7f2fe78bSCy Schubert 
2904*7f2fe78bSCy Schubert     if (cryptoctx->received_params != NULL)
2905*7f2fe78bSCy Schubert         params = cryptoctx->received_params;
2906*7f2fe78bSCy Schubert     else if (dh_size == 1024)
2907*7f2fe78bSCy Schubert         params = plg_cryptoctx->dh_1024;
2908*7f2fe78bSCy Schubert     else if (dh_size == 2048)
2909*7f2fe78bSCy Schubert         params = plg_cryptoctx->dh_2048;
2910*7f2fe78bSCy Schubert     else if (dh_size == 4096)
2911*7f2fe78bSCy Schubert         params = plg_cryptoctx->dh_4096;
2912*7f2fe78bSCy Schubert     else
2913*7f2fe78bSCy Schubert         goto cleanup;
2914*7f2fe78bSCy Schubert 
2915*7f2fe78bSCy Schubert     pkey = generate_dh_pkey(params);
2916*7f2fe78bSCy Schubert     if (pkey == NULL)
2917*7f2fe78bSCy Schubert         goto cleanup;
2918*7f2fe78bSCy Schubert 
2919*7f2fe78bSCy Schubert     retval = encode_spki(pkey, spki_out);
2920*7f2fe78bSCy Schubert     if (retval)
2921*7f2fe78bSCy Schubert         goto cleanup;
2922*7f2fe78bSCy Schubert 
2923*7f2fe78bSCy Schubert     EVP_PKEY_free(cryptoctx->client_pkey);
2924*7f2fe78bSCy Schubert     cryptoctx->client_pkey = pkey;
2925*7f2fe78bSCy Schubert     pkey = NULL;
2926*7f2fe78bSCy Schubert 
2927*7f2fe78bSCy Schubert cleanup:
2928*7f2fe78bSCy Schubert     EVP_PKEY_free(pkey);
2929*7f2fe78bSCy Schubert     return retval;
2930*7f2fe78bSCy Schubert }
2931*7f2fe78bSCy Schubert 
2932*7f2fe78bSCy Schubert krb5_error_code
client_process_dh(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context cryptoctx,pkinit_identity_crypto_context id_cryptoctx,unsigned char * subjectPublicKey_data,unsigned int subjectPublicKey_length,unsigned char ** client_key_out,unsigned int * client_key_len_out)2933*7f2fe78bSCy Schubert client_process_dh(krb5_context context,
2934*7f2fe78bSCy Schubert                   pkinit_plg_crypto_context plg_cryptoctx,
2935*7f2fe78bSCy Schubert                   pkinit_req_crypto_context cryptoctx,
2936*7f2fe78bSCy Schubert                   pkinit_identity_crypto_context id_cryptoctx,
2937*7f2fe78bSCy Schubert                   unsigned char *subjectPublicKey_data,
2938*7f2fe78bSCy Schubert                   unsigned int subjectPublicKey_length,
2939*7f2fe78bSCy Schubert                   unsigned char **client_key_out,
2940*7f2fe78bSCy Schubert                   unsigned int *client_key_len_out)
2941*7f2fe78bSCy Schubert {
2942*7f2fe78bSCy Schubert     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
2943*7f2fe78bSCy Schubert     EVP_PKEY *server_pkey = NULL;
2944*7f2fe78bSCy Schubert     uint8_t *client_key = NULL;
2945*7f2fe78bSCy Schubert     unsigned int client_key_len;
2946*7f2fe78bSCy Schubert 
2947*7f2fe78bSCy Schubert     *client_key_out = NULL;
2948*7f2fe78bSCy Schubert     *client_key_len_out = 0;
2949*7f2fe78bSCy Schubert 
2950*7f2fe78bSCy Schubert     server_pkey = compose_dh_pkey(cryptoctx->client_pkey,
2951*7f2fe78bSCy Schubert                                   subjectPublicKey_data,
2952*7f2fe78bSCy Schubert                                   subjectPublicKey_length);
2953*7f2fe78bSCy Schubert     if (server_pkey == NULL)
2954*7f2fe78bSCy Schubert         goto cleanup;
2955*7f2fe78bSCy Schubert 
2956*7f2fe78bSCy Schubert     if (!dh_result(cryptoctx->client_pkey, server_pkey,
2957*7f2fe78bSCy Schubert                    &client_key, &client_key_len))
2958*7f2fe78bSCy Schubert         goto cleanup;
2959*7f2fe78bSCy Schubert 
2960*7f2fe78bSCy Schubert #ifdef DEBUG_DH
2961*7f2fe78bSCy Schubert     print_pubkey(server_pub_key, "server's pub_key=");
2962*7f2fe78bSCy Schubert     pkiDebug("client computed key (%d)= ", client_key_len);
2963*7f2fe78bSCy Schubert     print_buffer(client_key, client_key_len);
2964*7f2fe78bSCy Schubert #endif
2965*7f2fe78bSCy Schubert 
2966*7f2fe78bSCy Schubert     *client_key_out = client_key;
2967*7f2fe78bSCy Schubert     *client_key_len_out = client_key_len;
2968*7f2fe78bSCy Schubert     client_key = NULL;
2969*7f2fe78bSCy Schubert 
2970*7f2fe78bSCy Schubert     retval = 0;
2971*7f2fe78bSCy Schubert 
2972*7f2fe78bSCy Schubert cleanup:
2973*7f2fe78bSCy Schubert     EVP_PKEY_free(server_pkey);
2974*7f2fe78bSCy Schubert     free(client_key);
2975*7f2fe78bSCy Schubert     return retval;
2976*7f2fe78bSCy Schubert }
2977*7f2fe78bSCy Schubert 
2978*7f2fe78bSCy Schubert /* Return 1 if dh is a permitted well-known group, otherwise return 0. */
2979*7f2fe78bSCy Schubert static int
check_dh_wellknown(pkinit_plg_crypto_context cryptoctx,EVP_PKEY * pkey,int nbits)2980*7f2fe78bSCy Schubert check_dh_wellknown(pkinit_plg_crypto_context cryptoctx, EVP_PKEY *pkey,
2981*7f2fe78bSCy Schubert                    int nbits)
2982*7f2fe78bSCy Schubert {
2983*7f2fe78bSCy Schubert     if (nbits == 1024)
2984*7f2fe78bSCy Schubert         return EVP_PKEY_parameters_eq(cryptoctx->dh_1024, pkey) == 1;
2985*7f2fe78bSCy Schubert     else if (nbits == 2048)
2986*7f2fe78bSCy Schubert         return EVP_PKEY_parameters_eq(cryptoctx->dh_2048, pkey) == 1;
2987*7f2fe78bSCy Schubert     else if (nbits == 4096)
2988*7f2fe78bSCy Schubert         return EVP_PKEY_parameters_eq(cryptoctx->dh_4096, pkey) == 1;
2989*7f2fe78bSCy Schubert     return 0;
2990*7f2fe78bSCy Schubert }
2991*7f2fe78bSCy Schubert 
2992*7f2fe78bSCy Schubert krb5_error_code
server_check_dh(krb5_context context,pkinit_plg_crypto_context cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,const krb5_data * client_spki,int minbits)2993*7f2fe78bSCy Schubert server_check_dh(krb5_context context,
2994*7f2fe78bSCy Schubert                 pkinit_plg_crypto_context cryptoctx,
2995*7f2fe78bSCy Schubert                 pkinit_req_crypto_context req_cryptoctx,
2996*7f2fe78bSCy Schubert                 pkinit_identity_crypto_context id_cryptoctx,
2997*7f2fe78bSCy Schubert                 const krb5_data *client_spki,
2998*7f2fe78bSCy Schubert                 int minbits)
2999*7f2fe78bSCy Schubert {
3000*7f2fe78bSCy Schubert     EVP_PKEY *client_pkey = NULL;
3001*7f2fe78bSCy Schubert     int dh_prime_bits;
3002*7f2fe78bSCy Schubert     krb5_error_code retval = KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
3003*7f2fe78bSCy Schubert 
3004*7f2fe78bSCy Schubert     client_pkey = decode_spki(client_spki);
3005*7f2fe78bSCy Schubert     if (client_pkey == NULL) {
3006*7f2fe78bSCy Schubert         pkiDebug("failed to decode dhparams\n");
3007*7f2fe78bSCy Schubert         goto cleanup;
3008*7f2fe78bSCy Schubert     }
3009*7f2fe78bSCy Schubert 
3010*7f2fe78bSCy Schubert     /* KDC SHOULD check to see if the key parameters satisfy its policy */
3011*7f2fe78bSCy Schubert     dh_prime_bits = EVP_PKEY_get_bits(client_pkey);
3012*7f2fe78bSCy Schubert     if (minbits && dh_prime_bits < minbits) {
3013*7f2fe78bSCy Schubert         pkiDebug("client sent dh params with %d bits, we require %d\n",
3014*7f2fe78bSCy Schubert                  dh_prime_bits, minbits);
3015*7f2fe78bSCy Schubert         goto cleanup;
3016*7f2fe78bSCy Schubert     }
3017*7f2fe78bSCy Schubert 
3018*7f2fe78bSCy Schubert     if (check_dh_wellknown(cryptoctx, client_pkey, dh_prime_bits))
3019*7f2fe78bSCy Schubert         retval = 0;
3020*7f2fe78bSCy Schubert 
3021*7f2fe78bSCy Schubert cleanup:
3022*7f2fe78bSCy Schubert     if (retval == 0)
3023*7f2fe78bSCy Schubert         req_cryptoctx->client_pkey = client_pkey;
3024*7f2fe78bSCy Schubert     else
3025*7f2fe78bSCy Schubert         EVP_PKEY_free(client_pkey);
3026*7f2fe78bSCy Schubert 
3027*7f2fe78bSCy Schubert     return retval;
3028*7f2fe78bSCy Schubert }
3029*7f2fe78bSCy Schubert 
3030*7f2fe78bSCy Schubert /* kdc's dh function */
3031*7f2fe78bSCy Schubert krb5_error_code
server_process_dh(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context cryptoctx,pkinit_identity_crypto_context id_cryptoctx,unsigned char ** dh_pubkey_out,unsigned int * dh_pubkey_len_out,unsigned char ** server_key_out,unsigned int * server_key_len_out)3032*7f2fe78bSCy Schubert server_process_dh(krb5_context context,
3033*7f2fe78bSCy Schubert                   pkinit_plg_crypto_context plg_cryptoctx,
3034*7f2fe78bSCy Schubert                   pkinit_req_crypto_context cryptoctx,
3035*7f2fe78bSCy Schubert                   pkinit_identity_crypto_context id_cryptoctx,
3036*7f2fe78bSCy Schubert                   unsigned char **dh_pubkey_out,
3037*7f2fe78bSCy Schubert                   unsigned int *dh_pubkey_len_out,
3038*7f2fe78bSCy Schubert                   unsigned char **server_key_out,
3039*7f2fe78bSCy Schubert                   unsigned int *server_key_len_out)
3040*7f2fe78bSCy Schubert {
3041*7f2fe78bSCy Schubert     krb5_error_code retval = ENOMEM;
3042*7f2fe78bSCy Schubert     EVP_PKEY *server_pkey = NULL;
3043*7f2fe78bSCy Schubert     unsigned char *dh_pubkey = NULL, *server_key = NULL;
3044*7f2fe78bSCy Schubert     unsigned int dh_pubkey_len = 0, server_key_len = 0;
3045*7f2fe78bSCy Schubert 
3046*7f2fe78bSCy Schubert     *dh_pubkey_out = *server_key_out = NULL;
3047*7f2fe78bSCy Schubert     *dh_pubkey_len_out = *server_key_len_out = 0;
3048*7f2fe78bSCy Schubert 
3049*7f2fe78bSCy Schubert     /* Generate a server DH key with the same parameters as the client key. */
3050*7f2fe78bSCy Schubert     server_pkey = generate_dh_pkey(cryptoctx->client_pkey);
3051*7f2fe78bSCy Schubert     if (server_pkey == NULL)
3052*7f2fe78bSCy Schubert         goto cleanup;
3053*7f2fe78bSCy Schubert 
3054*7f2fe78bSCy Schubert     if (!dh_result(server_pkey, cryptoctx->client_pkey, &server_key,
3055*7f2fe78bSCy Schubert                    &server_key_len))
3056*7f2fe78bSCy Schubert         goto cleanup;
3057*7f2fe78bSCy Schubert 
3058*7f2fe78bSCy Schubert     if (!dh_pubkey_der(server_pkey, &dh_pubkey, &dh_pubkey_len))
3059*7f2fe78bSCy Schubert         goto cleanup;
3060*7f2fe78bSCy Schubert 
3061*7f2fe78bSCy Schubert     *dh_pubkey_out = dh_pubkey;
3062*7f2fe78bSCy Schubert     *dh_pubkey_len_out = dh_pubkey_len;
3063*7f2fe78bSCy Schubert     *server_key_out = server_key;
3064*7f2fe78bSCy Schubert     *server_key_len_out = server_key_len;
3065*7f2fe78bSCy Schubert     dh_pubkey = server_key = NULL;
3066*7f2fe78bSCy Schubert 
3067*7f2fe78bSCy Schubert     retval = 0;
3068*7f2fe78bSCy Schubert 
3069*7f2fe78bSCy Schubert cleanup:
3070*7f2fe78bSCy Schubert     EVP_PKEY_free(server_pkey);
3071*7f2fe78bSCy Schubert     free(dh_pubkey);
3072*7f2fe78bSCy Schubert     free(server_key);
3073*7f2fe78bSCy Schubert 
3074*7f2fe78bSCy Schubert     return retval;
3075*7f2fe78bSCy Schubert }
3076*7f2fe78bSCy Schubert 
3077*7f2fe78bSCy Schubert int
pkinit_openssl_init()3078*7f2fe78bSCy Schubert pkinit_openssl_init()
3079*7f2fe78bSCy Schubert {
3080*7f2fe78bSCy Schubert     /* Initialize OpenSSL. */
3081*7f2fe78bSCy Schubert     ERR_load_crypto_strings();
3082*7f2fe78bSCy Schubert     OpenSSL_add_all_algorithms();
3083*7f2fe78bSCy Schubert     return 0;
3084*7f2fe78bSCy Schubert }
3085*7f2fe78bSCy Schubert 
3086*7f2fe78bSCy Schubert static krb5_error_code
pkinit_create_sequence_of_principal_identifiers(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,int type,krb5_pa_data *** e_data_out)3087*7f2fe78bSCy Schubert pkinit_create_sequence_of_principal_identifiers(
3088*7f2fe78bSCy Schubert     krb5_context context,
3089*7f2fe78bSCy Schubert     pkinit_plg_crypto_context plg_cryptoctx,
3090*7f2fe78bSCy Schubert     pkinit_req_crypto_context req_cryptoctx,
3091*7f2fe78bSCy Schubert     pkinit_identity_crypto_context id_cryptoctx,
3092*7f2fe78bSCy Schubert     int type,
3093*7f2fe78bSCy Schubert     krb5_pa_data ***e_data_out)
3094*7f2fe78bSCy Schubert {
3095*7f2fe78bSCy Schubert     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
3096*7f2fe78bSCy Schubert     krb5_external_principal_identifier **krb5_trusted_certifiers = NULL;
3097*7f2fe78bSCy Schubert     krb5_data *td_certifiers = NULL;
3098*7f2fe78bSCy Schubert     krb5_pa_data **pa_data = NULL;
3099*7f2fe78bSCy Schubert 
3100*7f2fe78bSCy Schubert     switch(type) {
3101*7f2fe78bSCy Schubert     case TD_TRUSTED_CERTIFIERS:
3102*7f2fe78bSCy Schubert         retval = create_krb5_trustedCertifiers(context, plg_cryptoctx,
3103*7f2fe78bSCy Schubert                                                req_cryptoctx, id_cryptoctx, &krb5_trusted_certifiers);
3104*7f2fe78bSCy Schubert         if (retval) {
3105*7f2fe78bSCy Schubert             pkiDebug("create_krb5_trustedCertifiers failed\n");
3106*7f2fe78bSCy Schubert             goto cleanup;
3107*7f2fe78bSCy Schubert         }
3108*7f2fe78bSCy Schubert         break;
3109*7f2fe78bSCy Schubert     case TD_INVALID_CERTIFICATES:
3110*7f2fe78bSCy Schubert         retval = create_krb5_invalidCertificates(context, plg_cryptoctx,
3111*7f2fe78bSCy Schubert                                                  req_cryptoctx, id_cryptoctx, &krb5_trusted_certifiers);
3112*7f2fe78bSCy Schubert         if (retval) {
3113*7f2fe78bSCy Schubert             pkiDebug("create_krb5_invalidCertificates failed\n");
3114*7f2fe78bSCy Schubert             goto cleanup;
3115*7f2fe78bSCy Schubert         }
3116*7f2fe78bSCy Schubert         break;
3117*7f2fe78bSCy Schubert     default:
3118*7f2fe78bSCy Schubert         retval = -1;
3119*7f2fe78bSCy Schubert         goto cleanup;
3120*7f2fe78bSCy Schubert     }
3121*7f2fe78bSCy Schubert 
3122*7f2fe78bSCy Schubert     retval = k5int_encode_krb5_td_trusted_certifiers((krb5_external_principal_identifier *const *)krb5_trusted_certifiers, &td_certifiers);
3123*7f2fe78bSCy Schubert     if (retval) {
3124*7f2fe78bSCy Schubert         pkiDebug("encode_krb5_td_trusted_certifiers failed\n");
3125*7f2fe78bSCy Schubert         goto cleanup;
3126*7f2fe78bSCy Schubert     }
3127*7f2fe78bSCy Schubert #ifdef DEBUG_ASN1
3128*7f2fe78bSCy Schubert     print_buffer_bin((unsigned char *)td_certifiers->data,
3129*7f2fe78bSCy Schubert                      td_certifiers->length, "/tmp/kdc_td_certifiers");
3130*7f2fe78bSCy Schubert #endif
3131*7f2fe78bSCy Schubert     pa_data = malloc(2 * sizeof(krb5_pa_data *));
3132*7f2fe78bSCy Schubert     if (pa_data == NULL) {
3133*7f2fe78bSCy Schubert         retval = ENOMEM;
3134*7f2fe78bSCy Schubert         goto cleanup;
3135*7f2fe78bSCy Schubert     }
3136*7f2fe78bSCy Schubert     pa_data[1] = NULL;
3137*7f2fe78bSCy Schubert     pa_data[0] = malloc(sizeof(krb5_pa_data));
3138*7f2fe78bSCy Schubert     if (pa_data[0] == NULL) {
3139*7f2fe78bSCy Schubert         free(pa_data);
3140*7f2fe78bSCy Schubert         retval = ENOMEM;
3141*7f2fe78bSCy Schubert         goto cleanup;
3142*7f2fe78bSCy Schubert     }
3143*7f2fe78bSCy Schubert     pa_data[0]->pa_type = type;
3144*7f2fe78bSCy Schubert     pa_data[0]->length = td_certifiers->length;
3145*7f2fe78bSCy Schubert     pa_data[0]->contents = (krb5_octet *)td_certifiers->data;
3146*7f2fe78bSCy Schubert     *e_data_out = pa_data;
3147*7f2fe78bSCy Schubert     retval = 0;
3148*7f2fe78bSCy Schubert 
3149*7f2fe78bSCy Schubert cleanup:
3150*7f2fe78bSCy Schubert     if (krb5_trusted_certifiers != NULL)
3151*7f2fe78bSCy Schubert         free_krb5_external_principal_identifier(&krb5_trusted_certifiers);
3152*7f2fe78bSCy Schubert     free(td_certifiers);
3153*7f2fe78bSCy Schubert     return retval;
3154*7f2fe78bSCy Schubert }
3155*7f2fe78bSCy Schubert 
3156*7f2fe78bSCy Schubert krb5_error_code
pkinit_create_td_trusted_certifiers(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,krb5_pa_data *** e_data_out)3157*7f2fe78bSCy Schubert pkinit_create_td_trusted_certifiers(krb5_context context,
3158*7f2fe78bSCy Schubert                                     pkinit_plg_crypto_context plg_cryptoctx,
3159*7f2fe78bSCy Schubert                                     pkinit_req_crypto_context req_cryptoctx,
3160*7f2fe78bSCy Schubert                                     pkinit_identity_crypto_context id_cryptoctx,
3161*7f2fe78bSCy Schubert                                     krb5_pa_data ***e_data_out)
3162*7f2fe78bSCy Schubert {
3163*7f2fe78bSCy Schubert     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
3164*7f2fe78bSCy Schubert 
3165*7f2fe78bSCy Schubert     retval = pkinit_create_sequence_of_principal_identifiers(context,
3166*7f2fe78bSCy Schubert                                                              plg_cryptoctx, req_cryptoctx, id_cryptoctx,
3167*7f2fe78bSCy Schubert                                                              TD_TRUSTED_CERTIFIERS, e_data_out);
3168*7f2fe78bSCy Schubert 
3169*7f2fe78bSCy Schubert     return retval;
3170*7f2fe78bSCy Schubert }
3171*7f2fe78bSCy Schubert 
3172*7f2fe78bSCy Schubert krb5_error_code
pkinit_create_td_invalid_certificate(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,krb5_pa_data *** e_data_out)3173*7f2fe78bSCy Schubert pkinit_create_td_invalid_certificate(
3174*7f2fe78bSCy Schubert     krb5_context context,
3175*7f2fe78bSCy Schubert     pkinit_plg_crypto_context plg_cryptoctx,
3176*7f2fe78bSCy Schubert     pkinit_req_crypto_context req_cryptoctx,
3177*7f2fe78bSCy Schubert     pkinit_identity_crypto_context id_cryptoctx,
3178*7f2fe78bSCy Schubert     krb5_pa_data ***e_data_out)
3179*7f2fe78bSCy Schubert {
3180*7f2fe78bSCy Schubert     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
3181*7f2fe78bSCy Schubert 
3182*7f2fe78bSCy Schubert     retval = pkinit_create_sequence_of_principal_identifiers(context,
3183*7f2fe78bSCy Schubert                                                              plg_cryptoctx, req_cryptoctx, id_cryptoctx,
3184*7f2fe78bSCy Schubert                                                              TD_INVALID_CERTIFICATES, e_data_out);
3185*7f2fe78bSCy Schubert 
3186*7f2fe78bSCy Schubert     return retval;
3187*7f2fe78bSCy Schubert }
3188*7f2fe78bSCy Schubert 
3189*7f2fe78bSCy Schubert krb5_error_code
pkinit_create_td_dh_parameters(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,pkinit_plg_opts * opts,krb5_pa_data *** e_data_out)3190*7f2fe78bSCy Schubert pkinit_create_td_dh_parameters(krb5_context context,
3191*7f2fe78bSCy Schubert                                pkinit_plg_crypto_context plg_cryptoctx,
3192*7f2fe78bSCy Schubert                                pkinit_req_crypto_context req_cryptoctx,
3193*7f2fe78bSCy Schubert                                pkinit_identity_crypto_context id_cryptoctx,
3194*7f2fe78bSCy Schubert                                pkinit_plg_opts *opts,
3195*7f2fe78bSCy Schubert                                krb5_pa_data ***e_data_out)
3196*7f2fe78bSCy Schubert {
3197*7f2fe78bSCy Schubert     krb5_error_code ret;
3198*7f2fe78bSCy Schubert     int i;
3199*7f2fe78bSCy Schubert     krb5_pa_data **pa_data = NULL;
3200*7f2fe78bSCy Schubert     krb5_data *der_alglist = NULL;
3201*7f2fe78bSCy Schubert     krb5_algorithm_identifier alg_1024 = { dh_oid, oakley_1024 };
3202*7f2fe78bSCy Schubert     krb5_algorithm_identifier alg_2048 = { dh_oid, oakley_2048 };
3203*7f2fe78bSCy Schubert     krb5_algorithm_identifier alg_4096 = { dh_oid, oakley_4096 };
3204*7f2fe78bSCy Schubert     krb5_algorithm_identifier *alglist[4];
3205*7f2fe78bSCy Schubert 
3206*7f2fe78bSCy Schubert     if (opts->dh_min_bits > 4096) {
3207*7f2fe78bSCy Schubert         ret = KRB5KRB_ERR_GENERIC;
3208*7f2fe78bSCy Schubert         goto cleanup;
3209*7f2fe78bSCy Schubert     }
3210*7f2fe78bSCy Schubert 
3211*7f2fe78bSCy Schubert     i = 0;
3212*7f2fe78bSCy Schubert     if (opts->dh_min_bits <= 2048)
3213*7f2fe78bSCy Schubert         alglist[i++] = &alg_2048;
3214*7f2fe78bSCy Schubert     alglist[i++] = &alg_4096;
3215*7f2fe78bSCy Schubert     if (opts->dh_min_bits <= 1024)
3216*7f2fe78bSCy Schubert         alglist[i++] = &alg_1024;
3217*7f2fe78bSCy Schubert     alglist[i] = NULL;
3218*7f2fe78bSCy Schubert 
3219*7f2fe78bSCy Schubert     ret = k5int_encode_krb5_td_dh_parameters(alglist, &der_alglist);
3220*7f2fe78bSCy Schubert     if (ret)
3221*7f2fe78bSCy Schubert         goto cleanup;
3222*7f2fe78bSCy Schubert 
3223*7f2fe78bSCy Schubert     pa_data = k5calloc(2, sizeof(*pa_data), &ret);
3224*7f2fe78bSCy Schubert     if (pa_data == NULL)
3225*7f2fe78bSCy Schubert         goto cleanup;
3226*7f2fe78bSCy Schubert     pa_data[1] = NULL;
3227*7f2fe78bSCy Schubert     pa_data[0] = k5alloc(sizeof(*pa_data[0]), &ret);
3228*7f2fe78bSCy Schubert     if (pa_data[0] == NULL) {
3229*7f2fe78bSCy Schubert         free(pa_data);
3230*7f2fe78bSCy Schubert         goto cleanup;
3231*7f2fe78bSCy Schubert     }
3232*7f2fe78bSCy Schubert     pa_data[0]->pa_type = TD_DH_PARAMETERS;
3233*7f2fe78bSCy Schubert     pa_data[0]->length = der_alglist->length;
3234*7f2fe78bSCy Schubert     pa_data[0]->contents = (krb5_octet *)der_alglist->data;
3235*7f2fe78bSCy Schubert     der_alglist->data = NULL;
3236*7f2fe78bSCy Schubert     *e_data_out = pa_data;
3237*7f2fe78bSCy Schubert 
3238*7f2fe78bSCy Schubert cleanup:
3239*7f2fe78bSCy Schubert     krb5_free_data(context, der_alglist);
3240*7f2fe78bSCy Schubert     return ret;
3241*7f2fe78bSCy Schubert }
3242*7f2fe78bSCy Schubert 
3243*7f2fe78bSCy Schubert krb5_error_code
pkinit_check_kdc_pkid(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,unsigned char * pdid_buf,unsigned int pkid_len,int * valid_kdcPkId)3244*7f2fe78bSCy Schubert pkinit_check_kdc_pkid(krb5_context context,
3245*7f2fe78bSCy Schubert                       pkinit_plg_crypto_context plg_cryptoctx,
3246*7f2fe78bSCy Schubert                       pkinit_req_crypto_context req_cryptoctx,
3247*7f2fe78bSCy Schubert                       pkinit_identity_crypto_context id_cryptoctx,
3248*7f2fe78bSCy Schubert                       unsigned char *pdid_buf,
3249*7f2fe78bSCy Schubert                       unsigned int pkid_len,
3250*7f2fe78bSCy Schubert                       int *valid_kdcPkId)
3251*7f2fe78bSCy Schubert {
3252*7f2fe78bSCy Schubert     PKCS7_ISSUER_AND_SERIAL *is = NULL;
3253*7f2fe78bSCy Schubert     const unsigned char *p = pdid_buf;
3254*7f2fe78bSCy Schubert     int status = 1;
3255*7f2fe78bSCy Schubert     X509 *kdc_cert = sk_X509_value(id_cryptoctx->my_certs, id_cryptoctx->cert_index);
3256*7f2fe78bSCy Schubert 
3257*7f2fe78bSCy Schubert     *valid_kdcPkId = 0;
3258*7f2fe78bSCy Schubert     pkiDebug("found kdcPkId in AS REQ\n");
3259*7f2fe78bSCy Schubert     is = d2i_PKCS7_ISSUER_AND_SERIAL(NULL, &p, (int)pkid_len);
3260*7f2fe78bSCy Schubert     if (is == NULL)
3261*7f2fe78bSCy Schubert         return KRB5KDC_ERR_PREAUTH_FAILED;
3262*7f2fe78bSCy Schubert 
3263*7f2fe78bSCy Schubert     status = X509_NAME_cmp(X509_get_issuer_name(kdc_cert), is->issuer);
3264*7f2fe78bSCy Schubert     if (!status) {
3265*7f2fe78bSCy Schubert         status = ASN1_INTEGER_cmp(X509_get_serialNumber(kdc_cert), is->serial);
3266*7f2fe78bSCy Schubert         if (!status)
3267*7f2fe78bSCy Schubert             *valid_kdcPkId = 1;
3268*7f2fe78bSCy Schubert     }
3269*7f2fe78bSCy Schubert 
3270*7f2fe78bSCy Schubert     X509_NAME_free(is->issuer);
3271*7f2fe78bSCy Schubert     ASN1_INTEGER_free(is->serial);
3272*7f2fe78bSCy Schubert     free(is);
3273*7f2fe78bSCy Schubert 
3274*7f2fe78bSCy Schubert     return 0;
3275*7f2fe78bSCy Schubert }
3276*7f2fe78bSCy Schubert 
3277*7f2fe78bSCy Schubert krb5_error_code
pkinit_process_td_dh_params(krb5_context context,pkinit_plg_crypto_context cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,krb5_algorithm_identifier ** algId,int * new_dh_size)3278*7f2fe78bSCy Schubert pkinit_process_td_dh_params(krb5_context context,
3279*7f2fe78bSCy Schubert                             pkinit_plg_crypto_context cryptoctx,
3280*7f2fe78bSCy Schubert                             pkinit_req_crypto_context req_cryptoctx,
3281*7f2fe78bSCy Schubert                             pkinit_identity_crypto_context id_cryptoctx,
3282*7f2fe78bSCy Schubert                             krb5_algorithm_identifier **algId,
3283*7f2fe78bSCy Schubert                             int *new_dh_size)
3284*7f2fe78bSCy Schubert {
3285*7f2fe78bSCy Schubert     krb5_error_code retval = KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
3286*7f2fe78bSCy Schubert     EVP_PKEY *params = NULL;
3287*7f2fe78bSCy Schubert     int i, dh_prime_bits, old_dh_size;
3288*7f2fe78bSCy Schubert 
3289*7f2fe78bSCy Schubert     pkiDebug("dh parameters\n");
3290*7f2fe78bSCy Schubert 
3291*7f2fe78bSCy Schubert     EVP_PKEY_free(req_cryptoctx->received_params);
3292*7f2fe78bSCy Schubert     req_cryptoctx->received_params = NULL;
3293*7f2fe78bSCy Schubert 
3294*7f2fe78bSCy Schubert     old_dh_size = *new_dh_size;
3295*7f2fe78bSCy Schubert 
3296*7f2fe78bSCy Schubert     for (i = 0; algId[i] != NULL; i++) {
3297*7f2fe78bSCy Schubert         /* Free any parameters from the previous iteration. */
3298*7f2fe78bSCy Schubert         EVP_PKEY_free(params);
3299*7f2fe78bSCy Schubert         params = NULL;
3300*7f2fe78bSCy Schubert 
3301*7f2fe78bSCy Schubert         /* Skip any parameters for algorithms other than DH. */
3302*7f2fe78bSCy Schubert         if (algId[i]->algorithm.length != dh_oid.length ||
3303*7f2fe78bSCy Schubert             memcmp(algId[i]->algorithm.data, dh_oid.data, dh_oid.length))
3304*7f2fe78bSCy Schubert             continue;
3305*7f2fe78bSCy Schubert 
3306*7f2fe78bSCy Schubert         params = decode_dh_params(&algId[i]->parameters);
3307*7f2fe78bSCy Schubert         if (params == NULL)
3308*7f2fe78bSCy Schubert             continue;
3309*7f2fe78bSCy Schubert         dh_prime_bits = EVP_PKEY_get_bits(params);
3310*7f2fe78bSCy Schubert         /* Skip any parameters shorter than the previous size. */
3311*7f2fe78bSCy Schubert         if (dh_prime_bits < old_dh_size)
3312*7f2fe78bSCy Schubert             continue;
3313*7f2fe78bSCy Schubert         pkiDebug("client sent %d DH bits server prefers %d DH bits\n",
3314*7f2fe78bSCy Schubert                  *new_dh_size, dh_prime_bits);
3315*7f2fe78bSCy Schubert 
3316*7f2fe78bSCy Schubert         /* If this is one of our well-known groups, just save the new size; we
3317*7f2fe78bSCy Schubert          * will use our own copy of the parameters. */
3318*7f2fe78bSCy Schubert         if (check_dh_wellknown(cryptoctx, params, dh_prime_bits)) {
3319*7f2fe78bSCy Schubert             *new_dh_size = dh_prime_bits;
3320*7f2fe78bSCy Schubert             retval = 0;
3321*7f2fe78bSCy Schubert             goto cleanup;
3322*7f2fe78bSCy Schubert         }
3323*7f2fe78bSCy Schubert 
3324*7f2fe78bSCy Schubert         /* If the parameters aren't well-known but check out, save them. */
3325*7f2fe78bSCy Schubert         if (params_valid(params)) {
3326*7f2fe78bSCy Schubert             req_cryptoctx->received_params = params;
3327*7f2fe78bSCy Schubert             params = NULL;
3328*7f2fe78bSCy Schubert             retval = 0;
3329*7f2fe78bSCy Schubert             goto cleanup;
3330*7f2fe78bSCy Schubert         }
3331*7f2fe78bSCy Schubert     }
3332*7f2fe78bSCy Schubert 
3333*7f2fe78bSCy Schubert cleanup:
3334*7f2fe78bSCy Schubert     EVP_PKEY_free(params);
3335*7f2fe78bSCy Schubert     return retval;
3336*7f2fe78bSCy Schubert }
3337*7f2fe78bSCy Schubert 
3338*7f2fe78bSCy Schubert static int
openssl_callback(int ok,X509_STORE_CTX * ctx)3339*7f2fe78bSCy Schubert openssl_callback(int ok, X509_STORE_CTX * ctx)
3340*7f2fe78bSCy Schubert {
3341*7f2fe78bSCy Schubert #ifdef DEBUG
3342*7f2fe78bSCy Schubert     if (!ok) {
3343*7f2fe78bSCy Schubert         X509 *cert = X509_STORE_CTX_get_current_cert(ctx);
3344*7f2fe78bSCy Schubert         int err = X509_STORE_CTX_get_error(ctx);
3345*7f2fe78bSCy Schubert         const char *errmsg = X509_verify_cert_error_string(err);
3346*7f2fe78bSCy Schubert         char buf[DN_BUF_LEN];
3347*7f2fe78bSCy Schubert 
3348*7f2fe78bSCy Schubert         X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf));
3349*7f2fe78bSCy Schubert         pkiDebug("cert = %s\n", buf);
3350*7f2fe78bSCy Schubert         pkiDebug("callback function: %d (%s)\n", err, errmsg);
3351*7f2fe78bSCy Schubert     }
3352*7f2fe78bSCy Schubert #endif
3353*7f2fe78bSCy Schubert     return ok;
3354*7f2fe78bSCy Schubert }
3355*7f2fe78bSCy Schubert 
3356*7f2fe78bSCy Schubert static int
openssl_callback_ignore_crls(int ok,X509_STORE_CTX * ctx)3357*7f2fe78bSCy Schubert openssl_callback_ignore_crls(int ok, X509_STORE_CTX * ctx)
3358*7f2fe78bSCy Schubert {
3359*7f2fe78bSCy Schubert     if (ok)
3360*7f2fe78bSCy Schubert         return ok;
3361*7f2fe78bSCy Schubert     return X509_STORE_CTX_get_error(ctx) == X509_V_ERR_UNABLE_TO_GET_CRL;
3362*7f2fe78bSCy Schubert }
3363*7f2fe78bSCy Schubert 
3364*7f2fe78bSCy Schubert static ASN1_OBJECT *
pkinit_pkcs7type2oid(pkinit_plg_crypto_context cryptoctx,int pkcs7_type)3365*7f2fe78bSCy Schubert pkinit_pkcs7type2oid(pkinit_plg_crypto_context cryptoctx, int pkcs7_type)
3366*7f2fe78bSCy Schubert {
3367*7f2fe78bSCy Schubert     switch (pkcs7_type) {
3368*7f2fe78bSCy Schubert     case CMS_SIGN_CLIENT:
3369*7f2fe78bSCy Schubert         return cryptoctx->id_pkinit_authData;
3370*7f2fe78bSCy Schubert     case CMS_SIGN_SERVER:
3371*7f2fe78bSCy Schubert         return cryptoctx->id_pkinit_DHKeyData;
3372*7f2fe78bSCy Schubert     case CMS_ENVEL_SERVER:
3373*7f2fe78bSCy Schubert         return cryptoctx->id_pkinit_rkeyData;
3374*7f2fe78bSCy Schubert     default:
3375*7f2fe78bSCy Schubert         return NULL;
3376*7f2fe78bSCy Schubert     }
3377*7f2fe78bSCy Schubert 
3378*7f2fe78bSCy Schubert }
3379*7f2fe78bSCy Schubert 
3380*7f2fe78bSCy Schubert static int
wrap_signeddata(unsigned char * data,unsigned int data_len,unsigned char ** out,unsigned int * out_len)3381*7f2fe78bSCy Schubert wrap_signeddata(unsigned char *data, unsigned int data_len,
3382*7f2fe78bSCy Schubert                 unsigned char **out, unsigned int *out_len)
3383*7f2fe78bSCy Schubert {
3384*7f2fe78bSCy Schubert 
3385*7f2fe78bSCy Schubert     unsigned int orig_len = 0, oid_len = 0, tot_len = 0;
3386*7f2fe78bSCy Schubert     ASN1_OBJECT *oid = NULL;
3387*7f2fe78bSCy Schubert     unsigned char *p = NULL;
3388*7f2fe78bSCy Schubert 
3389*7f2fe78bSCy Schubert     /* Get length to wrap the original data with SEQUENCE tag */
3390*7f2fe78bSCy Schubert     tot_len = orig_len = ASN1_object_size(1, (int)data_len, V_ASN1_SEQUENCE);
3391*7f2fe78bSCy Schubert 
3392*7f2fe78bSCy Schubert     /* Add the signedData OID and adjust lengths */
3393*7f2fe78bSCy Schubert     oid = OBJ_nid2obj(NID_pkcs7_signed);
3394*7f2fe78bSCy Schubert     oid_len = i2d_ASN1_OBJECT(oid, NULL);
3395*7f2fe78bSCy Schubert 
3396*7f2fe78bSCy Schubert     tot_len = ASN1_object_size(1, (int)(orig_len+oid_len), V_ASN1_SEQUENCE);
3397*7f2fe78bSCy Schubert 
3398*7f2fe78bSCy Schubert     p = *out = malloc(tot_len);
3399*7f2fe78bSCy Schubert     if (p == NULL) return -1;
3400*7f2fe78bSCy Schubert 
3401*7f2fe78bSCy Schubert     ASN1_put_object(&p, 1, (int)(orig_len+oid_len),
3402*7f2fe78bSCy Schubert                     V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
3403*7f2fe78bSCy Schubert 
3404*7f2fe78bSCy Schubert     i2d_ASN1_OBJECT(oid, &p);
3405*7f2fe78bSCy Schubert 
3406*7f2fe78bSCy Schubert     ASN1_put_object(&p, 1, (int)data_len, 0, V_ASN1_CONTEXT_SPECIFIC);
3407*7f2fe78bSCy Schubert     memcpy(p, data, data_len);
3408*7f2fe78bSCy Schubert 
3409*7f2fe78bSCy Schubert     *out_len = tot_len;
3410*7f2fe78bSCy Schubert 
3411*7f2fe78bSCy Schubert     return 0;
3412*7f2fe78bSCy Schubert }
3413*7f2fe78bSCy Schubert 
3414*7f2fe78bSCy Schubert static int
prepare_enc_data(const uint8_t * indata,int indata_len,uint8_t ** outdata,int * outdata_len)3415*7f2fe78bSCy Schubert prepare_enc_data(const uint8_t *indata, int indata_len, uint8_t **outdata,
3416*7f2fe78bSCy Schubert                  int *outdata_len)
3417*7f2fe78bSCy Schubert {
3418*7f2fe78bSCy Schubert     int tag, class;
3419*7f2fe78bSCy Schubert     long tlen, slen;
3420*7f2fe78bSCy Schubert     const uint8_t *p = indata, *oldp;
3421*7f2fe78bSCy Schubert 
3422*7f2fe78bSCy Schubert     if (ASN1_get_object(&p, &slen, &tag, &class, indata_len) & 0x80)
3423*7f2fe78bSCy Schubert         return EINVAL;
3424*7f2fe78bSCy Schubert     if (tag != V_ASN1_SEQUENCE)
3425*7f2fe78bSCy Schubert         return EINVAL;
3426*7f2fe78bSCy Schubert 
3427*7f2fe78bSCy Schubert     oldp = p;
3428*7f2fe78bSCy Schubert     if (ASN1_get_object(&p, &tlen, &tag, &class, slen) & 0x80)
3429*7f2fe78bSCy Schubert         return EINVAL;
3430*7f2fe78bSCy Schubert     p += tlen;
3431*7f2fe78bSCy Schubert     slen -= (p - oldp);
3432*7f2fe78bSCy Schubert 
3433*7f2fe78bSCy Schubert     if (ASN1_get_object(&p, &tlen, &tag, &class, slen) & 0x80)
3434*7f2fe78bSCy Schubert         return EINVAL;
3435*7f2fe78bSCy Schubert 
3436*7f2fe78bSCy Schubert     *outdata = malloc(tlen);
3437*7f2fe78bSCy Schubert     if (*outdata == NULL)
3438*7f2fe78bSCy Schubert         return ENOMEM;
3439*7f2fe78bSCy Schubert     memcpy(*outdata, p, tlen);
3440*7f2fe78bSCy Schubert     *outdata_len = tlen;
3441*7f2fe78bSCy Schubert     return 0;
3442*7f2fe78bSCy Schubert }
3443*7f2fe78bSCy Schubert 
3444*7f2fe78bSCy Schubert #ifndef WITHOUT_PKCS11
3445*7f2fe78bSCy Schubert static struct plugin_file_handle *
load_pkcs11_module(krb5_context context,const char * modname,CK_FUNCTION_LIST_PTR_PTR p11p)3446*7f2fe78bSCy Schubert load_pkcs11_module(krb5_context context, const char *modname,
3447*7f2fe78bSCy Schubert                    CK_FUNCTION_LIST_PTR_PTR p11p)
3448*7f2fe78bSCy Schubert {
3449*7f2fe78bSCy Schubert     struct plugin_file_handle *handle = NULL;
3450*7f2fe78bSCy Schubert     CK_RV (*getflist)(CK_FUNCTION_LIST_PTR_PTR);
3451*7f2fe78bSCy Schubert     struct errinfo einfo = EMPTY_ERRINFO;
3452*7f2fe78bSCy Schubert     const char *errmsg = NULL;
3453*7f2fe78bSCy Schubert     void (*sym)();
3454*7f2fe78bSCy Schubert     long err;
3455*7f2fe78bSCy Schubert     CK_RV rv;
3456*7f2fe78bSCy Schubert 
3457*7f2fe78bSCy Schubert     TRACE_PKINIT_PKCS11_OPEN(context, modname);
3458*7f2fe78bSCy Schubert     err = krb5int_open_plugin(modname, &handle, &einfo);
3459*7f2fe78bSCy Schubert     if (err) {
3460*7f2fe78bSCy Schubert         errmsg = k5_get_error(&einfo, err);
3461*7f2fe78bSCy Schubert         TRACE_PKINIT_PKCS11_OPEN_FAILED(context, errmsg);
3462*7f2fe78bSCy Schubert         goto error;
3463*7f2fe78bSCy Schubert     }
3464*7f2fe78bSCy Schubert 
3465*7f2fe78bSCy Schubert     err = krb5int_get_plugin_func(handle, "C_GetFunctionList", &sym, &einfo);
3466*7f2fe78bSCy Schubert     if (err) {
3467*7f2fe78bSCy Schubert         errmsg = k5_get_error(&einfo, err);
3468*7f2fe78bSCy Schubert         TRACE_PKINIT_PKCS11_GETSYM_FAILED(context, errmsg);
3469*7f2fe78bSCy Schubert         goto error;
3470*7f2fe78bSCy Schubert     }
3471*7f2fe78bSCy Schubert 
3472*7f2fe78bSCy Schubert     getflist = (CK_RV (*)())sym;
3473*7f2fe78bSCy Schubert     rv = (*getflist)(p11p);
3474*7f2fe78bSCy Schubert     if (rv != CKR_OK) {
3475*7f2fe78bSCy Schubert         TRACE_PKINIT_PKCS11_GETFLIST_FAILED(context, pkcs11err(rv));
3476*7f2fe78bSCy Schubert         goto error;
3477*7f2fe78bSCy Schubert     }
3478*7f2fe78bSCy Schubert 
3479*7f2fe78bSCy Schubert     return handle;
3480*7f2fe78bSCy Schubert 
3481*7f2fe78bSCy Schubert error:
3482*7f2fe78bSCy Schubert     k5_free_error(&einfo, errmsg);
3483*7f2fe78bSCy Schubert     k5_clear_error(&einfo);
3484*7f2fe78bSCy Schubert     if (handle != NULL)
3485*7f2fe78bSCy Schubert         krb5int_close_plugin(handle);
3486*7f2fe78bSCy Schubert     return NULL;
3487*7f2fe78bSCy Schubert }
3488*7f2fe78bSCy Schubert 
3489*7f2fe78bSCy Schubert static krb5_error_code
pkinit_login(krb5_context context,pkinit_identity_crypto_context id_cryptoctx,CK_TOKEN_INFO * tip,const char * password)3490*7f2fe78bSCy Schubert pkinit_login(krb5_context context,
3491*7f2fe78bSCy Schubert              pkinit_identity_crypto_context id_cryptoctx,
3492*7f2fe78bSCy Schubert              CK_TOKEN_INFO *tip, const char *password)
3493*7f2fe78bSCy Schubert {
3494*7f2fe78bSCy Schubert     krb5_data rdat;
3495*7f2fe78bSCy Schubert     char *prompt;
3496*7f2fe78bSCy Schubert     const char *warning;
3497*7f2fe78bSCy Schubert     krb5_prompt kprompt;
3498*7f2fe78bSCy Schubert     krb5_prompt_type prompt_type;
3499*7f2fe78bSCy Schubert     int r = 0;
3500*7f2fe78bSCy Schubert 
3501*7f2fe78bSCy Schubert     if (tip->flags & CKF_PROTECTED_AUTHENTICATION_PATH) {
3502*7f2fe78bSCy Schubert         rdat.data = NULL;
3503*7f2fe78bSCy Schubert         rdat.length = 0;
3504*7f2fe78bSCy Schubert     } else if (password != NULL) {
3505*7f2fe78bSCy Schubert         rdat.data = strdup(password);
3506*7f2fe78bSCy Schubert         rdat.length = strlen(password);
3507*7f2fe78bSCy Schubert     } else if (id_cryptoctx->prompter == NULL) {
3508*7f2fe78bSCy Schubert         r = KRB5_LIBOS_CANTREADPWD;
3509*7f2fe78bSCy Schubert         rdat.data = NULL;
3510*7f2fe78bSCy Schubert     } else {
3511*7f2fe78bSCy Schubert         if (tip->flags & CKF_USER_PIN_LOCKED)
3512*7f2fe78bSCy Schubert             warning = " (Warning: PIN locked)";
3513*7f2fe78bSCy Schubert         else if (tip->flags & CKF_USER_PIN_FINAL_TRY)
3514*7f2fe78bSCy Schubert             warning = " (Warning: PIN final try)";
3515*7f2fe78bSCy Schubert         else if (tip->flags & CKF_USER_PIN_COUNT_LOW)
3516*7f2fe78bSCy Schubert             warning = " (Warning: PIN count low)";
3517*7f2fe78bSCy Schubert         else
3518*7f2fe78bSCy Schubert             warning = "";
3519*7f2fe78bSCy Schubert         if (asprintf(&prompt, "%.*s PIN%s", (int) sizeof (tip->label),
3520*7f2fe78bSCy Schubert                      tip->label, warning) < 0)
3521*7f2fe78bSCy Schubert             return ENOMEM;
3522*7f2fe78bSCy Schubert         rdat.data = malloc(tip->ulMaxPinLen + 2);
3523*7f2fe78bSCy Schubert         rdat.length = tip->ulMaxPinLen + 1;
3524*7f2fe78bSCy Schubert 
3525*7f2fe78bSCy Schubert         kprompt.prompt = prompt;
3526*7f2fe78bSCy Schubert         kprompt.hidden = 1;
3527*7f2fe78bSCy Schubert         kprompt.reply = &rdat;
3528*7f2fe78bSCy Schubert         prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
3529*7f2fe78bSCy Schubert 
3530*7f2fe78bSCy Schubert         /* PROMPTER_INVOCATION */
3531*7f2fe78bSCy Schubert         k5int_set_prompt_types(context, &prompt_type);
3532*7f2fe78bSCy Schubert         r = (*id_cryptoctx->prompter)(context, id_cryptoctx->prompter_data,
3533*7f2fe78bSCy Schubert                                       NULL, NULL, 1, &kprompt);
3534*7f2fe78bSCy Schubert         k5int_set_prompt_types(context, 0);
3535*7f2fe78bSCy Schubert         free(prompt);
3536*7f2fe78bSCy Schubert     }
3537*7f2fe78bSCy Schubert 
3538*7f2fe78bSCy Schubert     if (r == 0) {
3539*7f2fe78bSCy Schubert         r = id_cryptoctx->p11->C_Login(id_cryptoctx->session, CKU_USER,
3540*7f2fe78bSCy Schubert                                        (u_char *) rdat.data, rdat.length);
3541*7f2fe78bSCy Schubert 
3542*7f2fe78bSCy Schubert         if (r != CKR_OK) {
3543*7f2fe78bSCy Schubert             TRACE_PKINIT_PKCS11_LOGIN_FAILED(context, pkcs11err(r));
3544*7f2fe78bSCy Schubert             r = KRB5KDC_ERR_PREAUTH_FAILED;
3545*7f2fe78bSCy Schubert         }
3546*7f2fe78bSCy Schubert     }
3547*7f2fe78bSCy Schubert     free(rdat.data);
3548*7f2fe78bSCy Schubert 
3549*7f2fe78bSCy Schubert     return r;
3550*7f2fe78bSCy Schubert }
3551*7f2fe78bSCy Schubert 
3552*7f2fe78bSCy Schubert static krb5_error_code
pkinit_open_session(krb5_context context,pkinit_identity_crypto_context cctx)3553*7f2fe78bSCy Schubert pkinit_open_session(krb5_context context,
3554*7f2fe78bSCy Schubert                     pkinit_identity_crypto_context cctx)
3555*7f2fe78bSCy Schubert {
3556*7f2fe78bSCy Schubert     CK_ULONG i, pret;
3557*7f2fe78bSCy Schubert     unsigned char *cp;
3558*7f2fe78bSCy Schubert     size_t label_len;
3559*7f2fe78bSCy Schubert     CK_ULONG count = 0;
3560*7f2fe78bSCy Schubert     CK_SLOT_ID_PTR slotlist = NULL;
3561*7f2fe78bSCy Schubert     CK_TOKEN_INFO tinfo;
3562*7f2fe78bSCy Schubert     char *p11name = NULL;
3563*7f2fe78bSCy Schubert     const char *password;
3564*7f2fe78bSCy Schubert     krb5_error_code ret;
3565*7f2fe78bSCy Schubert 
3566*7f2fe78bSCy Schubert     if (cctx->p11_module != NULL)
3567*7f2fe78bSCy Schubert         return 0; /* session already open */
3568*7f2fe78bSCy Schubert 
3569*7f2fe78bSCy Schubert     /* Load module */
3570*7f2fe78bSCy Schubert     cctx->p11_module = load_pkcs11_module(context, cctx->p11_module_name,
3571*7f2fe78bSCy Schubert                                           &cctx->p11);
3572*7f2fe78bSCy Schubert     if (cctx->p11_module == NULL)
3573*7f2fe78bSCy Schubert         return KRB5KDC_ERR_PREAUTH_FAILED;
3574*7f2fe78bSCy Schubert 
3575*7f2fe78bSCy Schubert     /* Init */
3576*7f2fe78bSCy Schubert     pret = cctx->p11->C_Initialize(NULL);
3577*7f2fe78bSCy Schubert     if (pret != CKR_OK) {
3578*7f2fe78bSCy Schubert         pkiDebug("C_Initialize: %s\n", pkcs11err(pret));
3579*7f2fe78bSCy Schubert         return KRB5KDC_ERR_PREAUTH_FAILED;
3580*7f2fe78bSCy Schubert     }
3581*7f2fe78bSCy Schubert 
3582*7f2fe78bSCy Schubert     /* Get the list of available slots */
3583*7f2fe78bSCy Schubert     if (cctx->p11->C_GetSlotList(TRUE, NULL, &count) != CKR_OK)
3584*7f2fe78bSCy Schubert         return KRB5KDC_ERR_PREAUTH_FAILED;
3585*7f2fe78bSCy Schubert     if (count == 0) {
3586*7f2fe78bSCy Schubert         TRACE_PKINIT_PKCS11_NO_TOKEN(context);
3587*7f2fe78bSCy Schubert         return KRB5KDC_ERR_PREAUTH_FAILED;
3588*7f2fe78bSCy Schubert     }
3589*7f2fe78bSCy Schubert     slotlist = calloc(count, sizeof(CK_SLOT_ID));
3590*7f2fe78bSCy Schubert     if (slotlist == NULL)
3591*7f2fe78bSCy Schubert         return ENOMEM;
3592*7f2fe78bSCy Schubert     if (cctx->p11->C_GetSlotList(TRUE, slotlist, &count) != CKR_OK) {
3593*7f2fe78bSCy Schubert         ret = KRB5KDC_ERR_PREAUTH_FAILED;
3594*7f2fe78bSCy Schubert         goto cleanup;
3595*7f2fe78bSCy Schubert     }
3596*7f2fe78bSCy Schubert 
3597*7f2fe78bSCy Schubert     /* Look for the given token label, or if none given take the first one */
3598*7f2fe78bSCy Schubert     for (i = 0; i < count; i++) {
3599*7f2fe78bSCy Schubert         /* Skip slots that don't match the specified slotid, if given. */
3600*7f2fe78bSCy Schubert         if (cctx->slotid != PK_NOSLOT && cctx->slotid != slotlist[i])
3601*7f2fe78bSCy Schubert             continue;
3602*7f2fe78bSCy Schubert 
3603*7f2fe78bSCy Schubert         /* Open session */
3604*7f2fe78bSCy Schubert         pret = cctx->p11->C_OpenSession(slotlist[i], CKF_SERIAL_SESSION,
3605*7f2fe78bSCy Schubert                                         NULL, NULL, &cctx->session);
3606*7f2fe78bSCy Schubert         if (pret != CKR_OK) {
3607*7f2fe78bSCy Schubert             pkiDebug("C_OpenSession: %s\n", pkcs11err(pret));
3608*7f2fe78bSCy Schubert             ret = KRB5KDC_ERR_PREAUTH_FAILED;
3609*7f2fe78bSCy Schubert             goto cleanup;
3610*7f2fe78bSCy Schubert         }
3611*7f2fe78bSCy Schubert 
3612*7f2fe78bSCy Schubert         /* Get token info */
3613*7f2fe78bSCy Schubert         pret = cctx->p11->C_GetTokenInfo(slotlist[i], &tinfo);
3614*7f2fe78bSCy Schubert         if (pret != CKR_OK) {
3615*7f2fe78bSCy Schubert             pkiDebug("C_GetTokenInfo: %s\n", pkcs11err(pret));
3616*7f2fe78bSCy Schubert             ret = KRB5KDC_ERR_PREAUTH_FAILED;
3617*7f2fe78bSCy Schubert             goto cleanup;
3618*7f2fe78bSCy Schubert         }
3619*7f2fe78bSCy Schubert 
3620*7f2fe78bSCy Schubert         /* tinfo.label is zero-filled but not necessarily zero-terminated.
3621*7f2fe78bSCy Schubert          * Find the length, ignoring any trailing spaces. */
3622*7f2fe78bSCy Schubert         for (cp = tinfo.label + sizeof(tinfo.label); cp > tinfo.label; cp--) {
3623*7f2fe78bSCy Schubert             if (cp[-1] != '\0' && cp[-1] != ' ')
3624*7f2fe78bSCy Schubert                 break;
3625*7f2fe78bSCy Schubert         }
3626*7f2fe78bSCy Schubert         label_len = cp - tinfo.label;
3627*7f2fe78bSCy Schubert 
3628*7f2fe78bSCy Schubert         TRACE_PKINIT_PKCS11_SLOT(context, (int)slotlist[i], (int)label_len,
3629*7f2fe78bSCy Schubert                                  tinfo.label);
3630*7f2fe78bSCy Schubert         if (cctx->token_label == NULL ||
3631*7f2fe78bSCy Schubert             (strlen(cctx->token_label) == label_len &&
3632*7f2fe78bSCy Schubert              memcmp(cctx->token_label, tinfo.label, label_len) == 0))
3633*7f2fe78bSCy Schubert             break;
3634*7f2fe78bSCy Schubert         cctx->p11->C_CloseSession(cctx->session);
3635*7f2fe78bSCy Schubert     }
3636*7f2fe78bSCy Schubert     if (i >= count) {
3637*7f2fe78bSCy Schubert         TRACE_PKINIT_PKCS11_NO_MATCH_TOKEN(context);
3638*7f2fe78bSCy Schubert         ret = KRB5KDC_ERR_PREAUTH_FAILED;
3639*7f2fe78bSCy Schubert         goto cleanup;
3640*7f2fe78bSCy Schubert     }
3641*7f2fe78bSCy Schubert     cctx->slotid = slotlist[i];
3642*7f2fe78bSCy Schubert     pkiDebug("open_session: slotid %d (%lu of %d)\n", (int)cctx->slotid,
3643*7f2fe78bSCy Schubert              i + 1, (int) count);
3644*7f2fe78bSCy Schubert 
3645*7f2fe78bSCy Schubert     /* Login if needed */
3646*7f2fe78bSCy Schubert     if (tinfo.flags & CKF_LOGIN_REQUIRED) {
3647*7f2fe78bSCy Schubert         if (cctx->p11_module_name != NULL) {
3648*7f2fe78bSCy Schubert             if (cctx->slotid != PK_NOSLOT) {
3649*7f2fe78bSCy Schubert                 if (asprintf(&p11name,
3650*7f2fe78bSCy Schubert                              "PKCS11:module_name=%s:slotid=%ld:token=%.*s",
3651*7f2fe78bSCy Schubert                              cctx->p11_module_name, (long)cctx->slotid,
3652*7f2fe78bSCy Schubert                              (int)label_len, tinfo.label) < 0)
3653*7f2fe78bSCy Schubert                     p11name = NULL;
3654*7f2fe78bSCy Schubert             } else {
3655*7f2fe78bSCy Schubert                 if (asprintf(&p11name,
3656*7f2fe78bSCy Schubert                              "PKCS11:module_name=%s,token=%.*s",
3657*7f2fe78bSCy Schubert                              cctx->p11_module_name,
3658*7f2fe78bSCy Schubert                              (int)label_len, tinfo.label) < 0)
3659*7f2fe78bSCy Schubert                     p11name = NULL;
3660*7f2fe78bSCy Schubert             }
3661*7f2fe78bSCy Schubert         }
3662*7f2fe78bSCy Schubert         if (cctx->defer_id_prompt) {
3663*7f2fe78bSCy Schubert             /* Supply the identity name to be passed to the responder. */
3664*7f2fe78bSCy Schubert             pkinit_set_deferred_id(&cctx->deferred_ids,
3665*7f2fe78bSCy Schubert                                    p11name, tinfo.flags, NULL);
3666*7f2fe78bSCy Schubert             ret = 0;
3667*7f2fe78bSCy Schubert             goto cleanup;
3668*7f2fe78bSCy Schubert         }
3669*7f2fe78bSCy Schubert         /* Look up a responder-supplied password for the token. */
3670*7f2fe78bSCy Schubert         password = pkinit_find_deferred_id(cctx->deferred_ids, p11name);
3671*7f2fe78bSCy Schubert         ret = pkinit_login(context, cctx, &tinfo, password);
3672*7f2fe78bSCy Schubert         if (ret)
3673*7f2fe78bSCy Schubert             goto cleanup;
3674*7f2fe78bSCy Schubert     }
3675*7f2fe78bSCy Schubert 
3676*7f2fe78bSCy Schubert     ret = 0;
3677*7f2fe78bSCy Schubert cleanup:
3678*7f2fe78bSCy Schubert     free(slotlist);
3679*7f2fe78bSCy Schubert     free(p11name);
3680*7f2fe78bSCy Schubert     return ret;
3681*7f2fe78bSCy Schubert }
3682*7f2fe78bSCy Schubert 
3683*7f2fe78bSCy Schubert /*
3684*7f2fe78bSCy Schubert  * Look for a key that's:
3685*7f2fe78bSCy Schubert  * 1. private
3686*7f2fe78bSCy Schubert  * 2. capable of the specified operation (usually signing or decrypting)
3687*7f2fe78bSCy Schubert  * 3. RSA (this may be wrong but it's all we can do for now)
3688*7f2fe78bSCy Schubert  * 4. matches the id of the cert we chose
3689*7f2fe78bSCy Schubert  *
3690*7f2fe78bSCy Schubert  * You must call pkinit_get_certs before calling pkinit_find_private_key
3691*7f2fe78bSCy Schubert  * (that's because we need the ID of the private key)
3692*7f2fe78bSCy Schubert  *
3693*7f2fe78bSCy Schubert  * pkcs11 says the id of the key doesn't have to match that of the cert, but
3694*7f2fe78bSCy Schubert  * I can't figure out any other way to decide which key to use.
3695*7f2fe78bSCy Schubert  *
3696*7f2fe78bSCy Schubert  * We should only find one key that fits all the requirements.
3697*7f2fe78bSCy Schubert  * If there are more than one, we just take the first one.
3698*7f2fe78bSCy Schubert  */
3699*7f2fe78bSCy Schubert 
3700*7f2fe78bSCy Schubert krb5_error_code
pkinit_find_private_key(pkinit_identity_crypto_context id_cryptoctx,CK_ATTRIBUTE_TYPE usage,CK_OBJECT_HANDLE * objp)3701*7f2fe78bSCy Schubert pkinit_find_private_key(pkinit_identity_crypto_context id_cryptoctx,
3702*7f2fe78bSCy Schubert                         CK_ATTRIBUTE_TYPE usage,
3703*7f2fe78bSCy Schubert                         CK_OBJECT_HANDLE *objp)
3704*7f2fe78bSCy Schubert {
3705*7f2fe78bSCy Schubert     CK_OBJECT_CLASS cls;
3706*7f2fe78bSCy Schubert     CK_ATTRIBUTE attrs[4];
3707*7f2fe78bSCy Schubert     CK_ULONG count;
3708*7f2fe78bSCy Schubert     CK_KEY_TYPE keytype;
3709*7f2fe78bSCy Schubert     unsigned int nattrs = 0;
3710*7f2fe78bSCy Schubert     int r;
3711*7f2fe78bSCy Schubert #ifdef PKINIT_USE_KEY_USAGE
3712*7f2fe78bSCy Schubert     CK_BBOOL true_false;
3713*7f2fe78bSCy Schubert #endif
3714*7f2fe78bSCy Schubert 
3715*7f2fe78bSCy Schubert     cls = CKO_PRIVATE_KEY;
3716*7f2fe78bSCy Schubert     attrs[nattrs].type = CKA_CLASS;
3717*7f2fe78bSCy Schubert     attrs[nattrs].pValue = &cls;
3718*7f2fe78bSCy Schubert     attrs[nattrs].ulValueLen = sizeof cls;
3719*7f2fe78bSCy Schubert     nattrs++;
3720*7f2fe78bSCy Schubert 
3721*7f2fe78bSCy Schubert #ifdef PKINIT_USE_KEY_USAGE
3722*7f2fe78bSCy Schubert     /*
3723*7f2fe78bSCy Schubert      * Some cards get confused if you try to specify a key usage,
3724*7f2fe78bSCy Schubert      * so don't, and hope for the best. This will fail if you have
3725*7f2fe78bSCy Schubert      * several keys with the same id and different usages but I have
3726*7f2fe78bSCy Schubert      * not seen this on real cards.
3727*7f2fe78bSCy Schubert      */
3728*7f2fe78bSCy Schubert     true_false = TRUE;
3729*7f2fe78bSCy Schubert     attrs[nattrs].type = usage;
3730*7f2fe78bSCy Schubert     attrs[nattrs].pValue = &true_false;
3731*7f2fe78bSCy Schubert     attrs[nattrs].ulValueLen = sizeof true_false;
3732*7f2fe78bSCy Schubert     nattrs++;
3733*7f2fe78bSCy Schubert #endif
3734*7f2fe78bSCy Schubert 
3735*7f2fe78bSCy Schubert     keytype = CKK_RSA;
3736*7f2fe78bSCy Schubert     attrs[nattrs].type = CKA_KEY_TYPE;
3737*7f2fe78bSCy Schubert     attrs[nattrs].pValue = &keytype;
3738*7f2fe78bSCy Schubert     attrs[nattrs].ulValueLen = sizeof keytype;
3739*7f2fe78bSCy Schubert     nattrs++;
3740*7f2fe78bSCy Schubert 
3741*7f2fe78bSCy Schubert     attrs[nattrs].type = CKA_ID;
3742*7f2fe78bSCy Schubert     attrs[nattrs].pValue = id_cryptoctx->cert_id;
3743*7f2fe78bSCy Schubert     attrs[nattrs].ulValueLen = id_cryptoctx->cert_id_len;
3744*7f2fe78bSCy Schubert     nattrs++;
3745*7f2fe78bSCy Schubert 
3746*7f2fe78bSCy Schubert     r = id_cryptoctx->p11->C_FindObjectsInit(id_cryptoctx->session, attrs, nattrs);
3747*7f2fe78bSCy Schubert     if (r != CKR_OK) {
3748*7f2fe78bSCy Schubert         pkiDebug("krb5_pkinit_sign_data: C_FindObjectsInit: %s\n",
3749*7f2fe78bSCy Schubert                  pkcs11err(r));
3750*7f2fe78bSCy Schubert         return KRB5KDC_ERR_PREAUTH_FAILED;
3751*7f2fe78bSCy Schubert     }
3752*7f2fe78bSCy Schubert 
3753*7f2fe78bSCy Schubert     r = id_cryptoctx->p11->C_FindObjects(id_cryptoctx->session, objp, 1, &count);
3754*7f2fe78bSCy Schubert     id_cryptoctx->p11->C_FindObjectsFinal(id_cryptoctx->session);
3755*7f2fe78bSCy Schubert     pkiDebug("found %d private keys (%s)\n", (int)count, pkcs11err(r));
3756*7f2fe78bSCy Schubert     if (r != CKR_OK || count < 1)
3757*7f2fe78bSCy Schubert         return KRB5KDC_ERR_PREAUTH_FAILED;
3758*7f2fe78bSCy Schubert     return 0;
3759*7f2fe78bSCy Schubert }
3760*7f2fe78bSCy Schubert #endif
3761*7f2fe78bSCy Schubert 
3762*7f2fe78bSCy Schubert static krb5_error_code
pkinit_decode_data_fs(krb5_context context,pkinit_identity_crypto_context id_cryptoctx,const uint8_t * data,unsigned int data_len,uint8_t ** decoded_data,unsigned int * decoded_data_len)3763*7f2fe78bSCy Schubert pkinit_decode_data_fs(krb5_context context,
3764*7f2fe78bSCy Schubert                       pkinit_identity_crypto_context id_cryptoctx,
3765*7f2fe78bSCy Schubert                       const uint8_t *data, unsigned int data_len,
3766*7f2fe78bSCy Schubert                       uint8_t **decoded_data, unsigned int *decoded_data_len)
3767*7f2fe78bSCy Schubert {
3768*7f2fe78bSCy Schubert     X509 *cert = sk_X509_value(id_cryptoctx->my_certs,
3769*7f2fe78bSCy Schubert                                id_cryptoctx->cert_index);
3770*7f2fe78bSCy Schubert     EVP_PKEY *pkey = id_cryptoctx->my_key;
3771*7f2fe78bSCy Schubert     EVP_PKEY_CTX *ctx = NULL;
3772*7f2fe78bSCy Schubert     uint8_t *buf = NULL;
3773*7f2fe78bSCy Schubert     size_t buf_len = 0;
3774*7f2fe78bSCy Schubert     int ok;
3775*7f2fe78bSCy Schubert 
3776*7f2fe78bSCy Schubert     *decoded_data = NULL;
3777*7f2fe78bSCy Schubert     *decoded_data_len = 0;
3778*7f2fe78bSCy Schubert 
3779*7f2fe78bSCy Schubert     if (cert != NULL && !X509_check_private_key(cert, pkey)) {
3780*7f2fe78bSCy Schubert         pkiDebug("private key does not match certificate\n");
3781*7f2fe78bSCy Schubert         return KRB5KDC_ERR_PREAUTH_FAILED;
3782*7f2fe78bSCy Schubert     }
3783*7f2fe78bSCy Schubert 
3784*7f2fe78bSCy Schubert     ctx = EVP_PKEY_CTX_new(pkey, NULL);
3785*7f2fe78bSCy Schubert     if (ctx == NULL)
3786*7f2fe78bSCy Schubert         return KRB5KDC_ERR_PREAUTH_FAILED;
3787*7f2fe78bSCy Schubert 
3788*7f2fe78bSCy Schubert     ok = EVP_PKEY_decrypt_init(ctx);
3789*7f2fe78bSCy Schubert     if (!ok)
3790*7f2fe78bSCy Schubert         goto cleanup;
3791*7f2fe78bSCy Schubert 
3792*7f2fe78bSCy Schubert     /* Get the length of the eventual output. */
3793*7f2fe78bSCy Schubert     ok = EVP_PKEY_decrypt(ctx, NULL, &buf_len, data, data_len);
3794*7f2fe78bSCy Schubert     if (!ok) {
3795*7f2fe78bSCy Schubert         pkiDebug("unable to decrypt received data\n");
3796*7f2fe78bSCy Schubert         goto cleanup;
3797*7f2fe78bSCy Schubert     }
3798*7f2fe78bSCy Schubert 
3799*7f2fe78bSCy Schubert     buf = malloc(buf_len);
3800*7f2fe78bSCy Schubert     if (buf == NULL) {
3801*7f2fe78bSCy Schubert         ok = 0;
3802*7f2fe78bSCy Schubert         goto cleanup;
3803*7f2fe78bSCy Schubert     }
3804*7f2fe78bSCy Schubert 
3805*7f2fe78bSCy Schubert     ok = EVP_PKEY_decrypt(ctx, buf, &buf_len, data, data_len);
3806*7f2fe78bSCy Schubert     if (!ok) {
3807*7f2fe78bSCy Schubert         pkiDebug("unable to decrypt received data\n");
3808*7f2fe78bSCy Schubert         goto cleanup;
3809*7f2fe78bSCy Schubert     }
3810*7f2fe78bSCy Schubert 
3811*7f2fe78bSCy Schubert     *decoded_data = buf;
3812*7f2fe78bSCy Schubert     *decoded_data_len = buf_len;
3813*7f2fe78bSCy Schubert     buf = NULL;
3814*7f2fe78bSCy Schubert cleanup:
3815*7f2fe78bSCy Schubert     zapfree(buf, buf_len);
3816*7f2fe78bSCy Schubert     EVP_PKEY_CTX_free(ctx);
3817*7f2fe78bSCy Schubert     return ok ? 0 : KRB5KDC_ERR_PREAUTH_FAILED;
3818*7f2fe78bSCy Schubert }
3819*7f2fe78bSCy Schubert 
3820*7f2fe78bSCy Schubert #ifndef WITHOUT_PKCS11
3821*7f2fe78bSCy Schubert /*
3822*7f2fe78bSCy Schubert  * When using the ActivCard Linux pkcs11 library (v2.0.1), the decrypt function
3823*7f2fe78bSCy Schubert  * fails.  By inserting an extra function call, which serves nothing but to
3824*7f2fe78bSCy Schubert  * change the stack, we were able to work around the issue.  If the ActivCard
3825*7f2fe78bSCy Schubert  * library is fixed in the future, this function can be inlined back into the
3826*7f2fe78bSCy Schubert  * caller.
3827*7f2fe78bSCy Schubert  */
3828*7f2fe78bSCy Schubert static CK_RV
pkinit_C_Decrypt(pkinit_identity_crypto_context id_cryptoctx,CK_BYTE_PTR pEncryptedData,CK_ULONG ulEncryptedDataLen,CK_BYTE_PTR pData,CK_ULONG_PTR pulDataLen)3829*7f2fe78bSCy Schubert pkinit_C_Decrypt(pkinit_identity_crypto_context id_cryptoctx,
3830*7f2fe78bSCy Schubert                  CK_BYTE_PTR pEncryptedData,
3831*7f2fe78bSCy Schubert                  CK_ULONG  ulEncryptedDataLen,
3832*7f2fe78bSCy Schubert                  CK_BYTE_PTR pData,
3833*7f2fe78bSCy Schubert                  CK_ULONG_PTR pulDataLen)
3834*7f2fe78bSCy Schubert {
3835*7f2fe78bSCy Schubert     CK_RV rv = CKR_OK;
3836*7f2fe78bSCy Schubert 
3837*7f2fe78bSCy Schubert     rv = id_cryptoctx->p11->C_Decrypt(id_cryptoctx->session, pEncryptedData,
3838*7f2fe78bSCy Schubert                                       ulEncryptedDataLen, pData, pulDataLen);
3839*7f2fe78bSCy Schubert     if (rv == CKR_OK) {
3840*7f2fe78bSCy Schubert         pkiDebug("pData %p *pulDataLen %d\n", (void *) pData,
3841*7f2fe78bSCy Schubert                  (int) *pulDataLen);
3842*7f2fe78bSCy Schubert     }
3843*7f2fe78bSCy Schubert     return rv;
3844*7f2fe78bSCy Schubert }
3845*7f2fe78bSCy Schubert 
3846*7f2fe78bSCy Schubert static krb5_error_code
pkinit_decode_data_pkcs11(krb5_context context,pkinit_identity_crypto_context id_cryptoctx,const uint8_t * data,unsigned int data_len,uint8_t ** decoded_data,unsigned int * decoded_data_len)3847*7f2fe78bSCy Schubert pkinit_decode_data_pkcs11(krb5_context context,
3848*7f2fe78bSCy Schubert                           pkinit_identity_crypto_context id_cryptoctx,
3849*7f2fe78bSCy Schubert                           const uint8_t *data, unsigned int data_len,
3850*7f2fe78bSCy Schubert                           uint8_t **decoded_data,
3851*7f2fe78bSCy Schubert                           unsigned int *decoded_data_len)
3852*7f2fe78bSCy Schubert {
3853*7f2fe78bSCy Schubert     CK_OBJECT_HANDLE obj;
3854*7f2fe78bSCy Schubert     CK_ULONG len;
3855*7f2fe78bSCy Schubert     CK_MECHANISM mech;
3856*7f2fe78bSCy Schubert     uint8_t *cp;
3857*7f2fe78bSCy Schubert     int r;
3858*7f2fe78bSCy Schubert 
3859*7f2fe78bSCy Schubert     *decoded_data = NULL;
3860*7f2fe78bSCy Schubert     *decoded_data_len = 0;
3861*7f2fe78bSCy Schubert 
3862*7f2fe78bSCy Schubert     if (pkinit_open_session(context, id_cryptoctx)) {
3863*7f2fe78bSCy Schubert         pkiDebug("can't open pkcs11 session\n");
3864*7f2fe78bSCy Schubert         return KRB5KDC_ERR_PREAUTH_FAILED;
3865*7f2fe78bSCy Schubert     }
3866*7f2fe78bSCy Schubert 
3867*7f2fe78bSCy Schubert     pkinit_find_private_key(id_cryptoctx, CKA_DECRYPT, &obj);
3868*7f2fe78bSCy Schubert 
3869*7f2fe78bSCy Schubert     mech.mechanism = CKM_RSA_PKCS;
3870*7f2fe78bSCy Schubert     mech.pParameter = NULL;
3871*7f2fe78bSCy Schubert     mech.ulParameterLen = 0;
3872*7f2fe78bSCy Schubert 
3873*7f2fe78bSCy Schubert     if ((r = id_cryptoctx->p11->C_DecryptInit(id_cryptoctx->session, &mech,
3874*7f2fe78bSCy Schubert                                               obj)) != CKR_OK) {
3875*7f2fe78bSCy Schubert         pkiDebug("C_DecryptInit: 0x%x\n", (int) r);
3876*7f2fe78bSCy Schubert         return KRB5KDC_ERR_PREAUTH_FAILED;
3877*7f2fe78bSCy Schubert     }
3878*7f2fe78bSCy Schubert     pkiDebug("data_len = %d\n", data_len);
3879*7f2fe78bSCy Schubert     cp = malloc((size_t) data_len);
3880*7f2fe78bSCy Schubert     if (cp == NULL)
3881*7f2fe78bSCy Schubert         return ENOMEM;
3882*7f2fe78bSCy Schubert     len = data_len;
3883*7f2fe78bSCy Schubert     pkiDebug("session %p edata %p edata_len %d data %p datalen @%p %d\n",
3884*7f2fe78bSCy Schubert              (void *) id_cryptoctx->session, (void *) data, (int) data_len,
3885*7f2fe78bSCy Schubert              (void *) cp, (void *) &len, (int) len);
3886*7f2fe78bSCy Schubert     r = pkinit_C_Decrypt(id_cryptoctx, (CK_BYTE_PTR) data, (CK_ULONG) data_len,
3887*7f2fe78bSCy Schubert                          cp, &len);
3888*7f2fe78bSCy Schubert     if (r != CKR_OK) {
3889*7f2fe78bSCy Schubert         pkiDebug("C_Decrypt: %s\n", pkcs11err(r));
3890*7f2fe78bSCy Schubert         if (r == CKR_BUFFER_TOO_SMALL)
3891*7f2fe78bSCy Schubert             pkiDebug("decrypt %d needs %d\n", (int) data_len, (int) len);
3892*7f2fe78bSCy Schubert         return KRB5KDC_ERR_PREAUTH_FAILED;
3893*7f2fe78bSCy Schubert     }
3894*7f2fe78bSCy Schubert     pkiDebug("decrypt %d -> %d\n", (int) data_len, (int) len);
3895*7f2fe78bSCy Schubert     *decoded_data_len = len;
3896*7f2fe78bSCy Schubert     *decoded_data = cp;
3897*7f2fe78bSCy Schubert 
3898*7f2fe78bSCy Schubert     return 0;
3899*7f2fe78bSCy Schubert }
3900*7f2fe78bSCy Schubert #endif
3901*7f2fe78bSCy Schubert 
3902*7f2fe78bSCy Schubert krb5_error_code
pkinit_decode_data(krb5_context context,pkinit_identity_crypto_context id_cryptoctx,const uint8_t * data,unsigned int data_len,uint8_t ** decoded_data,unsigned int * decoded_data_len)3903*7f2fe78bSCy Schubert pkinit_decode_data(krb5_context context,
3904*7f2fe78bSCy Schubert                    pkinit_identity_crypto_context id_cryptoctx,
3905*7f2fe78bSCy Schubert                    const uint8_t *data, unsigned int data_len,
3906*7f2fe78bSCy Schubert                    uint8_t **decoded_data, unsigned int *decoded_data_len)
3907*7f2fe78bSCy Schubert {
3908*7f2fe78bSCy Schubert     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
3909*7f2fe78bSCy Schubert 
3910*7f2fe78bSCy Schubert     *decoded_data = NULL;
3911*7f2fe78bSCy Schubert     *decoded_data_len = 0;
3912*7f2fe78bSCy Schubert 
3913*7f2fe78bSCy Schubert     if (id_cryptoctx->pkcs11_method != 1)
3914*7f2fe78bSCy Schubert         retval = pkinit_decode_data_fs(context, id_cryptoctx, data, data_len,
3915*7f2fe78bSCy Schubert                                        decoded_data, decoded_data_len);
3916*7f2fe78bSCy Schubert #ifndef WITHOUT_PKCS11
3917*7f2fe78bSCy Schubert     else
3918*7f2fe78bSCy Schubert         retval = pkinit_decode_data_pkcs11(context, id_cryptoctx, data,
3919*7f2fe78bSCy Schubert                                            data_len, decoded_data, decoded_data_len);
3920*7f2fe78bSCy Schubert #endif
3921*7f2fe78bSCy Schubert 
3922*7f2fe78bSCy Schubert     return retval;
3923*7f2fe78bSCy Schubert }
3924*7f2fe78bSCy Schubert 
3925*7f2fe78bSCy Schubert static krb5_error_code
pkinit_sign_data_fs(krb5_context context,pkinit_identity_crypto_context id_cryptoctx,unsigned char * data,unsigned int data_len,unsigned char ** sig,unsigned int * sig_len)3926*7f2fe78bSCy Schubert pkinit_sign_data_fs(krb5_context context,
3927*7f2fe78bSCy Schubert                     pkinit_identity_crypto_context id_cryptoctx,
3928*7f2fe78bSCy Schubert                     unsigned char *data,
3929*7f2fe78bSCy Schubert                     unsigned int data_len,
3930*7f2fe78bSCy Schubert                     unsigned char **sig,
3931*7f2fe78bSCy Schubert                     unsigned int *sig_len)
3932*7f2fe78bSCy Schubert {
3933*7f2fe78bSCy Schubert     if (create_signature(sig, sig_len, data, data_len,
3934*7f2fe78bSCy Schubert                          id_cryptoctx->my_key) != 0) {
3935*7f2fe78bSCy Schubert         pkiDebug("failed to create the signature\n");
3936*7f2fe78bSCy Schubert         return KRB5KDC_ERR_PREAUTH_FAILED;
3937*7f2fe78bSCy Schubert     }
3938*7f2fe78bSCy Schubert     return 0;
3939*7f2fe78bSCy Schubert }
3940*7f2fe78bSCy Schubert 
3941*7f2fe78bSCy Schubert #ifndef WITHOUT_PKCS11
3942*7f2fe78bSCy Schubert static krb5_error_code
pkinit_sign_data_pkcs11(krb5_context context,pkinit_identity_crypto_context id_cryptoctx,unsigned char * data,unsigned int data_len,unsigned char ** sig,unsigned int * sig_len)3943*7f2fe78bSCy Schubert pkinit_sign_data_pkcs11(krb5_context context,
3944*7f2fe78bSCy Schubert                         pkinit_identity_crypto_context id_cryptoctx,
3945*7f2fe78bSCy Schubert                         unsigned char *data,
3946*7f2fe78bSCy Schubert                         unsigned int data_len,
3947*7f2fe78bSCy Schubert                         unsigned char **sig,
3948*7f2fe78bSCy Schubert                         unsigned int *sig_len)
3949*7f2fe78bSCy Schubert {
3950*7f2fe78bSCy Schubert     CK_OBJECT_HANDLE obj;
3951*7f2fe78bSCy Schubert     CK_ULONG len;
3952*7f2fe78bSCy Schubert     CK_MECHANISM mech;
3953*7f2fe78bSCy Schubert     unsigned char *cp;
3954*7f2fe78bSCy Schubert     int r;
3955*7f2fe78bSCy Schubert 
3956*7f2fe78bSCy Schubert     if (pkinit_open_session(context, id_cryptoctx)) {
3957*7f2fe78bSCy Schubert         pkiDebug("can't open pkcs11 session\n");
3958*7f2fe78bSCy Schubert         return KRB5KDC_ERR_PREAUTH_FAILED;
3959*7f2fe78bSCy Schubert     }
3960*7f2fe78bSCy Schubert 
3961*7f2fe78bSCy Schubert     pkinit_find_private_key(id_cryptoctx, CKA_SIGN, &obj);
3962*7f2fe78bSCy Schubert 
3963*7f2fe78bSCy Schubert     mech.mechanism = id_cryptoctx->mech;
3964*7f2fe78bSCy Schubert     mech.pParameter = NULL;
3965*7f2fe78bSCy Schubert     mech.ulParameterLen = 0;
3966*7f2fe78bSCy Schubert 
3967*7f2fe78bSCy Schubert     if ((r = id_cryptoctx->p11->C_SignInit(id_cryptoctx->session, &mech,
3968*7f2fe78bSCy Schubert                                            obj)) != CKR_OK) {
3969*7f2fe78bSCy Schubert         pkiDebug("C_SignInit: %s\n", pkcs11err(r));
3970*7f2fe78bSCy Schubert         return KRB5KDC_ERR_PREAUTH_FAILED;
3971*7f2fe78bSCy Schubert     }
3972*7f2fe78bSCy Schubert 
3973*7f2fe78bSCy Schubert     /*
3974*7f2fe78bSCy Schubert      * Key len would give an upper bound on sig size, but there's no way to
3975*7f2fe78bSCy Schubert      * get that. So guess, and if it's too small, re-malloc.
3976*7f2fe78bSCy Schubert      */
3977*7f2fe78bSCy Schubert     len = PK_SIGLEN_GUESS;
3978*7f2fe78bSCy Schubert     cp = malloc((size_t) len);
3979*7f2fe78bSCy Schubert     if (cp == NULL)
3980*7f2fe78bSCy Schubert         return ENOMEM;
3981*7f2fe78bSCy Schubert 
3982*7f2fe78bSCy Schubert     r = id_cryptoctx->p11->C_Sign(id_cryptoctx->session, data,
3983*7f2fe78bSCy Schubert                                   (CK_ULONG) data_len, cp, &len);
3984*7f2fe78bSCy Schubert     if (r == CKR_BUFFER_TOO_SMALL || (r == CKR_OK && len >= PK_SIGLEN_GUESS)) {
3985*7f2fe78bSCy Schubert         free(cp);
3986*7f2fe78bSCy Schubert         pkiDebug("C_Sign realloc %d\n", (int) len);
3987*7f2fe78bSCy Schubert         cp = malloc((size_t) len);
3988*7f2fe78bSCy Schubert         r = id_cryptoctx->p11->C_Sign(id_cryptoctx->session, data,
3989*7f2fe78bSCy Schubert                                       (CK_ULONG) data_len, cp, &len);
3990*7f2fe78bSCy Schubert     }
3991*7f2fe78bSCy Schubert     if (r != CKR_OK) {
3992*7f2fe78bSCy Schubert         pkiDebug("C_Sign: %s\n", pkcs11err(r));
3993*7f2fe78bSCy Schubert         return KRB5KDC_ERR_PREAUTH_FAILED;
3994*7f2fe78bSCy Schubert     }
3995*7f2fe78bSCy Schubert     pkiDebug("sign %d -> %d\n", (int) data_len, (int) len);
3996*7f2fe78bSCy Schubert     *sig_len = len;
3997*7f2fe78bSCy Schubert     *sig = cp;
3998*7f2fe78bSCy Schubert 
3999*7f2fe78bSCy Schubert     return 0;
4000*7f2fe78bSCy Schubert }
4001*7f2fe78bSCy Schubert #endif
4002*7f2fe78bSCy Schubert 
4003*7f2fe78bSCy Schubert krb5_error_code
pkinit_sign_data(krb5_context context,pkinit_identity_crypto_context id_cryptoctx,unsigned char * data,unsigned int data_len,unsigned char ** sig,unsigned int * sig_len)4004*7f2fe78bSCy Schubert pkinit_sign_data(krb5_context context,
4005*7f2fe78bSCy Schubert                  pkinit_identity_crypto_context id_cryptoctx,
4006*7f2fe78bSCy Schubert                  unsigned char *data,
4007*7f2fe78bSCy Schubert                  unsigned int data_len,
4008*7f2fe78bSCy Schubert                  unsigned char **sig,
4009*7f2fe78bSCy Schubert                  unsigned int *sig_len)
4010*7f2fe78bSCy Schubert {
4011*7f2fe78bSCy Schubert     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
4012*7f2fe78bSCy Schubert 
4013*7f2fe78bSCy Schubert     if (id_cryptoctx == NULL || id_cryptoctx->pkcs11_method != 1)
4014*7f2fe78bSCy Schubert         retval = pkinit_sign_data_fs(context, id_cryptoctx, data, data_len,
4015*7f2fe78bSCy Schubert                                      sig, sig_len);
4016*7f2fe78bSCy Schubert #ifndef WITHOUT_PKCS11
4017*7f2fe78bSCy Schubert     else
4018*7f2fe78bSCy Schubert         retval = pkinit_sign_data_pkcs11(context, id_cryptoctx, data, data_len,
4019*7f2fe78bSCy Schubert                                          sig, sig_len);
4020*7f2fe78bSCy Schubert #endif
4021*7f2fe78bSCy Schubert 
4022*7f2fe78bSCy Schubert     return retval;
4023*7f2fe78bSCy Schubert }
4024*7f2fe78bSCy Schubert 
4025*7f2fe78bSCy Schubert 
4026*7f2fe78bSCy Schubert static krb5_error_code
create_signature(unsigned char ** sig,unsigned int * sig_len,unsigned char * data,unsigned int data_len,EVP_PKEY * pkey)4027*7f2fe78bSCy Schubert create_signature(unsigned char **sig, unsigned int *sig_len,
4028*7f2fe78bSCy Schubert                  unsigned char *data, unsigned int data_len, EVP_PKEY *pkey)
4029*7f2fe78bSCy Schubert {
4030*7f2fe78bSCy Schubert     krb5_error_code retval = ENOMEM;
4031*7f2fe78bSCy Schubert     EVP_MD_CTX *ctx;
4032*7f2fe78bSCy Schubert 
4033*7f2fe78bSCy Schubert     if (pkey == NULL)
4034*7f2fe78bSCy Schubert         return retval;
4035*7f2fe78bSCy Schubert 
4036*7f2fe78bSCy Schubert     ctx = EVP_MD_CTX_new();
4037*7f2fe78bSCy Schubert     if (ctx == NULL)
4038*7f2fe78bSCy Schubert         return ENOMEM;
4039*7f2fe78bSCy Schubert     EVP_SignInit(ctx, EVP_sha256());
4040*7f2fe78bSCy Schubert     EVP_SignUpdate(ctx, data, data_len);
4041*7f2fe78bSCy Schubert     *sig_len = EVP_PKEY_size(pkey);
4042*7f2fe78bSCy Schubert     if ((*sig = malloc(*sig_len)) == NULL)
4043*7f2fe78bSCy Schubert         goto cleanup;
4044*7f2fe78bSCy Schubert     EVP_SignFinal(ctx, *sig, sig_len, pkey);
4045*7f2fe78bSCy Schubert 
4046*7f2fe78bSCy Schubert     retval = 0;
4047*7f2fe78bSCy Schubert 
4048*7f2fe78bSCy Schubert cleanup:
4049*7f2fe78bSCy Schubert     EVP_MD_CTX_free(ctx);
4050*7f2fe78bSCy Schubert 
4051*7f2fe78bSCy Schubert     return retval;
4052*7f2fe78bSCy Schubert }
4053*7f2fe78bSCy Schubert 
4054*7f2fe78bSCy Schubert /*
4055*7f2fe78bSCy Schubert  * Note:
4056*7f2fe78bSCy Schubert  * This is not the routine the KDC uses to get its certificate.
4057*7f2fe78bSCy Schubert  * This routine is intended to be called by the client
4058*7f2fe78bSCy Schubert  * to obtain the KDC's certificate from some local storage
4059*7f2fe78bSCy Schubert  * to be sent as a hint in its request to the KDC.
4060*7f2fe78bSCy Schubert  */
4061*7f2fe78bSCy Schubert krb5_error_code
pkinit_get_kdc_cert(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,krb5_principal princ)4062*7f2fe78bSCy Schubert pkinit_get_kdc_cert(krb5_context context,
4063*7f2fe78bSCy Schubert                     pkinit_plg_crypto_context plg_cryptoctx,
4064*7f2fe78bSCy Schubert                     pkinit_req_crypto_context req_cryptoctx,
4065*7f2fe78bSCy Schubert                     pkinit_identity_crypto_context id_cryptoctx,
4066*7f2fe78bSCy Schubert                     krb5_principal princ)
4067*7f2fe78bSCy Schubert {
4068*7f2fe78bSCy Schubert     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
4069*7f2fe78bSCy Schubert 
4070*7f2fe78bSCy Schubert     req_cryptoctx->received_cert = NULL;
4071*7f2fe78bSCy Schubert     retval = 0;
4072*7f2fe78bSCy Schubert     return retval;
4073*7f2fe78bSCy Schubert }
4074*7f2fe78bSCy Schubert 
4075*7f2fe78bSCy Schubert static char *
reassemble_pkcs12_name(const char * filename)4076*7f2fe78bSCy Schubert reassemble_pkcs12_name(const char *filename)
4077*7f2fe78bSCy Schubert {
4078*7f2fe78bSCy Schubert     char *ret;
4079*7f2fe78bSCy Schubert 
4080*7f2fe78bSCy Schubert     if (asprintf(&ret, "PKCS12:%s", filename) < 0)
4081*7f2fe78bSCy Schubert         return NULL;
4082*7f2fe78bSCy Schubert     return ret;
4083*7f2fe78bSCy Schubert }
4084*7f2fe78bSCy Schubert 
4085*7f2fe78bSCy Schubert static krb5_error_code
pkinit_get_certs_pkcs12(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_opts * idopts,pkinit_identity_crypto_context id_cryptoctx,krb5_principal princ)4086*7f2fe78bSCy Schubert pkinit_get_certs_pkcs12(krb5_context context,
4087*7f2fe78bSCy Schubert                         pkinit_plg_crypto_context plg_cryptoctx,
4088*7f2fe78bSCy Schubert                         pkinit_req_crypto_context req_cryptoctx,
4089*7f2fe78bSCy Schubert                         pkinit_identity_opts *idopts,
4090*7f2fe78bSCy Schubert                         pkinit_identity_crypto_context id_cryptoctx,
4091*7f2fe78bSCy Schubert                         krb5_principal princ)
4092*7f2fe78bSCy Schubert {
4093*7f2fe78bSCy Schubert     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
4094*7f2fe78bSCy Schubert     char *prompt_string = NULL;
4095*7f2fe78bSCy Schubert     X509 *x = NULL;
4096*7f2fe78bSCy Schubert     PKCS12 *p12 = NULL;
4097*7f2fe78bSCy Schubert     int ret;
4098*7f2fe78bSCy Schubert     FILE *fp;
4099*7f2fe78bSCy Schubert     EVP_PKEY *y = NULL;
4100*7f2fe78bSCy Schubert 
4101*7f2fe78bSCy Schubert     if (idopts->cert_filename == NULL) {
4102*7f2fe78bSCy Schubert         pkiDebug("%s: failed to get user's cert location\n", __FUNCTION__);
4103*7f2fe78bSCy Schubert         goto cleanup;
4104*7f2fe78bSCy Schubert     }
4105*7f2fe78bSCy Schubert 
4106*7f2fe78bSCy Schubert     if (idopts->key_filename == NULL) {
4107*7f2fe78bSCy Schubert         pkiDebug("%s: failed to get user's private key location\n", __FUNCTION__);
4108*7f2fe78bSCy Schubert         goto cleanup;
4109*7f2fe78bSCy Schubert     }
4110*7f2fe78bSCy Schubert 
4111*7f2fe78bSCy Schubert     fp = fopen(idopts->cert_filename, "rb");
4112*7f2fe78bSCy Schubert     if (fp == NULL) {
4113*7f2fe78bSCy Schubert         TRACE_PKINIT_PKCS_OPEN_FAIL(context, idopts->cert_filename, errno);
4114*7f2fe78bSCy Schubert         goto cleanup;
4115*7f2fe78bSCy Schubert     }
4116*7f2fe78bSCy Schubert     set_cloexec_file(fp);
4117*7f2fe78bSCy Schubert 
4118*7f2fe78bSCy Schubert     p12 = d2i_PKCS12_fp(fp, NULL);
4119*7f2fe78bSCy Schubert     fclose(fp);
4120*7f2fe78bSCy Schubert     if (p12 == NULL) {
4121*7f2fe78bSCy Schubert         TRACE_PKINIT_PKCS_DECODE_FAIL(context, idopts->cert_filename);
4122*7f2fe78bSCy Schubert         goto cleanup;
4123*7f2fe78bSCy Schubert     }
4124*7f2fe78bSCy Schubert     /*
4125*7f2fe78bSCy Schubert      * Try parsing with no pass phrase first.  If that fails,
4126*7f2fe78bSCy Schubert      * prompt for the pass phrase and try again.
4127*7f2fe78bSCy Schubert      */
4128*7f2fe78bSCy Schubert     ret = PKCS12_parse(p12, NULL, &y, &x, NULL);
4129*7f2fe78bSCy Schubert     if (ret == 0) {
4130*7f2fe78bSCy Schubert         krb5_data rdat;
4131*7f2fe78bSCy Schubert         krb5_prompt kprompt;
4132*7f2fe78bSCy Schubert         krb5_prompt_type prompt_type;
4133*7f2fe78bSCy Schubert         krb5_error_code r;
4134*7f2fe78bSCy Schubert         char prompt_reply[128];
4135*7f2fe78bSCy Schubert         char *prompt_prefix = _("Pass phrase for");
4136*7f2fe78bSCy Schubert         char *p12name = reassemble_pkcs12_name(idopts->cert_filename);
4137*7f2fe78bSCy Schubert         const char *tmp;
4138*7f2fe78bSCy Schubert 
4139*7f2fe78bSCy Schubert         TRACE_PKINIT_PKCS_PARSE_FAIL_FIRST(context);
4140*7f2fe78bSCy Schubert 
4141*7f2fe78bSCy Schubert         if (id_cryptoctx->defer_id_prompt) {
4142*7f2fe78bSCy Schubert             /* Supply the identity name to be passed to the responder. */
4143*7f2fe78bSCy Schubert             pkinit_set_deferred_id(&id_cryptoctx->deferred_ids, p12name, 0,
4144*7f2fe78bSCy Schubert                                    NULL);
4145*7f2fe78bSCy Schubert             free(p12name);
4146*7f2fe78bSCy Schubert             retval = 0;
4147*7f2fe78bSCy Schubert             goto cleanup;
4148*7f2fe78bSCy Schubert         }
4149*7f2fe78bSCy Schubert         /* Try to read a responder-supplied password. */
4150*7f2fe78bSCy Schubert         tmp = pkinit_find_deferred_id(id_cryptoctx->deferred_ids, p12name);
4151*7f2fe78bSCy Schubert         free(p12name);
4152*7f2fe78bSCy Schubert         if (tmp != NULL) {
4153*7f2fe78bSCy Schubert             /* Try using the responder-supplied password. */
4154*7f2fe78bSCy Schubert             rdat.data = (char *)tmp;
4155*7f2fe78bSCy Schubert             rdat.length = strlen(tmp);
4156*7f2fe78bSCy Schubert         } else if (id_cryptoctx->prompter == NULL) {
4157*7f2fe78bSCy Schubert             /* We can't use a prompter. */
4158*7f2fe78bSCy Schubert             goto cleanup;
4159*7f2fe78bSCy Schubert         } else {
4160*7f2fe78bSCy Schubert             /* Ask using a prompter. */
4161*7f2fe78bSCy Schubert             memset(prompt_reply, '\0', sizeof(prompt_reply));
4162*7f2fe78bSCy Schubert             rdat.data = prompt_reply;
4163*7f2fe78bSCy Schubert             rdat.length = sizeof(prompt_reply);
4164*7f2fe78bSCy Schubert 
4165*7f2fe78bSCy Schubert             if (asprintf(&prompt_string, "%s %s", prompt_prefix,
4166*7f2fe78bSCy Schubert                          idopts->cert_filename) < 0) {
4167*7f2fe78bSCy Schubert                 prompt_string = NULL;
4168*7f2fe78bSCy Schubert                 goto cleanup;
4169*7f2fe78bSCy Schubert             }
4170*7f2fe78bSCy Schubert             kprompt.prompt = prompt_string;
4171*7f2fe78bSCy Schubert             kprompt.hidden = 1;
4172*7f2fe78bSCy Schubert             kprompt.reply = &rdat;
4173*7f2fe78bSCy Schubert             prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
4174*7f2fe78bSCy Schubert             /* PROMPTER_INVOCATION */
4175*7f2fe78bSCy Schubert             k5int_set_prompt_types(context, &prompt_type);
4176*7f2fe78bSCy Schubert             r = (*id_cryptoctx->prompter)(context, id_cryptoctx->prompter_data,
4177*7f2fe78bSCy Schubert                                           NULL, NULL, 1, &kprompt);
4178*7f2fe78bSCy Schubert             k5int_set_prompt_types(context, 0);
4179*7f2fe78bSCy Schubert             if (r) {
4180*7f2fe78bSCy Schubert                 TRACE_PKINIT_PKCS_PROMPT_FAIL(context);
4181*7f2fe78bSCy Schubert                 goto cleanup;
4182*7f2fe78bSCy Schubert             }
4183*7f2fe78bSCy Schubert         }
4184*7f2fe78bSCy Schubert 
4185*7f2fe78bSCy Schubert         ret = PKCS12_parse(p12, rdat.data, &y, &x, NULL);
4186*7f2fe78bSCy Schubert         if (ret == 0) {
4187*7f2fe78bSCy Schubert             TRACE_PKINIT_PKCS_PARSE_FAIL_SECOND(context);
4188*7f2fe78bSCy Schubert             goto cleanup;
4189*7f2fe78bSCy Schubert         }
4190*7f2fe78bSCy Schubert     }
4191*7f2fe78bSCy Schubert     id_cryptoctx->creds[0] = malloc(sizeof(struct _pkinit_cred_info));
4192*7f2fe78bSCy Schubert     if (id_cryptoctx->creds[0] == NULL)
4193*7f2fe78bSCy Schubert         goto cleanup;
4194*7f2fe78bSCy Schubert     id_cryptoctx->creds[0]->name =
4195*7f2fe78bSCy Schubert         reassemble_pkcs12_name(idopts->cert_filename);
4196*7f2fe78bSCy Schubert     id_cryptoctx->creds[0]->cert = x;
4197*7f2fe78bSCy Schubert #ifndef WITHOUT_PKCS11
4198*7f2fe78bSCy Schubert     id_cryptoctx->creds[0]->cert_id = NULL;
4199*7f2fe78bSCy Schubert     id_cryptoctx->creds[0]->cert_id_len = 0;
4200*7f2fe78bSCy Schubert #endif
4201*7f2fe78bSCy Schubert     id_cryptoctx->creds[0]->key = y;
4202*7f2fe78bSCy Schubert     id_cryptoctx->creds[1] = NULL;
4203*7f2fe78bSCy Schubert 
4204*7f2fe78bSCy Schubert     retval = 0;
4205*7f2fe78bSCy Schubert 
4206*7f2fe78bSCy Schubert cleanup:
4207*7f2fe78bSCy Schubert     free(prompt_string);
4208*7f2fe78bSCy Schubert     if (p12)
4209*7f2fe78bSCy Schubert         PKCS12_free(p12);
4210*7f2fe78bSCy Schubert     if (retval) {
4211*7f2fe78bSCy Schubert         if (x != NULL)
4212*7f2fe78bSCy Schubert             X509_free(x);
4213*7f2fe78bSCy Schubert         if (y != NULL)
4214*7f2fe78bSCy Schubert             EVP_PKEY_free(y);
4215*7f2fe78bSCy Schubert     }
4216*7f2fe78bSCy Schubert     return retval;
4217*7f2fe78bSCy Schubert }
4218*7f2fe78bSCy Schubert 
4219*7f2fe78bSCy Schubert static char *
reassemble_files_name(const char * certfile,const char * keyfile)4220*7f2fe78bSCy Schubert reassemble_files_name(const char *certfile, const char *keyfile)
4221*7f2fe78bSCy Schubert {
4222*7f2fe78bSCy Schubert     char *ret;
4223*7f2fe78bSCy Schubert 
4224*7f2fe78bSCy Schubert     if (keyfile != NULL) {
4225*7f2fe78bSCy Schubert         if (asprintf(&ret, "FILE:%s,%s", certfile, keyfile) < 0)
4226*7f2fe78bSCy Schubert             return NULL;
4227*7f2fe78bSCy Schubert     } else {
4228*7f2fe78bSCy Schubert         if (asprintf(&ret, "FILE:%s", certfile) < 0)
4229*7f2fe78bSCy Schubert             return NULL;
4230*7f2fe78bSCy Schubert     }
4231*7f2fe78bSCy Schubert     return ret;
4232*7f2fe78bSCy Schubert }
4233*7f2fe78bSCy Schubert 
4234*7f2fe78bSCy Schubert static krb5_error_code
pkinit_load_fs_cert_and_key(krb5_context context,pkinit_identity_crypto_context id_cryptoctx,char * certname,char * keyname,int cindex)4235*7f2fe78bSCy Schubert pkinit_load_fs_cert_and_key(krb5_context context,
4236*7f2fe78bSCy Schubert                             pkinit_identity_crypto_context id_cryptoctx,
4237*7f2fe78bSCy Schubert                             char *certname,
4238*7f2fe78bSCy Schubert                             char *keyname,
4239*7f2fe78bSCy Schubert                             int cindex)
4240*7f2fe78bSCy Schubert {
4241*7f2fe78bSCy Schubert     krb5_error_code retval;
4242*7f2fe78bSCy Schubert     X509 *x = NULL;
4243*7f2fe78bSCy Schubert     EVP_PKEY *y = NULL;
4244*7f2fe78bSCy Schubert     char *fsname = NULL;
4245*7f2fe78bSCy Schubert     const char *password;
4246*7f2fe78bSCy Schubert 
4247*7f2fe78bSCy Schubert     fsname = reassemble_files_name(certname, keyname);
4248*7f2fe78bSCy Schubert 
4249*7f2fe78bSCy Schubert     /* Try to read a responder-supplied password. */
4250*7f2fe78bSCy Schubert     password = pkinit_find_deferred_id(id_cryptoctx->deferred_ids, fsname);
4251*7f2fe78bSCy Schubert 
4252*7f2fe78bSCy Schubert     /* Load the certificate. */
4253*7f2fe78bSCy Schubert     retval = get_cert(certname, &x);
4254*7f2fe78bSCy Schubert     if (retval) {
4255*7f2fe78bSCy Schubert         retval = oerr(context, retval, _("Cannot read certificate file '%s'"),
4256*7f2fe78bSCy Schubert                       certname);
4257*7f2fe78bSCy Schubert     }
4258*7f2fe78bSCy Schubert     if (retval || x == NULL)
4259*7f2fe78bSCy Schubert         goto cleanup;
4260*7f2fe78bSCy Schubert     /* Load the key. */
4261*7f2fe78bSCy Schubert     retval = get_key(context, id_cryptoctx, keyname, fsname, &y, password);
4262*7f2fe78bSCy Schubert     if (retval)
4263*7f2fe78bSCy Schubert         retval = oerr(context, retval, _("Cannot read key file '%s'"), fsname);
4264*7f2fe78bSCy Schubert     if (retval || y == NULL)
4265*7f2fe78bSCy Schubert         goto cleanup;
4266*7f2fe78bSCy Schubert 
4267*7f2fe78bSCy Schubert     id_cryptoctx->creds[cindex] = malloc(sizeof(struct _pkinit_cred_info));
4268*7f2fe78bSCy Schubert     if (id_cryptoctx->creds[cindex] == NULL) {
4269*7f2fe78bSCy Schubert         retval = ENOMEM;
4270*7f2fe78bSCy Schubert         goto cleanup;
4271*7f2fe78bSCy Schubert     }
4272*7f2fe78bSCy Schubert     id_cryptoctx->creds[cindex]->name = reassemble_files_name(certname,
4273*7f2fe78bSCy Schubert                                                               keyname);
4274*7f2fe78bSCy Schubert     id_cryptoctx->creds[cindex]->cert = x;
4275*7f2fe78bSCy Schubert #ifndef WITHOUT_PKCS11
4276*7f2fe78bSCy Schubert     id_cryptoctx->creds[cindex]->cert_id = NULL;
4277*7f2fe78bSCy Schubert     id_cryptoctx->creds[cindex]->cert_id_len = 0;
4278*7f2fe78bSCy Schubert #endif
4279*7f2fe78bSCy Schubert     id_cryptoctx->creds[cindex]->key = y;
4280*7f2fe78bSCy Schubert     id_cryptoctx->creds[cindex+1] = NULL;
4281*7f2fe78bSCy Schubert 
4282*7f2fe78bSCy Schubert     retval = 0;
4283*7f2fe78bSCy Schubert 
4284*7f2fe78bSCy Schubert cleanup:
4285*7f2fe78bSCy Schubert     free(fsname);
4286*7f2fe78bSCy Schubert     if (retval != 0 || y == NULL) {
4287*7f2fe78bSCy Schubert         if (x != NULL)
4288*7f2fe78bSCy Schubert             X509_free(x);
4289*7f2fe78bSCy Schubert         if (y != NULL)
4290*7f2fe78bSCy Schubert             EVP_PKEY_free(y);
4291*7f2fe78bSCy Schubert     }
4292*7f2fe78bSCy Schubert     return retval;
4293*7f2fe78bSCy Schubert }
4294*7f2fe78bSCy Schubert 
4295*7f2fe78bSCy Schubert static krb5_error_code
pkinit_get_certs_fs(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_opts * idopts,pkinit_identity_crypto_context id_cryptoctx,krb5_principal princ)4296*7f2fe78bSCy Schubert pkinit_get_certs_fs(krb5_context context,
4297*7f2fe78bSCy Schubert                     pkinit_plg_crypto_context plg_cryptoctx,
4298*7f2fe78bSCy Schubert                     pkinit_req_crypto_context req_cryptoctx,
4299*7f2fe78bSCy Schubert                     pkinit_identity_opts *idopts,
4300*7f2fe78bSCy Schubert                     pkinit_identity_crypto_context id_cryptoctx,
4301*7f2fe78bSCy Schubert                     krb5_principal princ)
4302*7f2fe78bSCy Schubert {
4303*7f2fe78bSCy Schubert     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
4304*7f2fe78bSCy Schubert 
4305*7f2fe78bSCy Schubert     if (idopts->cert_filename == NULL) {
4306*7f2fe78bSCy Schubert         pkiDebug("%s: failed to get user's cert location\n", __FUNCTION__);
4307*7f2fe78bSCy Schubert         goto cleanup;
4308*7f2fe78bSCy Schubert     }
4309*7f2fe78bSCy Schubert 
4310*7f2fe78bSCy Schubert     if (idopts->key_filename == NULL) {
4311*7f2fe78bSCy Schubert         TRACE_PKINIT_NO_PRIVKEY(context);
4312*7f2fe78bSCy Schubert         goto cleanup;
4313*7f2fe78bSCy Schubert     }
4314*7f2fe78bSCy Schubert 
4315*7f2fe78bSCy Schubert     retval = pkinit_load_fs_cert_and_key(context, id_cryptoctx,
4316*7f2fe78bSCy Schubert                                          idopts->cert_filename,
4317*7f2fe78bSCy Schubert                                          idopts->key_filename, 0);
4318*7f2fe78bSCy Schubert cleanup:
4319*7f2fe78bSCy Schubert     return retval;
4320*7f2fe78bSCy Schubert }
4321*7f2fe78bSCy Schubert 
4322*7f2fe78bSCy Schubert static krb5_error_code
pkinit_get_certs_dir(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_opts * idopts,pkinit_identity_crypto_context id_cryptoctx,krb5_principal princ)4323*7f2fe78bSCy Schubert pkinit_get_certs_dir(krb5_context context,
4324*7f2fe78bSCy Schubert                      pkinit_plg_crypto_context plg_cryptoctx,
4325*7f2fe78bSCy Schubert                      pkinit_req_crypto_context req_cryptoctx,
4326*7f2fe78bSCy Schubert                      pkinit_identity_opts *idopts,
4327*7f2fe78bSCy Schubert                      pkinit_identity_crypto_context id_cryptoctx,
4328*7f2fe78bSCy Schubert                      krb5_principal princ)
4329*7f2fe78bSCy Schubert {
4330*7f2fe78bSCy Schubert     krb5_error_code retval = ENOMEM;
4331*7f2fe78bSCy Schubert     DIR *d = NULL;
4332*7f2fe78bSCy Schubert     struct dirent *dentry = NULL;
4333*7f2fe78bSCy Schubert     char certname[1024];
4334*7f2fe78bSCy Schubert     char keyname[1024];
4335*7f2fe78bSCy Schubert     int i = 0, len;
4336*7f2fe78bSCy Schubert     char *dirname, *suf;
4337*7f2fe78bSCy Schubert 
4338*7f2fe78bSCy Schubert     if (idopts->cert_filename == NULL) {
4339*7f2fe78bSCy Schubert         TRACE_PKINIT_NO_CERT(context);
4340*7f2fe78bSCy Schubert         return ENOENT;
4341*7f2fe78bSCy Schubert     }
4342*7f2fe78bSCy Schubert 
4343*7f2fe78bSCy Schubert     dirname = idopts->cert_filename;
4344*7f2fe78bSCy Schubert     d = opendir(dirname);
4345*7f2fe78bSCy Schubert     if (d == NULL)
4346*7f2fe78bSCy Schubert         return errno;
4347*7f2fe78bSCy Schubert 
4348*7f2fe78bSCy Schubert     /*
4349*7f2fe78bSCy Schubert      * We'll assume that certs are named XXX.crt and the corresponding
4350*7f2fe78bSCy Schubert      * key is named XXX.key
4351*7f2fe78bSCy Schubert      */
4352*7f2fe78bSCy Schubert     while ((i < MAX_CREDS_ALLOWED) &&  (dentry = readdir(d)) != NULL) {
4353*7f2fe78bSCy Schubert         /* Ignore subdirectories and anything starting with a dot */
4354*7f2fe78bSCy Schubert #ifdef DT_DIR
4355*7f2fe78bSCy Schubert         if (dentry->d_type == DT_DIR)
4356*7f2fe78bSCy Schubert             continue;
4357*7f2fe78bSCy Schubert #endif
4358*7f2fe78bSCy Schubert         if (dentry->d_name[0] == '.')
4359*7f2fe78bSCy Schubert             continue;
4360*7f2fe78bSCy Schubert         len = strlen(dentry->d_name);
4361*7f2fe78bSCy Schubert         if (len < 5)
4362*7f2fe78bSCy Schubert             continue;
4363*7f2fe78bSCy Schubert         suf = dentry->d_name + (len - 4);
4364*7f2fe78bSCy Schubert         if (strncmp(suf, ".crt", 4) != 0)
4365*7f2fe78bSCy Schubert             continue;
4366*7f2fe78bSCy Schubert 
4367*7f2fe78bSCy Schubert         /* Checked length */
4368*7f2fe78bSCy Schubert         if (strlen(dirname) + strlen(dentry->d_name) + 2 > sizeof(certname)) {
4369*7f2fe78bSCy Schubert             pkiDebug("%s: Path too long -- directory '%s' and file '%s'\n",
4370*7f2fe78bSCy Schubert                      __FUNCTION__, dirname, dentry->d_name);
4371*7f2fe78bSCy Schubert             continue;
4372*7f2fe78bSCy Schubert         }
4373*7f2fe78bSCy Schubert         snprintf(certname, sizeof(certname), "%s/%s", dirname, dentry->d_name);
4374*7f2fe78bSCy Schubert         snprintf(keyname, sizeof(keyname), "%s/%s", dirname, dentry->d_name);
4375*7f2fe78bSCy Schubert         len = strlen(keyname);
4376*7f2fe78bSCy Schubert         keyname[len - 3] = 'k';
4377*7f2fe78bSCy Schubert         keyname[len - 2] = 'e';
4378*7f2fe78bSCy Schubert         keyname[len - 1] = 'y';
4379*7f2fe78bSCy Schubert 
4380*7f2fe78bSCy Schubert         retval = pkinit_load_fs_cert_and_key(context, id_cryptoctx,
4381*7f2fe78bSCy Schubert                                              certname, keyname, i);
4382*7f2fe78bSCy Schubert         if (retval == 0) {
4383*7f2fe78bSCy Schubert             TRACE_PKINIT_LOADED_CERT(context, dentry->d_name);
4384*7f2fe78bSCy Schubert             i++;
4385*7f2fe78bSCy Schubert         }
4386*7f2fe78bSCy Schubert         else
4387*7f2fe78bSCy Schubert             continue;
4388*7f2fe78bSCy Schubert     }
4389*7f2fe78bSCy Schubert 
4390*7f2fe78bSCy Schubert     if (!id_cryptoctx->defer_id_prompt && i == 0) {
4391*7f2fe78bSCy Schubert         TRACE_PKINIT_NO_CERT_AND_KEY(context, idopts->cert_filename);
4392*7f2fe78bSCy Schubert         retval = ENOENT;
4393*7f2fe78bSCy Schubert         goto cleanup;
4394*7f2fe78bSCy Schubert     }
4395*7f2fe78bSCy Schubert 
4396*7f2fe78bSCy Schubert     retval = 0;
4397*7f2fe78bSCy Schubert 
4398*7f2fe78bSCy Schubert cleanup:
4399*7f2fe78bSCy Schubert     if (d)
4400*7f2fe78bSCy Schubert         closedir(d);
4401*7f2fe78bSCy Schubert 
4402*7f2fe78bSCy Schubert     return retval;
4403*7f2fe78bSCy Schubert }
4404*7f2fe78bSCy Schubert 
4405*7f2fe78bSCy Schubert #ifndef WITHOUT_PKCS11
4406*7f2fe78bSCy Schubert static char *
reassemble_pkcs11_name(pkinit_identity_opts * idopts)4407*7f2fe78bSCy Schubert reassemble_pkcs11_name(pkinit_identity_opts *idopts)
4408*7f2fe78bSCy Schubert {
4409*7f2fe78bSCy Schubert     struct k5buf buf;
4410*7f2fe78bSCy Schubert     int n = 0;
4411*7f2fe78bSCy Schubert 
4412*7f2fe78bSCy Schubert     k5_buf_init_dynamic(&buf);
4413*7f2fe78bSCy Schubert     k5_buf_add(&buf, "PKCS11:");
4414*7f2fe78bSCy Schubert     n = 0;
4415*7f2fe78bSCy Schubert     if (idopts->p11_module_name != NULL) {
4416*7f2fe78bSCy Schubert         k5_buf_add_fmt(&buf, "%smodule_name=%s", n++ ? ":" : "",
4417*7f2fe78bSCy Schubert                        idopts->p11_module_name);
4418*7f2fe78bSCy Schubert     }
4419*7f2fe78bSCy Schubert     if (idopts->token_label != NULL) {
4420*7f2fe78bSCy Schubert         k5_buf_add_fmt(&buf, "%stoken=%s", n++ ? ":" : "",
4421*7f2fe78bSCy Schubert                        idopts->token_label);
4422*7f2fe78bSCy Schubert     }
4423*7f2fe78bSCy Schubert     if (idopts->cert_label != NULL) {
4424*7f2fe78bSCy Schubert         k5_buf_add_fmt(&buf, "%scertlabel=%s", n++ ? ":" : "",
4425*7f2fe78bSCy Schubert                        idopts->cert_label);
4426*7f2fe78bSCy Schubert     }
4427*7f2fe78bSCy Schubert     if (idopts->cert_id_string != NULL) {
4428*7f2fe78bSCy Schubert         k5_buf_add_fmt(&buf, "%scertid=%s", n++ ? ":" : "",
4429*7f2fe78bSCy Schubert                        idopts->cert_id_string);
4430*7f2fe78bSCy Schubert     }
4431*7f2fe78bSCy Schubert     if (idopts->slotid != PK_NOSLOT) {
4432*7f2fe78bSCy Schubert         k5_buf_add_fmt(&buf, "%sslotid=%ld", n++ ? ":" : "",
4433*7f2fe78bSCy Schubert                        (long)idopts->slotid);
4434*7f2fe78bSCy Schubert     }
4435*7f2fe78bSCy Schubert     return k5_buf_cstring(&buf);
4436*7f2fe78bSCy Schubert }
4437*7f2fe78bSCy Schubert 
4438*7f2fe78bSCy Schubert static krb5_error_code
load_one_cert(CK_FUNCTION_LIST_PTR p11,CK_SESSION_HANDLE session,pkinit_identity_opts * idopts,pkinit_cred_info * cred_out)4439*7f2fe78bSCy Schubert load_one_cert(CK_FUNCTION_LIST_PTR p11, CK_SESSION_HANDLE session,
4440*7f2fe78bSCy Schubert               pkinit_identity_opts *idopts, pkinit_cred_info *cred_out)
4441*7f2fe78bSCy Schubert {
4442*7f2fe78bSCy Schubert     krb5_error_code ret;
4443*7f2fe78bSCy Schubert     CK_ATTRIBUTE attrs[2];
4444*7f2fe78bSCy Schubert     CK_BYTE_PTR cert = NULL, cert_id = NULL;
4445*7f2fe78bSCy Schubert     CK_RV pret;
4446*7f2fe78bSCy Schubert     const unsigned char *cp;
4447*7f2fe78bSCy Schubert     CK_OBJECT_HANDLE obj;
4448*7f2fe78bSCy Schubert     CK_ULONG count;
4449*7f2fe78bSCy Schubert     X509 *x = NULL;
4450*7f2fe78bSCy Schubert     pkinit_cred_info cred;
4451*7f2fe78bSCy Schubert 
4452*7f2fe78bSCy Schubert     *cred_out = NULL;
4453*7f2fe78bSCy Schubert 
4454*7f2fe78bSCy Schubert     /* Look for X.509 cert. */
4455*7f2fe78bSCy Schubert     pret = p11->C_FindObjects(session, &obj, 1, &count);
4456*7f2fe78bSCy Schubert     if (pret != CKR_OK || count <= 0)
4457*7f2fe78bSCy Schubert         return 0;
4458*7f2fe78bSCy Schubert 
4459*7f2fe78bSCy Schubert     /* Get cert and id len. */
4460*7f2fe78bSCy Schubert     attrs[0].type = CKA_VALUE;
4461*7f2fe78bSCy Schubert     attrs[0].pValue = NULL;
4462*7f2fe78bSCy Schubert     attrs[0].ulValueLen = 0;
4463*7f2fe78bSCy Schubert     attrs[1].type = CKA_ID;
4464*7f2fe78bSCy Schubert     attrs[1].pValue = NULL;
4465*7f2fe78bSCy Schubert     attrs[1].ulValueLen = 0;
4466*7f2fe78bSCy Schubert     pret = p11->C_GetAttributeValue(session, obj, attrs, 2);
4467*7f2fe78bSCy Schubert     if (pret != CKR_OK && pret != CKR_BUFFER_TOO_SMALL) {
4468*7f2fe78bSCy Schubert         pkiDebug("C_GetAttributeValue: %s\n", pkcs11err(pret));
4469*7f2fe78bSCy Schubert         ret = KRB5KDC_ERR_PREAUTH_FAILED;
4470*7f2fe78bSCy Schubert         goto cleanup;
4471*7f2fe78bSCy Schubert     }
4472*7f2fe78bSCy Schubert 
4473*7f2fe78bSCy Schubert     /* Allocate buffers and read the cert and id. */
4474*7f2fe78bSCy Schubert     cert = k5alloc(attrs[0].ulValueLen + 1, &ret);
4475*7f2fe78bSCy Schubert     if (cert == NULL)
4476*7f2fe78bSCy Schubert         goto cleanup;
4477*7f2fe78bSCy Schubert     cert_id = k5alloc(attrs[1].ulValueLen + 1, &ret);
4478*7f2fe78bSCy Schubert     if (cert_id == NULL)
4479*7f2fe78bSCy Schubert         goto cleanup;
4480*7f2fe78bSCy Schubert     attrs[0].type = CKA_VALUE;
4481*7f2fe78bSCy Schubert     attrs[0].pValue = cert;
4482*7f2fe78bSCy Schubert     attrs[1].type = CKA_ID;
4483*7f2fe78bSCy Schubert     attrs[1].pValue = cert_id;
4484*7f2fe78bSCy Schubert     pret = p11->C_GetAttributeValue(session, obj, attrs, 2);
4485*7f2fe78bSCy Schubert     if (pret != CKR_OK) {
4486*7f2fe78bSCy Schubert         pkiDebug("C_GetAttributeValue: %s\n", pkcs11err(pret));
4487*7f2fe78bSCy Schubert         ret = KRB5KDC_ERR_PREAUTH_FAILED;
4488*7f2fe78bSCy Schubert         goto cleanup;
4489*7f2fe78bSCy Schubert     }
4490*7f2fe78bSCy Schubert 
4491*7f2fe78bSCy Schubert     pkiDebug("cert: size %d, id %d, idlen %d\n", (int)attrs[0].ulValueLen,
4492*7f2fe78bSCy Schubert              (int)cert_id[0], (int)attrs[1].ulValueLen);
4493*7f2fe78bSCy Schubert 
4494*7f2fe78bSCy Schubert     cp = (unsigned char *)cert;
4495*7f2fe78bSCy Schubert     x = d2i_X509(NULL, &cp, (int)attrs[0].ulValueLen);
4496*7f2fe78bSCy Schubert     if (x == NULL) {
4497*7f2fe78bSCy Schubert         ret = KRB5KDC_ERR_PREAUTH_FAILED;
4498*7f2fe78bSCy Schubert         goto cleanup;
4499*7f2fe78bSCy Schubert     }
4500*7f2fe78bSCy Schubert 
4501*7f2fe78bSCy Schubert     cred = k5alloc(sizeof(struct _pkinit_cred_info), &ret);
4502*7f2fe78bSCy Schubert     if (cred == NULL)
4503*7f2fe78bSCy Schubert         goto cleanup;
4504*7f2fe78bSCy Schubert 
4505*7f2fe78bSCy Schubert     cred->name = reassemble_pkcs11_name(idopts);
4506*7f2fe78bSCy Schubert     cred->cert = x;
4507*7f2fe78bSCy Schubert     cred->key = NULL;
4508*7f2fe78bSCy Schubert     cred->cert_id = cert_id;
4509*7f2fe78bSCy Schubert     cred->cert_id_len = attrs[1].ulValueLen;
4510*7f2fe78bSCy Schubert 
4511*7f2fe78bSCy Schubert     *cred_out = cred;
4512*7f2fe78bSCy Schubert     cert_id = NULL;
4513*7f2fe78bSCy Schubert     ret = 0;
4514*7f2fe78bSCy Schubert 
4515*7f2fe78bSCy Schubert cleanup:
4516*7f2fe78bSCy Schubert     free(cert);
4517*7f2fe78bSCy Schubert     free(cert_id);
4518*7f2fe78bSCy Schubert     return ret;
4519*7f2fe78bSCy Schubert }
4520*7f2fe78bSCy Schubert 
4521*7f2fe78bSCy Schubert static krb5_error_code
pkinit_get_certs_pkcs11(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_opts * idopts,pkinit_identity_crypto_context id_cryptoctx,krb5_principal princ)4522*7f2fe78bSCy Schubert pkinit_get_certs_pkcs11(krb5_context context,
4523*7f2fe78bSCy Schubert                         pkinit_plg_crypto_context plg_cryptoctx,
4524*7f2fe78bSCy Schubert                         pkinit_req_crypto_context req_cryptoctx,
4525*7f2fe78bSCy Schubert                         pkinit_identity_opts *idopts,
4526*7f2fe78bSCy Schubert                         pkinit_identity_crypto_context id_cryptoctx,
4527*7f2fe78bSCy Schubert                         krb5_principal princ)
4528*7f2fe78bSCy Schubert {
4529*7f2fe78bSCy Schubert     CK_OBJECT_CLASS cls;
4530*7f2fe78bSCy Schubert     CK_ATTRIBUTE attrs[4];
4531*7f2fe78bSCy Schubert     CK_CERTIFICATE_TYPE certtype;
4532*7f2fe78bSCy Schubert     int i;
4533*7f2fe78bSCy Schubert     unsigned int nattrs;
4534*7f2fe78bSCy Schubert     krb5_error_code ret;
4535*7f2fe78bSCy Schubert     CK_RV pret;
4536*7f2fe78bSCy Schubert 
4537*7f2fe78bSCy Schubert     /* Copy stuff from idopts -> id_cryptoctx */
4538*7f2fe78bSCy Schubert     if (idopts->p11_module_name != NULL) {
4539*7f2fe78bSCy Schubert         free(id_cryptoctx->p11_module_name);
4540*7f2fe78bSCy Schubert         id_cryptoctx->p11_module_name = strdup(idopts->p11_module_name);
4541*7f2fe78bSCy Schubert         if (id_cryptoctx->p11_module_name == NULL)
4542*7f2fe78bSCy Schubert             return ENOMEM;
4543*7f2fe78bSCy Schubert     }
4544*7f2fe78bSCy Schubert     if (idopts->token_label != NULL) {
4545*7f2fe78bSCy Schubert         id_cryptoctx->token_label = strdup(idopts->token_label);
4546*7f2fe78bSCy Schubert         if (id_cryptoctx->token_label == NULL)
4547*7f2fe78bSCy Schubert             return ENOMEM;
4548*7f2fe78bSCy Schubert     }
4549*7f2fe78bSCy Schubert     if (idopts->cert_label != NULL) {
4550*7f2fe78bSCy Schubert         id_cryptoctx->cert_label = strdup(idopts->cert_label);
4551*7f2fe78bSCy Schubert         if (id_cryptoctx->cert_label == NULL)
4552*7f2fe78bSCy Schubert             return ENOMEM;
4553*7f2fe78bSCy Schubert     }
4554*7f2fe78bSCy Schubert     /* Convert the ascii cert_id string into a binary blob */
4555*7f2fe78bSCy Schubert     if (idopts->cert_id_string != NULL) {
4556*7f2fe78bSCy Schubert         ret = k5_hex_decode(idopts->cert_id_string, &id_cryptoctx->cert_id,
4557*7f2fe78bSCy Schubert                             &id_cryptoctx->cert_id_len);
4558*7f2fe78bSCy Schubert         if (ret) {
4559*7f2fe78bSCy Schubert             pkiDebug("Failed to convert certid string [%s]\n",
4560*7f2fe78bSCy Schubert                      idopts->cert_id_string);
4561*7f2fe78bSCy Schubert             return ret;
4562*7f2fe78bSCy Schubert         }
4563*7f2fe78bSCy Schubert     }
4564*7f2fe78bSCy Schubert     id_cryptoctx->slotid = idopts->slotid;
4565*7f2fe78bSCy Schubert     id_cryptoctx->pkcs11_method = 1;
4566*7f2fe78bSCy Schubert 
4567*7f2fe78bSCy Schubert     ret = pkinit_open_session(context, id_cryptoctx);
4568*7f2fe78bSCy Schubert     if (ret)
4569*7f2fe78bSCy Schubert         return ret;
4570*7f2fe78bSCy Schubert     if (id_cryptoctx->defer_id_prompt) {
4571*7f2fe78bSCy Schubert         /*
4572*7f2fe78bSCy Schubert          * We need to reset all of the PKCS#11 state, so that the next time we
4573*7f2fe78bSCy Schubert          * poke at it, it'll be in as close to the state it was in after we
4574*7f2fe78bSCy Schubert          * loaded it the first time as we can make it.
4575*7f2fe78bSCy Schubert          */
4576*7f2fe78bSCy Schubert         pkinit_fini_pkcs11(id_cryptoctx);
4577*7f2fe78bSCy Schubert         pkinit_init_pkcs11(id_cryptoctx);
4578*7f2fe78bSCy Schubert         return 0;
4579*7f2fe78bSCy Schubert     }
4580*7f2fe78bSCy Schubert 
4581*7f2fe78bSCy Schubert     /*
4582*7f2fe78bSCy Schubert      * We'd like to use CKM_SHA256_RSA_PKCS for signing if it's available, but
4583*7f2fe78bSCy Schubert      * historically many cards seem to be confused about whether they are
4584*7f2fe78bSCy Schubert      * capable of mechanisms or not. The safe thing seems to be to ignore the
4585*7f2fe78bSCy Schubert      * mechanism list, always use CKM_RSA_PKCS and calculate the sha256 digest
4586*7f2fe78bSCy Schubert      * ourselves.
4587*7f2fe78bSCy Schubert      */
4588*7f2fe78bSCy Schubert     id_cryptoctx->mech = CKM_RSA_PKCS;
4589*7f2fe78bSCy Schubert 
4590*7f2fe78bSCy Schubert     cls = CKO_CERTIFICATE;
4591*7f2fe78bSCy Schubert     attrs[0].type = CKA_CLASS;
4592*7f2fe78bSCy Schubert     attrs[0].pValue = &cls;
4593*7f2fe78bSCy Schubert     attrs[0].ulValueLen = sizeof(cls);
4594*7f2fe78bSCy Schubert 
4595*7f2fe78bSCy Schubert     certtype = CKC_X_509;
4596*7f2fe78bSCy Schubert     attrs[1].type = CKA_CERTIFICATE_TYPE;
4597*7f2fe78bSCy Schubert     attrs[1].pValue = &certtype;
4598*7f2fe78bSCy Schubert     attrs[1].ulValueLen = sizeof(certtype);
4599*7f2fe78bSCy Schubert 
4600*7f2fe78bSCy Schubert     nattrs = 2;
4601*7f2fe78bSCy Schubert 
4602*7f2fe78bSCy Schubert     /* If a cert id and/or label were given, use them too */
4603*7f2fe78bSCy Schubert     if (id_cryptoctx->cert_id_len > 0) {
4604*7f2fe78bSCy Schubert         attrs[nattrs].type = CKA_ID;
4605*7f2fe78bSCy Schubert         attrs[nattrs].pValue = id_cryptoctx->cert_id;
4606*7f2fe78bSCy Schubert         attrs[nattrs].ulValueLen = id_cryptoctx->cert_id_len;
4607*7f2fe78bSCy Schubert         nattrs++;
4608*7f2fe78bSCy Schubert     }
4609*7f2fe78bSCy Schubert     if (id_cryptoctx->cert_label != NULL) {
4610*7f2fe78bSCy Schubert         attrs[nattrs].type = CKA_LABEL;
4611*7f2fe78bSCy Schubert         attrs[nattrs].pValue = id_cryptoctx->cert_label;
4612*7f2fe78bSCy Schubert         attrs[nattrs].ulValueLen = strlen(id_cryptoctx->cert_label);
4613*7f2fe78bSCy Schubert         nattrs++;
4614*7f2fe78bSCy Schubert     }
4615*7f2fe78bSCy Schubert 
4616*7f2fe78bSCy Schubert     pret = id_cryptoctx->p11->C_FindObjectsInit(id_cryptoctx->session, attrs,
4617*7f2fe78bSCy Schubert                                                 nattrs);
4618*7f2fe78bSCy Schubert     if (pret != CKR_OK) {
4619*7f2fe78bSCy Schubert         pkiDebug("C_FindObjectsInit: %s\n", pkcs11err(pret));
4620*7f2fe78bSCy Schubert         return KRB5KDC_ERR_PREAUTH_FAILED;
4621*7f2fe78bSCy Schubert     }
4622*7f2fe78bSCy Schubert 
4623*7f2fe78bSCy Schubert     for (i = 0; i < MAX_CREDS_ALLOWED; i++) {
4624*7f2fe78bSCy Schubert         ret = load_one_cert(id_cryptoctx->p11, id_cryptoctx->session, idopts,
4625*7f2fe78bSCy Schubert                             &id_cryptoctx->creds[i]);
4626*7f2fe78bSCy Schubert         if (ret)
4627*7f2fe78bSCy Schubert             return ret;
4628*7f2fe78bSCy Schubert         if (id_cryptoctx->creds[i] == NULL)
4629*7f2fe78bSCy Schubert             break;
4630*7f2fe78bSCy Schubert     }
4631*7f2fe78bSCy Schubert     if (i == MAX_CREDS_ALLOWED)
4632*7f2fe78bSCy Schubert         return KRB5KDC_ERR_PREAUTH_FAILED;
4633*7f2fe78bSCy Schubert 
4634*7f2fe78bSCy Schubert     id_cryptoctx->p11->C_FindObjectsFinal(id_cryptoctx->session);
4635*7f2fe78bSCy Schubert 
4636*7f2fe78bSCy Schubert     /* Check if we found no certs. */
4637*7f2fe78bSCy Schubert     if (id_cryptoctx->creds[0] == NULL)
4638*7f2fe78bSCy Schubert         return KRB5KDC_ERR_PREAUTH_FAILED;
4639*7f2fe78bSCy Schubert     return 0;
4640*7f2fe78bSCy Schubert }
4641*7f2fe78bSCy Schubert 
4642*7f2fe78bSCy Schubert #endif /* !WITHOUT_PKCS11 */
4643*7f2fe78bSCy Schubert 
4644*7f2fe78bSCy Schubert 
4645*7f2fe78bSCy Schubert static void
free_cred_info(krb5_context context,pkinit_identity_crypto_context id_cryptoctx,struct _pkinit_cred_info * cred)4646*7f2fe78bSCy Schubert free_cred_info(krb5_context context,
4647*7f2fe78bSCy Schubert                pkinit_identity_crypto_context id_cryptoctx,
4648*7f2fe78bSCy Schubert                struct _pkinit_cred_info *cred)
4649*7f2fe78bSCy Schubert {
4650*7f2fe78bSCy Schubert     if (cred != NULL) {
4651*7f2fe78bSCy Schubert         if (cred->cert != NULL)
4652*7f2fe78bSCy Schubert             X509_free(cred->cert);
4653*7f2fe78bSCy Schubert         if (cred->key != NULL)
4654*7f2fe78bSCy Schubert             EVP_PKEY_free(cred->key);
4655*7f2fe78bSCy Schubert #ifndef WITHOUT_PKCS11
4656*7f2fe78bSCy Schubert         free(cred->cert_id);
4657*7f2fe78bSCy Schubert #endif
4658*7f2fe78bSCy Schubert         free(cred->name);
4659*7f2fe78bSCy Schubert         free(cred);
4660*7f2fe78bSCy Schubert     }
4661*7f2fe78bSCy Schubert }
4662*7f2fe78bSCy Schubert 
4663*7f2fe78bSCy Schubert krb5_error_code
crypto_free_cert_info(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx)4664*7f2fe78bSCy Schubert crypto_free_cert_info(krb5_context context,
4665*7f2fe78bSCy Schubert                       pkinit_plg_crypto_context plg_cryptoctx,
4666*7f2fe78bSCy Schubert                       pkinit_req_crypto_context req_cryptoctx,
4667*7f2fe78bSCy Schubert                       pkinit_identity_crypto_context id_cryptoctx)
4668*7f2fe78bSCy Schubert {
4669*7f2fe78bSCy Schubert     int i;
4670*7f2fe78bSCy Schubert 
4671*7f2fe78bSCy Schubert     if (id_cryptoctx == NULL)
4672*7f2fe78bSCy Schubert         return EINVAL;
4673*7f2fe78bSCy Schubert 
4674*7f2fe78bSCy Schubert     for (i = 0; i < MAX_CREDS_ALLOWED; i++) {
4675*7f2fe78bSCy Schubert         if (id_cryptoctx->creds[i] != NULL) {
4676*7f2fe78bSCy Schubert             free_cred_info(context, id_cryptoctx, id_cryptoctx->creds[i]);
4677*7f2fe78bSCy Schubert             id_cryptoctx->creds[i] = NULL;
4678*7f2fe78bSCy Schubert         }
4679*7f2fe78bSCy Schubert     }
4680*7f2fe78bSCy Schubert     return 0;
4681*7f2fe78bSCy Schubert }
4682*7f2fe78bSCy Schubert 
4683*7f2fe78bSCy Schubert krb5_error_code
crypto_load_certs(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_opts * idopts,pkinit_identity_crypto_context id_cryptoctx,krb5_principal princ,krb5_boolean defer_id_prompts)4684*7f2fe78bSCy Schubert crypto_load_certs(krb5_context context,
4685*7f2fe78bSCy Schubert                   pkinit_plg_crypto_context plg_cryptoctx,
4686*7f2fe78bSCy Schubert                   pkinit_req_crypto_context req_cryptoctx,
4687*7f2fe78bSCy Schubert                   pkinit_identity_opts *idopts,
4688*7f2fe78bSCy Schubert                   pkinit_identity_crypto_context id_cryptoctx,
4689*7f2fe78bSCy Schubert                   krb5_principal princ,
4690*7f2fe78bSCy Schubert                   krb5_boolean defer_id_prompts)
4691*7f2fe78bSCy Schubert {
4692*7f2fe78bSCy Schubert     krb5_error_code retval;
4693*7f2fe78bSCy Schubert 
4694*7f2fe78bSCy Schubert     id_cryptoctx->defer_id_prompt = defer_id_prompts;
4695*7f2fe78bSCy Schubert 
4696*7f2fe78bSCy Schubert     switch(idopts->idtype) {
4697*7f2fe78bSCy Schubert     case IDTYPE_FILE:
4698*7f2fe78bSCy Schubert         retval = pkinit_get_certs_fs(context, plg_cryptoctx,
4699*7f2fe78bSCy Schubert                                      req_cryptoctx, idopts,
4700*7f2fe78bSCy Schubert                                      id_cryptoctx, princ);
4701*7f2fe78bSCy Schubert         break;
4702*7f2fe78bSCy Schubert     case IDTYPE_DIR:
4703*7f2fe78bSCy Schubert         retval = pkinit_get_certs_dir(context, plg_cryptoctx,
4704*7f2fe78bSCy Schubert                                       req_cryptoctx, idopts,
4705*7f2fe78bSCy Schubert                                       id_cryptoctx, princ);
4706*7f2fe78bSCy Schubert         break;
4707*7f2fe78bSCy Schubert #ifndef WITHOUT_PKCS11
4708*7f2fe78bSCy Schubert     case IDTYPE_PKCS11:
4709*7f2fe78bSCy Schubert         retval = pkinit_get_certs_pkcs11(context, plg_cryptoctx,
4710*7f2fe78bSCy Schubert                                          req_cryptoctx, idopts,
4711*7f2fe78bSCy Schubert                                          id_cryptoctx, princ);
4712*7f2fe78bSCy Schubert         break;
4713*7f2fe78bSCy Schubert #endif
4714*7f2fe78bSCy Schubert     case IDTYPE_PKCS12:
4715*7f2fe78bSCy Schubert         retval = pkinit_get_certs_pkcs12(context, plg_cryptoctx,
4716*7f2fe78bSCy Schubert                                          req_cryptoctx, idopts,
4717*7f2fe78bSCy Schubert                                          id_cryptoctx, princ);
4718*7f2fe78bSCy Schubert         break;
4719*7f2fe78bSCy Schubert     default:
4720*7f2fe78bSCy Schubert         retval = EINVAL;
4721*7f2fe78bSCy Schubert     }
4722*7f2fe78bSCy Schubert     if (retval)
4723*7f2fe78bSCy Schubert         goto cleanup;
4724*7f2fe78bSCy Schubert 
4725*7f2fe78bSCy Schubert cleanup:
4726*7f2fe78bSCy Schubert     return retval;
4727*7f2fe78bSCy Schubert }
4728*7f2fe78bSCy Schubert 
4729*7f2fe78bSCy Schubert /*
4730*7f2fe78bSCy Schubert  * Get certificate Key Usage and Extended Key Usage
4731*7f2fe78bSCy Schubert  */
4732*7f2fe78bSCy Schubert static krb5_error_code
crypto_retrieve_X509_key_usage(krb5_context context,pkinit_plg_crypto_context plgcctx,pkinit_req_crypto_context reqcctx,X509 * x,unsigned int * ret_ku_bits,unsigned int * ret_eku_bits)4733*7f2fe78bSCy Schubert crypto_retrieve_X509_key_usage(krb5_context context,
4734*7f2fe78bSCy Schubert                                pkinit_plg_crypto_context plgcctx,
4735*7f2fe78bSCy Schubert                                pkinit_req_crypto_context reqcctx,
4736*7f2fe78bSCy Schubert                                X509 *x,
4737*7f2fe78bSCy Schubert                                unsigned int *ret_ku_bits,
4738*7f2fe78bSCy Schubert                                unsigned int *ret_eku_bits)
4739*7f2fe78bSCy Schubert {
4740*7f2fe78bSCy Schubert     krb5_error_code retval = 0;
4741*7f2fe78bSCy Schubert     int i;
4742*7f2fe78bSCy Schubert     unsigned int eku_bits = 0, ku_bits = 0;
4743*7f2fe78bSCy Schubert     ASN1_BIT_STRING *usage = NULL;
4744*7f2fe78bSCy Schubert 
4745*7f2fe78bSCy Schubert     if (ret_ku_bits == NULL && ret_eku_bits == NULL)
4746*7f2fe78bSCy Schubert         return EINVAL;
4747*7f2fe78bSCy Schubert 
4748*7f2fe78bSCy Schubert     if (ret_eku_bits)
4749*7f2fe78bSCy Schubert         *ret_eku_bits = 0;
4750*7f2fe78bSCy Schubert     else {
4751*7f2fe78bSCy Schubert         pkiDebug("%s: EKUs not requested, not checking\n", __FUNCTION__);
4752*7f2fe78bSCy Schubert         goto check_kus;
4753*7f2fe78bSCy Schubert     }
4754*7f2fe78bSCy Schubert 
4755*7f2fe78bSCy Schubert     /* Start with Extended Key usage */
4756*7f2fe78bSCy Schubert     i = X509_get_ext_by_NID(x, NID_ext_key_usage, -1);
4757*7f2fe78bSCy Schubert     if (i >= 0) {
4758*7f2fe78bSCy Schubert         EXTENDED_KEY_USAGE *eku;
4759*7f2fe78bSCy Schubert 
4760*7f2fe78bSCy Schubert         eku = X509_get_ext_d2i(x, NID_ext_key_usage, NULL, NULL);
4761*7f2fe78bSCy Schubert         if (eku) {
4762*7f2fe78bSCy Schubert             for (i = 0; i < sk_ASN1_OBJECT_num(eku); i++) {
4763*7f2fe78bSCy Schubert                 ASN1_OBJECT *certoid;
4764*7f2fe78bSCy Schubert                 certoid = sk_ASN1_OBJECT_value(eku, i);
4765*7f2fe78bSCy Schubert                 if ((OBJ_cmp(certoid, plgcctx->id_pkinit_KPClientAuth)) == 0)
4766*7f2fe78bSCy Schubert                     eku_bits |= PKINIT_EKU_PKINIT;
4767*7f2fe78bSCy Schubert                 else if ((OBJ_cmp(certoid, OBJ_nid2obj(NID_ms_smartcard_login))) == 0)
4768*7f2fe78bSCy Schubert                     eku_bits |= PKINIT_EKU_MSSCLOGIN;
4769*7f2fe78bSCy Schubert                 else if ((OBJ_cmp(certoid, OBJ_nid2obj(NID_client_auth))) == 0)
4770*7f2fe78bSCy Schubert                     eku_bits |= PKINIT_EKU_CLIENTAUTH;
4771*7f2fe78bSCy Schubert                 else if ((OBJ_cmp(certoid, OBJ_nid2obj(NID_email_protect))) == 0)
4772*7f2fe78bSCy Schubert                     eku_bits |= PKINIT_EKU_EMAILPROTECTION;
4773*7f2fe78bSCy Schubert             }
4774*7f2fe78bSCy Schubert             EXTENDED_KEY_USAGE_free(eku);
4775*7f2fe78bSCy Schubert         }
4776*7f2fe78bSCy Schubert     }
4777*7f2fe78bSCy Schubert     pkiDebug("%s: returning eku 0x%08x\n", __FUNCTION__, eku_bits);
4778*7f2fe78bSCy Schubert     *ret_eku_bits = eku_bits;
4779*7f2fe78bSCy Schubert 
4780*7f2fe78bSCy Schubert check_kus:
4781*7f2fe78bSCy Schubert     /* Now the Key Usage bits */
4782*7f2fe78bSCy Schubert     if (ret_ku_bits)
4783*7f2fe78bSCy Schubert         *ret_ku_bits = 0;
4784*7f2fe78bSCy Schubert     else {
4785*7f2fe78bSCy Schubert         pkiDebug("%s: KUs not requested, not checking\n", __FUNCTION__);
4786*7f2fe78bSCy Schubert         goto out;
4787*7f2fe78bSCy Schubert     }
4788*7f2fe78bSCy Schubert 
4789*7f2fe78bSCy Schubert     /* Make sure usage exists before checking bits */
4790*7f2fe78bSCy Schubert     X509_check_ca(x);
4791*7f2fe78bSCy Schubert     usage = X509_get_ext_d2i(x, NID_key_usage, NULL, NULL);
4792*7f2fe78bSCy Schubert     if (usage) {
4793*7f2fe78bSCy Schubert         if (!ku_reject(x, X509v3_KU_DIGITAL_SIGNATURE))
4794*7f2fe78bSCy Schubert             ku_bits |= PKINIT_KU_DIGITALSIGNATURE;
4795*7f2fe78bSCy Schubert         if (!ku_reject(x, X509v3_KU_KEY_ENCIPHERMENT))
4796*7f2fe78bSCy Schubert             ku_bits |= PKINIT_KU_KEYENCIPHERMENT;
4797*7f2fe78bSCy Schubert         ASN1_BIT_STRING_free(usage);
4798*7f2fe78bSCy Schubert     }
4799*7f2fe78bSCy Schubert 
4800*7f2fe78bSCy Schubert     pkiDebug("%s: returning ku 0x%08x\n", __FUNCTION__, ku_bits);
4801*7f2fe78bSCy Schubert     *ret_ku_bits = ku_bits;
4802*7f2fe78bSCy Schubert     retval = 0;
4803*7f2fe78bSCy Schubert out:
4804*7f2fe78bSCy Schubert     return retval;
4805*7f2fe78bSCy Schubert }
4806*7f2fe78bSCy Schubert 
4807*7f2fe78bSCy Schubert static krb5_error_code
rfc2253_name(X509_NAME * name,char ** str_out)4808*7f2fe78bSCy Schubert rfc2253_name(X509_NAME *name, char **str_out)
4809*7f2fe78bSCy Schubert {
4810*7f2fe78bSCy Schubert     BIO *b = NULL;
4811*7f2fe78bSCy Schubert     char *str;
4812*7f2fe78bSCy Schubert 
4813*7f2fe78bSCy Schubert     *str_out = NULL;
4814*7f2fe78bSCy Schubert     b = BIO_new(BIO_s_mem());
4815*7f2fe78bSCy Schubert     if (b == NULL)
4816*7f2fe78bSCy Schubert         return ENOMEM;
4817*7f2fe78bSCy Schubert     if (X509_NAME_print_ex(b, name, 0, XN_FLAG_SEP_COMMA_PLUS) < 0)
4818*7f2fe78bSCy Schubert         goto error;
4819*7f2fe78bSCy Schubert     str = calloc(BIO_number_written(b) + 1, 1);
4820*7f2fe78bSCy Schubert     if (str == NULL)
4821*7f2fe78bSCy Schubert         goto error;
4822*7f2fe78bSCy Schubert     BIO_read(b, str, BIO_number_written(b));
4823*7f2fe78bSCy Schubert     BIO_free(b);
4824*7f2fe78bSCy Schubert     *str_out = str;
4825*7f2fe78bSCy Schubert     return 0;
4826*7f2fe78bSCy Schubert 
4827*7f2fe78bSCy Schubert error:
4828*7f2fe78bSCy Schubert     BIO_free(b);
4829*7f2fe78bSCy Schubert     return ENOMEM;
4830*7f2fe78bSCy Schubert }
4831*7f2fe78bSCy Schubert 
4832*7f2fe78bSCy Schubert /*
4833*7f2fe78bSCy Schubert  * Get number of certificates available after crypto_load_certs()
4834*7f2fe78bSCy Schubert  */
4835*7f2fe78bSCy Schubert static krb5_error_code
crypto_cert_get_count(pkinit_identity_crypto_context id_cryptoctx,int * cert_count)4836*7f2fe78bSCy Schubert crypto_cert_get_count(pkinit_identity_crypto_context id_cryptoctx,
4837*7f2fe78bSCy Schubert                       int *cert_count)
4838*7f2fe78bSCy Schubert {
4839*7f2fe78bSCy Schubert     int count;
4840*7f2fe78bSCy Schubert 
4841*7f2fe78bSCy Schubert     *cert_count = 0;
4842*7f2fe78bSCy Schubert     if (id_cryptoctx == NULL || id_cryptoctx->creds[0] == NULL)
4843*7f2fe78bSCy Schubert         return EINVAL;
4844*7f2fe78bSCy Schubert 
4845*7f2fe78bSCy Schubert     for (count = 0;
4846*7f2fe78bSCy Schubert          count <= MAX_CREDS_ALLOWED && id_cryptoctx->creds[count] != NULL;
4847*7f2fe78bSCy Schubert          count++);
4848*7f2fe78bSCy Schubert     *cert_count = count;
4849*7f2fe78bSCy Schubert     return 0;
4850*7f2fe78bSCy Schubert }
4851*7f2fe78bSCy Schubert 
4852*7f2fe78bSCy Schubert void
crypto_cert_free_matching_data(krb5_context context,pkinit_cert_matching_data * md)4853*7f2fe78bSCy Schubert crypto_cert_free_matching_data(krb5_context context,
4854*7f2fe78bSCy Schubert                                pkinit_cert_matching_data *md)
4855*7f2fe78bSCy Schubert {
4856*7f2fe78bSCy Schubert     int i;
4857*7f2fe78bSCy Schubert 
4858*7f2fe78bSCy Schubert     if (md == NULL)
4859*7f2fe78bSCy Schubert         return;
4860*7f2fe78bSCy Schubert     free(md->subject_dn);
4861*7f2fe78bSCy Schubert     free(md->issuer_dn);
4862*7f2fe78bSCy Schubert     for (i = 0; md->sans != NULL && md->sans[i] != NULL; i++)
4863*7f2fe78bSCy Schubert         krb5_free_principal(context, md->sans[i]);
4864*7f2fe78bSCy Schubert     free(md->sans);
4865*7f2fe78bSCy Schubert     for (i = 0; md->upns != NULL && md->upns[i] != NULL; i++)
4866*7f2fe78bSCy Schubert         free(md->upns[i]);
4867*7f2fe78bSCy Schubert     free(md->upns);
4868*7f2fe78bSCy Schubert     free(md);
4869*7f2fe78bSCy Schubert }
4870*7f2fe78bSCy Schubert 
4871*7f2fe78bSCy Schubert /*
4872*7f2fe78bSCy Schubert  * Free certificate matching data.
4873*7f2fe78bSCy Schubert  */
4874*7f2fe78bSCy Schubert void
crypto_cert_free_matching_data_list(krb5_context context,pkinit_cert_matching_data ** list)4875*7f2fe78bSCy Schubert crypto_cert_free_matching_data_list(krb5_context context,
4876*7f2fe78bSCy Schubert                                     pkinit_cert_matching_data **list)
4877*7f2fe78bSCy Schubert {
4878*7f2fe78bSCy Schubert     int i;
4879*7f2fe78bSCy Schubert 
4880*7f2fe78bSCy Schubert     for (i = 0; list != NULL && list[i] != NULL; i++)
4881*7f2fe78bSCy Schubert         crypto_cert_free_matching_data(context, list[i]);
4882*7f2fe78bSCy Schubert     free(list);
4883*7f2fe78bSCy Schubert }
4884*7f2fe78bSCy Schubert 
4885*7f2fe78bSCy Schubert /*
4886*7f2fe78bSCy Schubert  * Get certificate matching data for cert.
4887*7f2fe78bSCy Schubert  */
4888*7f2fe78bSCy Schubert static krb5_error_code
get_matching_data(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,X509 * cert,pkinit_cert_matching_data ** md_out)4889*7f2fe78bSCy Schubert get_matching_data(krb5_context context,
4890*7f2fe78bSCy Schubert                   pkinit_plg_crypto_context plg_cryptoctx,
4891*7f2fe78bSCy Schubert                   pkinit_req_crypto_context req_cryptoctx, X509 *cert,
4892*7f2fe78bSCy Schubert                   pkinit_cert_matching_data **md_out)
4893*7f2fe78bSCy Schubert {
4894*7f2fe78bSCy Schubert     krb5_error_code ret = ENOMEM;
4895*7f2fe78bSCy Schubert     pkinit_cert_matching_data *md = NULL;
4896*7f2fe78bSCy Schubert 
4897*7f2fe78bSCy Schubert     *md_out = NULL;
4898*7f2fe78bSCy Schubert 
4899*7f2fe78bSCy Schubert     md = calloc(1, sizeof(*md));
4900*7f2fe78bSCy Schubert     if (md == NULL)
4901*7f2fe78bSCy Schubert         goto cleanup;
4902*7f2fe78bSCy Schubert 
4903*7f2fe78bSCy Schubert     ret = rfc2253_name(X509_get_subject_name(cert), &md->subject_dn);
4904*7f2fe78bSCy Schubert     if (ret)
4905*7f2fe78bSCy Schubert         goto cleanup;
4906*7f2fe78bSCy Schubert     ret = rfc2253_name(X509_get_issuer_name(cert), &md->issuer_dn);
4907*7f2fe78bSCy Schubert     if (ret)
4908*7f2fe78bSCy Schubert         goto cleanup;
4909*7f2fe78bSCy Schubert 
4910*7f2fe78bSCy Schubert     /* Get the SAN data. */
4911*7f2fe78bSCy Schubert     ret = crypto_retrieve_X509_sans(context, plg_cryptoctx, req_cryptoctx,
4912*7f2fe78bSCy Schubert                                     cert, &md->sans, &md->upns, NULL);
4913*7f2fe78bSCy Schubert     if (ret)
4914*7f2fe78bSCy Schubert         goto cleanup;
4915*7f2fe78bSCy Schubert 
4916*7f2fe78bSCy Schubert     /* Get the KU and EKU data. */
4917*7f2fe78bSCy Schubert     ret = crypto_retrieve_X509_key_usage(context, plg_cryptoctx,
4918*7f2fe78bSCy Schubert                                          req_cryptoctx, cert, &md->ku_bits,
4919*7f2fe78bSCy Schubert                                          &md->eku_bits);
4920*7f2fe78bSCy Schubert     if (ret)
4921*7f2fe78bSCy Schubert         goto cleanup;
4922*7f2fe78bSCy Schubert 
4923*7f2fe78bSCy Schubert     *md_out = md;
4924*7f2fe78bSCy Schubert     md = NULL;
4925*7f2fe78bSCy Schubert 
4926*7f2fe78bSCy Schubert cleanup:
4927*7f2fe78bSCy Schubert     crypto_cert_free_matching_data(context, md);
4928*7f2fe78bSCy Schubert     return ret;
4929*7f2fe78bSCy Schubert }
4930*7f2fe78bSCy Schubert 
4931*7f2fe78bSCy Schubert krb5_error_code
crypto_cert_get_matching_data(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,pkinit_cert_matching_data *** md_out)4932*7f2fe78bSCy Schubert crypto_cert_get_matching_data(krb5_context context,
4933*7f2fe78bSCy Schubert                               pkinit_plg_crypto_context plg_cryptoctx,
4934*7f2fe78bSCy Schubert                               pkinit_req_crypto_context req_cryptoctx,
4935*7f2fe78bSCy Schubert                               pkinit_identity_crypto_context id_cryptoctx,
4936*7f2fe78bSCy Schubert                               pkinit_cert_matching_data ***md_out)
4937*7f2fe78bSCy Schubert {
4938*7f2fe78bSCy Schubert     krb5_error_code ret;
4939*7f2fe78bSCy Schubert     pkinit_cert_matching_data **md_list = NULL;
4940*7f2fe78bSCy Schubert     int count, i;
4941*7f2fe78bSCy Schubert 
4942*7f2fe78bSCy Schubert     ret = crypto_cert_get_count(id_cryptoctx, &count);
4943*7f2fe78bSCy Schubert     if (ret)
4944*7f2fe78bSCy Schubert         goto cleanup;
4945*7f2fe78bSCy Schubert 
4946*7f2fe78bSCy Schubert     md_list = calloc(count + 1, sizeof(*md_list));
4947*7f2fe78bSCy Schubert     if (md_list == NULL) {
4948*7f2fe78bSCy Schubert         ret = ENOMEM;
4949*7f2fe78bSCy Schubert         goto cleanup;
4950*7f2fe78bSCy Schubert     }
4951*7f2fe78bSCy Schubert 
4952*7f2fe78bSCy Schubert     for (i = 0; i < count; i++) {
4953*7f2fe78bSCy Schubert         ret = get_matching_data(context, plg_cryptoctx, req_cryptoctx,
4954*7f2fe78bSCy Schubert                                 id_cryptoctx->creds[i]->cert, &md_list[i]);
4955*7f2fe78bSCy Schubert         if (ret) {
4956*7f2fe78bSCy Schubert             pkiDebug("%s: crypto_cert_get_matching_data error %d, %s\n",
4957*7f2fe78bSCy Schubert                      __FUNCTION__, ret, error_message(ret));
4958*7f2fe78bSCy Schubert             goto cleanup;
4959*7f2fe78bSCy Schubert         }
4960*7f2fe78bSCy Schubert     }
4961*7f2fe78bSCy Schubert 
4962*7f2fe78bSCy Schubert     *md_out = md_list;
4963*7f2fe78bSCy Schubert     md_list = NULL;
4964*7f2fe78bSCy Schubert 
4965*7f2fe78bSCy Schubert cleanup:
4966*7f2fe78bSCy Schubert     crypto_cert_free_matching_data_list(context, md_list);
4967*7f2fe78bSCy Schubert     return ret;
4968*7f2fe78bSCy Schubert }
4969*7f2fe78bSCy Schubert 
4970*7f2fe78bSCy Schubert /*
4971*7f2fe78bSCy Schubert  * Set the certificate in idctx->creds[cred_index] as the selected certificate.
4972*7f2fe78bSCy Schubert  */
4973*7f2fe78bSCy Schubert krb5_error_code
crypto_cert_select(krb5_context context,pkinit_identity_crypto_context idctx,size_t cred_index)4974*7f2fe78bSCy Schubert crypto_cert_select(krb5_context context, pkinit_identity_crypto_context idctx,
4975*7f2fe78bSCy Schubert                    size_t cred_index)
4976*7f2fe78bSCy Schubert {
4977*7f2fe78bSCy Schubert     pkinit_cred_info ci = NULL;
4978*7f2fe78bSCy Schubert 
4979*7f2fe78bSCy Schubert     if (cred_index >= MAX_CREDS_ALLOWED || idctx->creds[cred_index] == NULL)
4980*7f2fe78bSCy Schubert         return ENOENT;
4981*7f2fe78bSCy Schubert 
4982*7f2fe78bSCy Schubert     ci = idctx->creds[cred_index];
4983*7f2fe78bSCy Schubert     /* copy the selected cert into our id_cryptoctx */
4984*7f2fe78bSCy Schubert     if (idctx->my_certs != NULL)
4985*7f2fe78bSCy Schubert         sk_X509_pop_free(idctx->my_certs, X509_free);
4986*7f2fe78bSCy Schubert     idctx->my_certs = sk_X509_new_null();
4987*7f2fe78bSCy Schubert     sk_X509_push(idctx->my_certs, ci->cert);
4988*7f2fe78bSCy Schubert     free(idctx->identity);
4989*7f2fe78bSCy Schubert     /* hang on to the selected credential name */
4990*7f2fe78bSCy Schubert     if (ci->name != NULL)
4991*7f2fe78bSCy Schubert         idctx->identity = strdup(ci->name);
4992*7f2fe78bSCy Schubert     else
4993*7f2fe78bSCy Schubert         idctx->identity = NULL;
4994*7f2fe78bSCy Schubert 
4995*7f2fe78bSCy Schubert     ci->cert = NULL;       /* Don't free it twice */
4996*7f2fe78bSCy Schubert     idctx->cert_index = 0;
4997*7f2fe78bSCy Schubert     if (idctx->pkcs11_method != 1) {
4998*7f2fe78bSCy Schubert         idctx->my_key = ci->key;
4999*7f2fe78bSCy Schubert         ci->key = NULL;    /* Don't free it twice */
5000*7f2fe78bSCy Schubert     }
5001*7f2fe78bSCy Schubert #ifndef WITHOUT_PKCS11
5002*7f2fe78bSCy Schubert     else {
5003*7f2fe78bSCy Schubert         idctx->cert_id = ci->cert_id;
5004*7f2fe78bSCy Schubert         ci->cert_id = NULL; /* Don't free it twice */
5005*7f2fe78bSCy Schubert         idctx->cert_id_len = ci->cert_id_len;
5006*7f2fe78bSCy Schubert     }
5007*7f2fe78bSCy Schubert #endif
5008*7f2fe78bSCy Schubert     return 0;
5009*7f2fe78bSCy Schubert }
5010*7f2fe78bSCy Schubert 
5011*7f2fe78bSCy Schubert /*
5012*7f2fe78bSCy Schubert  * Choose the default certificate as "the chosen one"
5013*7f2fe78bSCy Schubert  */
5014*7f2fe78bSCy Schubert krb5_error_code
crypto_cert_select_default(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx)5015*7f2fe78bSCy Schubert crypto_cert_select_default(krb5_context context,
5016*7f2fe78bSCy Schubert                            pkinit_plg_crypto_context plg_cryptoctx,
5017*7f2fe78bSCy Schubert                            pkinit_req_crypto_context req_cryptoctx,
5018*7f2fe78bSCy Schubert                            pkinit_identity_crypto_context id_cryptoctx)
5019*7f2fe78bSCy Schubert {
5020*7f2fe78bSCy Schubert     krb5_error_code retval;
5021*7f2fe78bSCy Schubert     int cert_count;
5022*7f2fe78bSCy Schubert 
5023*7f2fe78bSCy Schubert     retval = crypto_cert_get_count(id_cryptoctx, &cert_count);
5024*7f2fe78bSCy Schubert     if (retval)
5025*7f2fe78bSCy Schubert         goto errout;
5026*7f2fe78bSCy Schubert 
5027*7f2fe78bSCy Schubert     if (cert_count != 1) {
5028*7f2fe78bSCy Schubert         TRACE_PKINIT_NO_DEFAULT_CERT(context, cert_count);
5029*7f2fe78bSCy Schubert         retval = EINVAL;
5030*7f2fe78bSCy Schubert         goto errout;
5031*7f2fe78bSCy Schubert     }
5032*7f2fe78bSCy Schubert     /* copy the selected cert into our id_cryptoctx */
5033*7f2fe78bSCy Schubert     if (id_cryptoctx->my_certs != NULL) {
5034*7f2fe78bSCy Schubert         sk_X509_pop_free(id_cryptoctx->my_certs, X509_free);
5035*7f2fe78bSCy Schubert     }
5036*7f2fe78bSCy Schubert     id_cryptoctx->my_certs = sk_X509_new_null();
5037*7f2fe78bSCy Schubert     sk_X509_push(id_cryptoctx->my_certs, id_cryptoctx->creds[0]->cert);
5038*7f2fe78bSCy Schubert     id_cryptoctx->creds[0]->cert = NULL;        /* Don't free it twice */
5039*7f2fe78bSCy Schubert     id_cryptoctx->cert_index = 0;
5040*7f2fe78bSCy Schubert     /* hang on to the selected credential name */
5041*7f2fe78bSCy Schubert     if (id_cryptoctx->creds[0]->name != NULL)
5042*7f2fe78bSCy Schubert         id_cryptoctx->identity = strdup(id_cryptoctx->creds[0]->name);
5043*7f2fe78bSCy Schubert     else
5044*7f2fe78bSCy Schubert         id_cryptoctx->identity = NULL;
5045*7f2fe78bSCy Schubert 
5046*7f2fe78bSCy Schubert     if (id_cryptoctx->pkcs11_method != 1) {
5047*7f2fe78bSCy Schubert         id_cryptoctx->my_key = id_cryptoctx->creds[0]->key;
5048*7f2fe78bSCy Schubert         id_cryptoctx->creds[0]->key = NULL;     /* Don't free it twice */
5049*7f2fe78bSCy Schubert     }
5050*7f2fe78bSCy Schubert #ifndef WITHOUT_PKCS11
5051*7f2fe78bSCy Schubert     else {
5052*7f2fe78bSCy Schubert         id_cryptoctx->cert_id = id_cryptoctx->creds[0]->cert_id;
5053*7f2fe78bSCy Schubert         id_cryptoctx->creds[0]->cert_id = NULL; /* Don't free it twice */
5054*7f2fe78bSCy Schubert         id_cryptoctx->cert_id_len = id_cryptoctx->creds[0]->cert_id_len;
5055*7f2fe78bSCy Schubert     }
5056*7f2fe78bSCy Schubert #endif
5057*7f2fe78bSCy Schubert     retval = 0;
5058*7f2fe78bSCy Schubert errout:
5059*7f2fe78bSCy Schubert     return retval;
5060*7f2fe78bSCy Schubert }
5061*7f2fe78bSCy Schubert 
5062*7f2fe78bSCy Schubert 
5063*7f2fe78bSCy Schubert 
5064*7f2fe78bSCy Schubert static krb5_error_code
load_cas_and_crls(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,int catype,char * filename)5065*7f2fe78bSCy Schubert load_cas_and_crls(krb5_context context,
5066*7f2fe78bSCy Schubert                   pkinit_plg_crypto_context plg_cryptoctx,
5067*7f2fe78bSCy Schubert                   pkinit_req_crypto_context req_cryptoctx,
5068*7f2fe78bSCy Schubert                   pkinit_identity_crypto_context id_cryptoctx,
5069*7f2fe78bSCy Schubert                   int catype,
5070*7f2fe78bSCy Schubert                   char *filename)
5071*7f2fe78bSCy Schubert {
5072*7f2fe78bSCy Schubert     STACK_OF(X509_INFO) *sk = NULL;
5073*7f2fe78bSCy Schubert     STACK_OF(X509) *ca_certs = NULL;
5074*7f2fe78bSCy Schubert     STACK_OF(X509_CRL) *ca_crls = NULL;
5075*7f2fe78bSCy Schubert     BIO *in = NULL;
5076*7f2fe78bSCy Schubert     krb5_error_code retval = ENOMEM;
5077*7f2fe78bSCy Schubert     int i = 0;
5078*7f2fe78bSCy Schubert 
5079*7f2fe78bSCy Schubert     /* If there isn't already a stack in the context,
5080*7f2fe78bSCy Schubert      * create a temporary one now */
5081*7f2fe78bSCy Schubert     switch(catype) {
5082*7f2fe78bSCy Schubert     case CATYPE_ANCHORS:
5083*7f2fe78bSCy Schubert         if (id_cryptoctx->trustedCAs != NULL)
5084*7f2fe78bSCy Schubert             ca_certs = id_cryptoctx->trustedCAs;
5085*7f2fe78bSCy Schubert         else {
5086*7f2fe78bSCy Schubert             ca_certs = sk_X509_new_null();
5087*7f2fe78bSCy Schubert             if (ca_certs == NULL)
5088*7f2fe78bSCy Schubert                 return ENOMEM;
5089*7f2fe78bSCy Schubert         }
5090*7f2fe78bSCy Schubert         break;
5091*7f2fe78bSCy Schubert     case CATYPE_INTERMEDIATES:
5092*7f2fe78bSCy Schubert         if (id_cryptoctx->intermediateCAs != NULL)
5093*7f2fe78bSCy Schubert             ca_certs = id_cryptoctx->intermediateCAs;
5094*7f2fe78bSCy Schubert         else {
5095*7f2fe78bSCy Schubert             ca_certs = sk_X509_new_null();
5096*7f2fe78bSCy Schubert             if (ca_certs == NULL)
5097*7f2fe78bSCy Schubert                 return ENOMEM;
5098*7f2fe78bSCy Schubert         }
5099*7f2fe78bSCy Schubert         break;
5100*7f2fe78bSCy Schubert     case CATYPE_CRLS:
5101*7f2fe78bSCy Schubert         if (id_cryptoctx->revoked != NULL)
5102*7f2fe78bSCy Schubert             ca_crls = id_cryptoctx->revoked;
5103*7f2fe78bSCy Schubert         else {
5104*7f2fe78bSCy Schubert             ca_crls = sk_X509_CRL_new_null();
5105*7f2fe78bSCy Schubert             if (ca_crls == NULL)
5106*7f2fe78bSCy Schubert                 return ENOMEM;
5107*7f2fe78bSCy Schubert         }
5108*7f2fe78bSCy Schubert         break;
5109*7f2fe78bSCy Schubert     default:
5110*7f2fe78bSCy Schubert         return ENOTSUP;
5111*7f2fe78bSCy Schubert     }
5112*7f2fe78bSCy Schubert 
5113*7f2fe78bSCy Schubert     if (!(in = BIO_new_file(filename, "r"))) {
5114*7f2fe78bSCy Schubert         retval = oerr(context, 0, _("Cannot open file '%s'"), filename);
5115*7f2fe78bSCy Schubert         goto cleanup;
5116*7f2fe78bSCy Schubert     }
5117*7f2fe78bSCy Schubert 
5118*7f2fe78bSCy Schubert     /* This loads from a file, a stack of x509/crl/pkey sets */
5119*7f2fe78bSCy Schubert     if ((sk = PEM_X509_INFO_read_bio(in, NULL, NULL, NULL)) == NULL) {
5120*7f2fe78bSCy Schubert         pkiDebug("%s: error reading file '%s'\n", __FUNCTION__, filename);
5121*7f2fe78bSCy Schubert         retval = oerr(context, 0, _("Cannot read file '%s'"), filename);
5122*7f2fe78bSCy Schubert         goto cleanup;
5123*7f2fe78bSCy Schubert     }
5124*7f2fe78bSCy Schubert 
5125*7f2fe78bSCy Schubert     /* scan over the stack created from loading the file contents,
5126*7f2fe78bSCy Schubert      * weed out duplicates, and push new ones onto the return stack
5127*7f2fe78bSCy Schubert      */
5128*7f2fe78bSCy Schubert     for (i = 0; i < sk_X509_INFO_num(sk); i++) {
5129*7f2fe78bSCy Schubert         X509_INFO *xi = sk_X509_INFO_value(sk, i);
5130*7f2fe78bSCy Schubert         if (xi != NULL && xi->x509 != NULL && catype != CATYPE_CRLS) {
5131*7f2fe78bSCy Schubert             int j = 0, size = sk_X509_num(ca_certs), flag = 0;
5132*7f2fe78bSCy Schubert 
5133*7f2fe78bSCy Schubert             if (!size) {
5134*7f2fe78bSCy Schubert                 sk_X509_push(ca_certs, xi->x509);
5135*7f2fe78bSCy Schubert                 xi->x509 = NULL;
5136*7f2fe78bSCy Schubert                 continue;
5137*7f2fe78bSCy Schubert             }
5138*7f2fe78bSCy Schubert             for (j = 0; j < size; j++) {
5139*7f2fe78bSCy Schubert                 X509 *x = sk_X509_value(ca_certs, j);
5140*7f2fe78bSCy Schubert                 flag = X509_cmp(x, xi->x509);
5141*7f2fe78bSCy Schubert                 if (flag == 0)
5142*7f2fe78bSCy Schubert                     break;
5143*7f2fe78bSCy Schubert                 else
5144*7f2fe78bSCy Schubert                     continue;
5145*7f2fe78bSCy Schubert             }
5146*7f2fe78bSCy Schubert             if (flag != 0) {
5147*7f2fe78bSCy Schubert                 sk_X509_push(ca_certs, X509_dup(xi->x509));
5148*7f2fe78bSCy Schubert             }
5149*7f2fe78bSCy Schubert         } else if (xi != NULL && xi->crl != NULL && catype == CATYPE_CRLS) {
5150*7f2fe78bSCy Schubert             int j = 0, size = sk_X509_CRL_num(ca_crls), flag = 0;
5151*7f2fe78bSCy Schubert             if (!size) {
5152*7f2fe78bSCy Schubert                 sk_X509_CRL_push(ca_crls, xi->crl);
5153*7f2fe78bSCy Schubert                 xi->crl = NULL;
5154*7f2fe78bSCy Schubert                 continue;
5155*7f2fe78bSCy Schubert             }
5156*7f2fe78bSCy Schubert             for (j = 0; j < size; j++) {
5157*7f2fe78bSCy Schubert                 X509_CRL *x = sk_X509_CRL_value(ca_crls, j);
5158*7f2fe78bSCy Schubert                 flag = X509_CRL_cmp(x, xi->crl);
5159*7f2fe78bSCy Schubert                 if (flag == 0)
5160*7f2fe78bSCy Schubert                     break;
5161*7f2fe78bSCy Schubert                 else
5162*7f2fe78bSCy Schubert                     continue;
5163*7f2fe78bSCy Schubert             }
5164*7f2fe78bSCy Schubert             if (flag != 0) {
5165*7f2fe78bSCy Schubert                 sk_X509_CRL_push(ca_crls, X509_CRL_dup(xi->crl));
5166*7f2fe78bSCy Schubert             }
5167*7f2fe78bSCy Schubert         }
5168*7f2fe78bSCy Schubert     }
5169*7f2fe78bSCy Schubert 
5170*7f2fe78bSCy Schubert     /* If we added something and there wasn't a stack in the
5171*7f2fe78bSCy Schubert      * context before, add the temporary stack to the context.
5172*7f2fe78bSCy Schubert      */
5173*7f2fe78bSCy Schubert     switch(catype) {
5174*7f2fe78bSCy Schubert     case CATYPE_ANCHORS:
5175*7f2fe78bSCy Schubert         if (sk_X509_num(ca_certs) == 0) {
5176*7f2fe78bSCy Schubert             TRACE_PKINIT_NO_CA_ANCHOR(context, filename);
5177*7f2fe78bSCy Schubert             if (id_cryptoctx->trustedCAs == NULL)
5178*7f2fe78bSCy Schubert                 sk_X509_free(ca_certs);
5179*7f2fe78bSCy Schubert         } else {
5180*7f2fe78bSCy Schubert             if (id_cryptoctx->trustedCAs == NULL)
5181*7f2fe78bSCy Schubert                 id_cryptoctx->trustedCAs = ca_certs;
5182*7f2fe78bSCy Schubert         }
5183*7f2fe78bSCy Schubert         break;
5184*7f2fe78bSCy Schubert     case CATYPE_INTERMEDIATES:
5185*7f2fe78bSCy Schubert         if (sk_X509_num(ca_certs) == 0) {
5186*7f2fe78bSCy Schubert             TRACE_PKINIT_NO_CA_INTERMEDIATE(context, filename);
5187*7f2fe78bSCy Schubert             if (id_cryptoctx->intermediateCAs == NULL)
5188*7f2fe78bSCy Schubert                 sk_X509_free(ca_certs);
5189*7f2fe78bSCy Schubert         } else {
5190*7f2fe78bSCy Schubert             if (id_cryptoctx->intermediateCAs == NULL)
5191*7f2fe78bSCy Schubert                 id_cryptoctx->intermediateCAs = ca_certs;
5192*7f2fe78bSCy Schubert         }
5193*7f2fe78bSCy Schubert         break;
5194*7f2fe78bSCy Schubert     case CATYPE_CRLS:
5195*7f2fe78bSCy Schubert         if (sk_X509_CRL_num(ca_crls) == 0) {
5196*7f2fe78bSCy Schubert             TRACE_PKINIT_NO_CRL(context, filename);
5197*7f2fe78bSCy Schubert             if (id_cryptoctx->revoked == NULL)
5198*7f2fe78bSCy Schubert                 sk_X509_CRL_free(ca_crls);
5199*7f2fe78bSCy Schubert         } else {
5200*7f2fe78bSCy Schubert             if (id_cryptoctx->revoked == NULL)
5201*7f2fe78bSCy Schubert                 id_cryptoctx->revoked = ca_crls;
5202*7f2fe78bSCy Schubert         }
5203*7f2fe78bSCy Schubert         break;
5204*7f2fe78bSCy Schubert     default:
5205*7f2fe78bSCy Schubert         /* Should have been caught above! */
5206*7f2fe78bSCy Schubert         retval = EINVAL;
5207*7f2fe78bSCy Schubert         goto cleanup;
5208*7f2fe78bSCy Schubert         break;
5209*7f2fe78bSCy Schubert     }
5210*7f2fe78bSCy Schubert 
5211*7f2fe78bSCy Schubert     retval = 0;
5212*7f2fe78bSCy Schubert 
5213*7f2fe78bSCy Schubert cleanup:
5214*7f2fe78bSCy Schubert     if (in != NULL)
5215*7f2fe78bSCy Schubert         BIO_free(in);
5216*7f2fe78bSCy Schubert     if (sk != NULL)
5217*7f2fe78bSCy Schubert         sk_X509_INFO_pop_free(sk, X509_INFO_free);
5218*7f2fe78bSCy Schubert 
5219*7f2fe78bSCy Schubert     return retval;
5220*7f2fe78bSCy Schubert }
5221*7f2fe78bSCy Schubert 
5222*7f2fe78bSCy Schubert static krb5_error_code
load_cas_and_crls_dir(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,int catype,char * dirname)5223*7f2fe78bSCy Schubert load_cas_and_crls_dir(krb5_context context,
5224*7f2fe78bSCy Schubert                       pkinit_plg_crypto_context plg_cryptoctx,
5225*7f2fe78bSCy Schubert                       pkinit_req_crypto_context req_cryptoctx,
5226*7f2fe78bSCy Schubert                       pkinit_identity_crypto_context id_cryptoctx,
5227*7f2fe78bSCy Schubert                       int catype,
5228*7f2fe78bSCy Schubert                       char *dirname)
5229*7f2fe78bSCy Schubert {
5230*7f2fe78bSCy Schubert     krb5_error_code retval = EINVAL;
5231*7f2fe78bSCy Schubert     DIR *d = NULL;
5232*7f2fe78bSCy Schubert     struct dirent *dentry = NULL;
5233*7f2fe78bSCy Schubert     char filename[1024];
5234*7f2fe78bSCy Schubert 
5235*7f2fe78bSCy Schubert     if (dirname == NULL)
5236*7f2fe78bSCy Schubert         return EINVAL;
5237*7f2fe78bSCy Schubert 
5238*7f2fe78bSCy Schubert     d = opendir(dirname);
5239*7f2fe78bSCy Schubert     if (d == NULL)
5240*7f2fe78bSCy Schubert         return ENOENT;
5241*7f2fe78bSCy Schubert 
5242*7f2fe78bSCy Schubert     while ((dentry = readdir(d))) {
5243*7f2fe78bSCy Schubert         if (strlen(dirname) + strlen(dentry->d_name) + 2 > sizeof(filename)) {
5244*7f2fe78bSCy Schubert             pkiDebug("%s: Path too long -- directory '%s' and file '%s'\n",
5245*7f2fe78bSCy Schubert                      __FUNCTION__, dirname, dentry->d_name);
5246*7f2fe78bSCy Schubert             goto cleanup;
5247*7f2fe78bSCy Schubert         }
5248*7f2fe78bSCy Schubert         /* Ignore subdirectories and anything starting with a dot */
5249*7f2fe78bSCy Schubert #ifdef DT_DIR
5250*7f2fe78bSCy Schubert         if (dentry->d_type == DT_DIR)
5251*7f2fe78bSCy Schubert             continue;
5252*7f2fe78bSCy Schubert #endif
5253*7f2fe78bSCy Schubert         if (dentry->d_name[0] == '.')
5254*7f2fe78bSCy Schubert             continue;
5255*7f2fe78bSCy Schubert         snprintf(filename, sizeof(filename), "%s/%s", dirname, dentry->d_name);
5256*7f2fe78bSCy Schubert 
5257*7f2fe78bSCy Schubert         retval = load_cas_and_crls(context, plg_cryptoctx, req_cryptoctx,
5258*7f2fe78bSCy Schubert                                    id_cryptoctx, catype, filename);
5259*7f2fe78bSCy Schubert         if (retval)
5260*7f2fe78bSCy Schubert             goto cleanup;
5261*7f2fe78bSCy Schubert     }
5262*7f2fe78bSCy Schubert 
5263*7f2fe78bSCy Schubert     retval = 0;
5264*7f2fe78bSCy Schubert 
5265*7f2fe78bSCy Schubert cleanup:
5266*7f2fe78bSCy Schubert     if (d != NULL)
5267*7f2fe78bSCy Schubert         closedir(d);
5268*7f2fe78bSCy Schubert 
5269*7f2fe78bSCy Schubert     return retval;
5270*7f2fe78bSCy Schubert }
5271*7f2fe78bSCy Schubert 
5272*7f2fe78bSCy Schubert krb5_error_code
crypto_load_cas_and_crls(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_opts * idopts,pkinit_identity_crypto_context id_cryptoctx,int idtype,int catype,char * id)5273*7f2fe78bSCy Schubert crypto_load_cas_and_crls(krb5_context context,
5274*7f2fe78bSCy Schubert                          pkinit_plg_crypto_context plg_cryptoctx,
5275*7f2fe78bSCy Schubert                          pkinit_req_crypto_context req_cryptoctx,
5276*7f2fe78bSCy Schubert                          pkinit_identity_opts *idopts,
5277*7f2fe78bSCy Schubert                          pkinit_identity_crypto_context id_cryptoctx,
5278*7f2fe78bSCy Schubert                          int idtype,
5279*7f2fe78bSCy Schubert                          int catype,
5280*7f2fe78bSCy Schubert                          char *id)
5281*7f2fe78bSCy Schubert {
5282*7f2fe78bSCy Schubert     switch (idtype) {
5283*7f2fe78bSCy Schubert     case IDTYPE_FILE:
5284*7f2fe78bSCy Schubert         TRACE_PKINIT_LOAD_FROM_FILE(context, id);
5285*7f2fe78bSCy Schubert         return load_cas_and_crls(context, plg_cryptoctx, req_cryptoctx,
5286*7f2fe78bSCy Schubert                                  id_cryptoctx, catype, id);
5287*7f2fe78bSCy Schubert         break;
5288*7f2fe78bSCy Schubert     case IDTYPE_DIR:
5289*7f2fe78bSCy Schubert         TRACE_PKINIT_LOAD_FROM_DIR(context, id);
5290*7f2fe78bSCy Schubert         return load_cas_and_crls_dir(context, plg_cryptoctx, req_cryptoctx,
5291*7f2fe78bSCy Schubert                                      id_cryptoctx, catype, id);
5292*7f2fe78bSCy Schubert         break;
5293*7f2fe78bSCy Schubert     default:
5294*7f2fe78bSCy Schubert         return ENOTSUP;
5295*7f2fe78bSCy Schubert         break;
5296*7f2fe78bSCy Schubert     }
5297*7f2fe78bSCy Schubert }
5298*7f2fe78bSCy Schubert 
5299*7f2fe78bSCy Schubert static krb5_error_code
create_identifiers_from_stack(STACK_OF (X509)* sk,krb5_external_principal_identifier *** ids)5300*7f2fe78bSCy Schubert create_identifiers_from_stack(STACK_OF(X509) *sk,
5301*7f2fe78bSCy Schubert                               krb5_external_principal_identifier *** ids)
5302*7f2fe78bSCy Schubert {
5303*7f2fe78bSCy Schubert     int i = 0, sk_size = sk_X509_num(sk);
5304*7f2fe78bSCy Schubert     krb5_external_principal_identifier **krb5_cas = NULL;
5305*7f2fe78bSCy Schubert     X509 *x = NULL;
5306*7f2fe78bSCy Schubert     X509_NAME *xn = NULL;
5307*7f2fe78bSCy Schubert     unsigned char *p = NULL;
5308*7f2fe78bSCy Schubert     int len = 0;
5309*7f2fe78bSCy Schubert     PKCS7_ISSUER_AND_SERIAL *is = NULL;
5310*7f2fe78bSCy Schubert     char buf[DN_BUF_LEN];
5311*7f2fe78bSCy Schubert 
5312*7f2fe78bSCy Schubert     *ids = NULL;
5313*7f2fe78bSCy Schubert 
5314*7f2fe78bSCy Schubert     krb5_cas = calloc(sk_size + 1, sizeof(*krb5_cas));
5315*7f2fe78bSCy Schubert     if (krb5_cas == NULL)
5316*7f2fe78bSCy Schubert         return ENOMEM;
5317*7f2fe78bSCy Schubert 
5318*7f2fe78bSCy Schubert     for (i = 0; i < sk_size; i++) {
5319*7f2fe78bSCy Schubert         krb5_cas[i] = malloc(sizeof(krb5_external_principal_identifier));
5320*7f2fe78bSCy Schubert 
5321*7f2fe78bSCy Schubert         x = sk_X509_value(sk, i);
5322*7f2fe78bSCy Schubert 
5323*7f2fe78bSCy Schubert         X509_NAME_oneline(X509_get_subject_name(x), buf, sizeof(buf));
5324*7f2fe78bSCy Schubert         pkiDebug("#%d cert= %s\n", i, buf);
5325*7f2fe78bSCy Schubert 
5326*7f2fe78bSCy Schubert         /* fill-in subjectName */
5327*7f2fe78bSCy Schubert         krb5_cas[i]->subjectName.magic = 0;
5328*7f2fe78bSCy Schubert         krb5_cas[i]->subjectName.length = 0;
5329*7f2fe78bSCy Schubert         krb5_cas[i]->subjectName.data = NULL;
5330*7f2fe78bSCy Schubert 
5331*7f2fe78bSCy Schubert         xn = X509_get_subject_name(x);
5332*7f2fe78bSCy Schubert         len = i2d_X509_NAME(xn, NULL);
5333*7f2fe78bSCy Schubert         if ((p = malloc((size_t) len)) == NULL)
5334*7f2fe78bSCy Schubert             goto oom;
5335*7f2fe78bSCy Schubert         krb5_cas[i]->subjectName.data = (char *)p;
5336*7f2fe78bSCy Schubert         i2d_X509_NAME(xn, &p);
5337*7f2fe78bSCy Schubert         krb5_cas[i]->subjectName.length = len;
5338*7f2fe78bSCy Schubert 
5339*7f2fe78bSCy Schubert         /* fill-in issuerAndSerialNumber */
5340*7f2fe78bSCy Schubert         krb5_cas[i]->issuerAndSerialNumber.length = 0;
5341*7f2fe78bSCy Schubert         krb5_cas[i]->issuerAndSerialNumber.magic = 0;
5342*7f2fe78bSCy Schubert         krb5_cas[i]->issuerAndSerialNumber.data = NULL;
5343*7f2fe78bSCy Schubert 
5344*7f2fe78bSCy Schubert         is = PKCS7_ISSUER_AND_SERIAL_new();
5345*7f2fe78bSCy Schubert         if (is == NULL)
5346*7f2fe78bSCy Schubert             goto oom;
5347*7f2fe78bSCy Schubert         X509_NAME_set(&is->issuer, X509_get_issuer_name(x));
5348*7f2fe78bSCy Schubert         ASN1_INTEGER_free(is->serial);
5349*7f2fe78bSCy Schubert         is->serial = ASN1_INTEGER_dup(X509_get_serialNumber(x));
5350*7f2fe78bSCy Schubert         if (is->serial == NULL)
5351*7f2fe78bSCy Schubert             goto oom;
5352*7f2fe78bSCy Schubert         len = i2d_PKCS7_ISSUER_AND_SERIAL(is, NULL);
5353*7f2fe78bSCy Schubert         p = malloc(len);
5354*7f2fe78bSCy Schubert         if (p == NULL)
5355*7f2fe78bSCy Schubert             goto oom;
5356*7f2fe78bSCy Schubert         krb5_cas[i]->issuerAndSerialNumber.data = (char *)p;
5357*7f2fe78bSCy Schubert         i2d_PKCS7_ISSUER_AND_SERIAL(is, &p);
5358*7f2fe78bSCy Schubert         krb5_cas[i]->issuerAndSerialNumber.length = len;
5359*7f2fe78bSCy Schubert 
5360*7f2fe78bSCy Schubert         /* fill-in subjectKeyIdentifier */
5361*7f2fe78bSCy Schubert         krb5_cas[i]->subjectKeyIdentifier.length = 0;
5362*7f2fe78bSCy Schubert         krb5_cas[i]->subjectKeyIdentifier.magic = 0;
5363*7f2fe78bSCy Schubert         krb5_cas[i]->subjectKeyIdentifier.data = NULL;
5364*7f2fe78bSCy Schubert 
5365*7f2fe78bSCy Schubert         if (X509_get_ext_by_NID(x, NID_subject_key_identifier, -1) >= 0) {
5366*7f2fe78bSCy Schubert             ASN1_OCTET_STRING *ikeyid;
5367*7f2fe78bSCy Schubert 
5368*7f2fe78bSCy Schubert             ikeyid = X509_get_ext_d2i(x, NID_subject_key_identifier, NULL,
5369*7f2fe78bSCy Schubert                                       NULL);
5370*7f2fe78bSCy Schubert             if (ikeyid != NULL) {
5371*7f2fe78bSCy Schubert                 len = i2d_ASN1_OCTET_STRING(ikeyid, NULL);
5372*7f2fe78bSCy Schubert                 p = malloc(len);
5373*7f2fe78bSCy Schubert                 if (p == NULL)
5374*7f2fe78bSCy Schubert                     goto oom;
5375*7f2fe78bSCy Schubert                 krb5_cas[i]->subjectKeyIdentifier.data = (char *)p;
5376*7f2fe78bSCy Schubert                 i2d_ASN1_OCTET_STRING(ikeyid, &p);
5377*7f2fe78bSCy Schubert                 krb5_cas[i]->subjectKeyIdentifier.length = len;
5378*7f2fe78bSCy Schubert                 ASN1_OCTET_STRING_free(ikeyid);
5379*7f2fe78bSCy Schubert             }
5380*7f2fe78bSCy Schubert         }
5381*7f2fe78bSCy Schubert         PKCS7_ISSUER_AND_SERIAL_free(is);
5382*7f2fe78bSCy Schubert         is = NULL;
5383*7f2fe78bSCy Schubert     }
5384*7f2fe78bSCy Schubert 
5385*7f2fe78bSCy Schubert     *ids = krb5_cas;
5386*7f2fe78bSCy Schubert     return 0;
5387*7f2fe78bSCy Schubert 
5388*7f2fe78bSCy Schubert oom:
5389*7f2fe78bSCy Schubert     free_krb5_external_principal_identifier(&krb5_cas);
5390*7f2fe78bSCy Schubert     PKCS7_ISSUER_AND_SERIAL_free(is);
5391*7f2fe78bSCy Schubert     return ENOMEM;
5392*7f2fe78bSCy Schubert }
5393*7f2fe78bSCy Schubert 
5394*7f2fe78bSCy Schubert static krb5_error_code
create_krb5_invalidCertificates(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,krb5_external_principal_identifier *** ids)5395*7f2fe78bSCy Schubert create_krb5_invalidCertificates(krb5_context context,
5396*7f2fe78bSCy Schubert                                 pkinit_plg_crypto_context plg_cryptoctx,
5397*7f2fe78bSCy Schubert                                 pkinit_req_crypto_context req_cryptoctx,
5398*7f2fe78bSCy Schubert                                 pkinit_identity_crypto_context id_cryptoctx,
5399*7f2fe78bSCy Schubert                                 krb5_external_principal_identifier *** ids)
5400*7f2fe78bSCy Schubert {
5401*7f2fe78bSCy Schubert 
5402*7f2fe78bSCy Schubert     krb5_error_code retval = ENOMEM;
5403*7f2fe78bSCy Schubert     STACK_OF(X509) *sk = NULL;
5404*7f2fe78bSCy Schubert 
5405*7f2fe78bSCy Schubert     *ids = NULL;
5406*7f2fe78bSCy Schubert     if (req_cryptoctx->received_cert == NULL)
5407*7f2fe78bSCy Schubert         return KRB5KDC_ERR_PREAUTH_FAILED;
5408*7f2fe78bSCy Schubert 
5409*7f2fe78bSCy Schubert     sk = sk_X509_new_null();
5410*7f2fe78bSCy Schubert     if (sk == NULL)
5411*7f2fe78bSCy Schubert         goto cleanup;
5412*7f2fe78bSCy Schubert     sk_X509_push(sk, req_cryptoctx->received_cert);
5413*7f2fe78bSCy Schubert 
5414*7f2fe78bSCy Schubert     retval = create_identifiers_from_stack(sk, ids);
5415*7f2fe78bSCy Schubert 
5416*7f2fe78bSCy Schubert     sk_X509_free(sk);
5417*7f2fe78bSCy Schubert cleanup:
5418*7f2fe78bSCy Schubert 
5419*7f2fe78bSCy Schubert     return retval;
5420*7f2fe78bSCy Schubert }
5421*7f2fe78bSCy Schubert 
5422*7f2fe78bSCy Schubert krb5_error_code
create_krb5_supportedCMSTypes(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,krb5_algorithm_identifier *** algs_out)5423*7f2fe78bSCy Schubert create_krb5_supportedCMSTypes(krb5_context context,
5424*7f2fe78bSCy Schubert                               pkinit_plg_crypto_context plg_cryptoctx,
5425*7f2fe78bSCy Schubert                               pkinit_req_crypto_context req_cryptoctx,
5426*7f2fe78bSCy Schubert                               pkinit_identity_crypto_context id_cryptoctx,
5427*7f2fe78bSCy Schubert                               krb5_algorithm_identifier ***algs_out)
5428*7f2fe78bSCy Schubert {
5429*7f2fe78bSCy Schubert     krb5_error_code ret;
5430*7f2fe78bSCy Schubert     krb5_algorithm_identifier **algs = NULL;
5431*7f2fe78bSCy Schubert     size_t i, count;
5432*7f2fe78bSCy Schubert 
5433*7f2fe78bSCy Schubert     *algs_out = NULL;
5434*7f2fe78bSCy Schubert 
5435*7f2fe78bSCy Schubert     /* Count supported OIDs and allocate list (including null terminator). */
5436*7f2fe78bSCy Schubert     for (count = 0; supported_cms_algs[count] != NULL; count++);
5437*7f2fe78bSCy Schubert     algs = k5calloc(count + 1, sizeof(*algs), &ret);
5438*7f2fe78bSCy Schubert     if (algs == NULL)
5439*7f2fe78bSCy Schubert         goto cleanup;
5440*7f2fe78bSCy Schubert 
5441*7f2fe78bSCy Schubert     /* Add an algorithm identifier for each OID, with no parameters. */
5442*7f2fe78bSCy Schubert     for (i = 0; i < count; i++) {
5443*7f2fe78bSCy Schubert         algs[i] = k5alloc(sizeof(*algs[i]), &ret);
5444*7f2fe78bSCy Schubert         if (algs[i] == NULL)
5445*7f2fe78bSCy Schubert             goto cleanup;
5446*7f2fe78bSCy Schubert         ret = krb5int_copy_data_contents(context, supported_cms_algs[i],
5447*7f2fe78bSCy Schubert                                          &algs[i]->algorithm);
5448*7f2fe78bSCy Schubert         if (ret)
5449*7f2fe78bSCy Schubert             goto cleanup;
5450*7f2fe78bSCy Schubert         algs[i]->parameters = empty_data();
5451*7f2fe78bSCy Schubert     }
5452*7f2fe78bSCy Schubert 
5453*7f2fe78bSCy Schubert     *algs_out = algs;
5454*7f2fe78bSCy Schubert     algs = NULL;
5455*7f2fe78bSCy Schubert 
5456*7f2fe78bSCy Schubert cleanup:
5457*7f2fe78bSCy Schubert     free_krb5_algorithm_identifiers(&algs);
5458*7f2fe78bSCy Schubert     return ret;
5459*7f2fe78bSCy Schubert }
5460*7f2fe78bSCy Schubert 
5461*7f2fe78bSCy Schubert krb5_error_code
create_krb5_trustedCertifiers(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,krb5_external_principal_identifier *** ids)5462*7f2fe78bSCy Schubert create_krb5_trustedCertifiers(krb5_context context,
5463*7f2fe78bSCy Schubert                               pkinit_plg_crypto_context plg_cryptoctx,
5464*7f2fe78bSCy Schubert                               pkinit_req_crypto_context req_cryptoctx,
5465*7f2fe78bSCy Schubert                               pkinit_identity_crypto_context id_cryptoctx,
5466*7f2fe78bSCy Schubert                               krb5_external_principal_identifier *** ids)
5467*7f2fe78bSCy Schubert {
5468*7f2fe78bSCy Schubert 
5469*7f2fe78bSCy Schubert     krb5_error_code retval = ENOMEM;
5470*7f2fe78bSCy Schubert     STACK_OF(X509) *sk = id_cryptoctx->trustedCAs;
5471*7f2fe78bSCy Schubert 
5472*7f2fe78bSCy Schubert     *ids = NULL;
5473*7f2fe78bSCy Schubert     if (id_cryptoctx->trustedCAs == NULL)
5474*7f2fe78bSCy Schubert         return KRB5KDC_ERR_PREAUTH_FAILED;
5475*7f2fe78bSCy Schubert 
5476*7f2fe78bSCy Schubert     retval = create_identifiers_from_stack(sk, ids);
5477*7f2fe78bSCy Schubert 
5478*7f2fe78bSCy Schubert     return retval;
5479*7f2fe78bSCy Schubert }
5480*7f2fe78bSCy Schubert 
5481*7f2fe78bSCy Schubert krb5_error_code
create_issuerAndSerial(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,unsigned char ** out,unsigned int * out_len)5482*7f2fe78bSCy Schubert create_issuerAndSerial(krb5_context context,
5483*7f2fe78bSCy Schubert                        pkinit_plg_crypto_context plg_cryptoctx,
5484*7f2fe78bSCy Schubert                        pkinit_req_crypto_context req_cryptoctx,
5485*7f2fe78bSCy Schubert                        pkinit_identity_crypto_context id_cryptoctx,
5486*7f2fe78bSCy Schubert                        unsigned char **out,
5487*7f2fe78bSCy Schubert                        unsigned int *out_len)
5488*7f2fe78bSCy Schubert {
5489*7f2fe78bSCy Schubert     unsigned char *p = NULL;
5490*7f2fe78bSCy Schubert     PKCS7_ISSUER_AND_SERIAL *is = NULL;
5491*7f2fe78bSCy Schubert     int len = 0;
5492*7f2fe78bSCy Schubert     krb5_error_code retval = ENOMEM;
5493*7f2fe78bSCy Schubert     X509 *cert = req_cryptoctx->received_cert;
5494*7f2fe78bSCy Schubert 
5495*7f2fe78bSCy Schubert     *out = NULL;
5496*7f2fe78bSCy Schubert     *out_len = 0;
5497*7f2fe78bSCy Schubert     if (req_cryptoctx->received_cert == NULL)
5498*7f2fe78bSCy Schubert         return 0;
5499*7f2fe78bSCy Schubert 
5500*7f2fe78bSCy Schubert     is = PKCS7_ISSUER_AND_SERIAL_new();
5501*7f2fe78bSCy Schubert     X509_NAME_set(&is->issuer, X509_get_issuer_name(cert));
5502*7f2fe78bSCy Schubert     ASN1_INTEGER_free(is->serial);
5503*7f2fe78bSCy Schubert     is->serial = ASN1_INTEGER_dup(X509_get_serialNumber(cert));
5504*7f2fe78bSCy Schubert     len = i2d_PKCS7_ISSUER_AND_SERIAL(is, NULL);
5505*7f2fe78bSCy Schubert     if ((p = *out = malloc((size_t) len)) == NULL)
5506*7f2fe78bSCy Schubert         goto cleanup;
5507*7f2fe78bSCy Schubert     i2d_PKCS7_ISSUER_AND_SERIAL(is, &p);
5508*7f2fe78bSCy Schubert     *out_len = len;
5509*7f2fe78bSCy Schubert     retval = 0;
5510*7f2fe78bSCy Schubert 
5511*7f2fe78bSCy Schubert cleanup:
5512*7f2fe78bSCy Schubert     X509_NAME_free(is->issuer);
5513*7f2fe78bSCy Schubert     ASN1_INTEGER_free(is->serial);
5514*7f2fe78bSCy Schubert     free(is);
5515*7f2fe78bSCy Schubert 
5516*7f2fe78bSCy Schubert     return retval;
5517*7f2fe78bSCy Schubert }
5518*7f2fe78bSCy Schubert 
5519*7f2fe78bSCy Schubert krb5_error_code
pkinit_process_td_trusted_certifiers(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,krb5_external_principal_identifier ** krb5_trusted_certifiers,int td_type)5520*7f2fe78bSCy Schubert pkinit_process_td_trusted_certifiers(
5521*7f2fe78bSCy Schubert     krb5_context context,
5522*7f2fe78bSCy Schubert     pkinit_plg_crypto_context plg_cryptoctx,
5523*7f2fe78bSCy Schubert     pkinit_req_crypto_context req_cryptoctx,
5524*7f2fe78bSCy Schubert     pkinit_identity_crypto_context id_cryptoctx,
5525*7f2fe78bSCy Schubert     krb5_external_principal_identifier **krb5_trusted_certifiers,
5526*7f2fe78bSCy Schubert     int td_type)
5527*7f2fe78bSCy Schubert {
5528*7f2fe78bSCy Schubert     krb5_error_code retval = ENOMEM;
5529*7f2fe78bSCy Schubert     STACK_OF(X509_NAME) *sk_xn = NULL;
5530*7f2fe78bSCy Schubert     X509_NAME *xn = NULL;
5531*7f2fe78bSCy Schubert     PKCS7_ISSUER_AND_SERIAL *is = NULL;
5532*7f2fe78bSCy Schubert     ASN1_OCTET_STRING *id = NULL;
5533*7f2fe78bSCy Schubert     const unsigned char *p = NULL;
5534*7f2fe78bSCy Schubert     char buf[DN_BUF_LEN];
5535*7f2fe78bSCy Schubert     int i = 0;
5536*7f2fe78bSCy Schubert 
5537*7f2fe78bSCy Schubert     if (td_type == TD_TRUSTED_CERTIFIERS)
5538*7f2fe78bSCy Schubert         pkiDebug("received trusted certifiers\n");
5539*7f2fe78bSCy Schubert     else
5540*7f2fe78bSCy Schubert         pkiDebug("received invalid certificate\n");
5541*7f2fe78bSCy Schubert 
5542*7f2fe78bSCy Schubert     sk_xn = sk_X509_NAME_new_null();
5543*7f2fe78bSCy Schubert     while(krb5_trusted_certifiers[i] != NULL) {
5544*7f2fe78bSCy Schubert         if (krb5_trusted_certifiers[i]->subjectName.data != NULL) {
5545*7f2fe78bSCy Schubert             p = (unsigned char *)krb5_trusted_certifiers[i]->subjectName.data;
5546*7f2fe78bSCy Schubert             xn = d2i_X509_NAME(NULL, &p,
5547*7f2fe78bSCy Schubert                                (int)krb5_trusted_certifiers[i]->subjectName.length);
5548*7f2fe78bSCy Schubert             if (xn == NULL)
5549*7f2fe78bSCy Schubert                 goto cleanup;
5550*7f2fe78bSCy Schubert             X509_NAME_oneline(xn, buf, sizeof(buf));
5551*7f2fe78bSCy Schubert             if (td_type == TD_TRUSTED_CERTIFIERS)
5552*7f2fe78bSCy Schubert                 pkiDebug("#%d cert = %s is trusted by kdc\n", i, buf);
5553*7f2fe78bSCy Schubert             else
5554*7f2fe78bSCy Schubert                 pkiDebug("#%d cert = %s is invalid\n", i, buf);
5555*7f2fe78bSCy Schubert             sk_X509_NAME_push(sk_xn, xn);
5556*7f2fe78bSCy Schubert         }
5557*7f2fe78bSCy Schubert 
5558*7f2fe78bSCy Schubert         if (krb5_trusted_certifiers[i]->issuerAndSerialNumber.data != NULL) {
5559*7f2fe78bSCy Schubert             p = (unsigned char *)
5560*7f2fe78bSCy Schubert                 krb5_trusted_certifiers[i]->issuerAndSerialNumber.data;
5561*7f2fe78bSCy Schubert             is = d2i_PKCS7_ISSUER_AND_SERIAL(NULL, &p,
5562*7f2fe78bSCy Schubert                                              (int)krb5_trusted_certifiers[i]->issuerAndSerialNumber.length);
5563*7f2fe78bSCy Schubert             if (is == NULL)
5564*7f2fe78bSCy Schubert                 goto cleanup;
5565*7f2fe78bSCy Schubert             X509_NAME_oneline(is->issuer, buf, sizeof(buf));
5566*7f2fe78bSCy Schubert             if (td_type == TD_TRUSTED_CERTIFIERS)
5567*7f2fe78bSCy Schubert                 pkiDebug("#%d issuer = %s serial = %ld is trusted bu kdc\n", i,
5568*7f2fe78bSCy Schubert                          buf, ASN1_INTEGER_get(is->serial));
5569*7f2fe78bSCy Schubert             else
5570*7f2fe78bSCy Schubert                 pkiDebug("#%d issuer = %s serial = %ld is invalid\n", i, buf,
5571*7f2fe78bSCy Schubert                          ASN1_INTEGER_get(is->serial));
5572*7f2fe78bSCy Schubert             PKCS7_ISSUER_AND_SERIAL_free(is);
5573*7f2fe78bSCy Schubert         }
5574*7f2fe78bSCy Schubert 
5575*7f2fe78bSCy Schubert         if (krb5_trusted_certifiers[i]->subjectKeyIdentifier.data != NULL) {
5576*7f2fe78bSCy Schubert             p = (unsigned char *)
5577*7f2fe78bSCy Schubert                 krb5_trusted_certifiers[i]->subjectKeyIdentifier.data;
5578*7f2fe78bSCy Schubert             id = d2i_ASN1_OCTET_STRING(NULL, &p,
5579*7f2fe78bSCy Schubert                                        (int)krb5_trusted_certifiers[i]->subjectKeyIdentifier.length);
5580*7f2fe78bSCy Schubert             if (id == NULL)
5581*7f2fe78bSCy Schubert                 goto cleanup;
5582*7f2fe78bSCy Schubert             /* XXX */
5583*7f2fe78bSCy Schubert             ASN1_OCTET_STRING_free(id);
5584*7f2fe78bSCy Schubert         }
5585*7f2fe78bSCy Schubert         i++;
5586*7f2fe78bSCy Schubert     }
5587*7f2fe78bSCy Schubert     /* XXX Since we not doing anything with received trusted certifiers
5588*7f2fe78bSCy Schubert      * return an error. this is the place where we can pick a different
5589*7f2fe78bSCy Schubert      * client certificate based on the information in td_trusted_certifiers
5590*7f2fe78bSCy Schubert      */
5591*7f2fe78bSCy Schubert     retval = KRB5KDC_ERR_PREAUTH_FAILED;
5592*7f2fe78bSCy Schubert cleanup:
5593*7f2fe78bSCy Schubert     if (sk_xn != NULL)
5594*7f2fe78bSCy Schubert         sk_X509_NAME_pop_free(sk_xn, X509_NAME_free);
5595*7f2fe78bSCy Schubert 
5596*7f2fe78bSCy Schubert     return retval;
5597*7f2fe78bSCy Schubert }
5598*7f2fe78bSCy Schubert 
5599*7f2fe78bSCy Schubert /* Originally based on OpenSSL's PKCS7_dataDecode(), now modified to remove the
5600*7f2fe78bSCy Schubert  * use of BIO objects and to fit the PKINIT internal interfaces. */
5601*7f2fe78bSCy Schubert static int
pkcs7_decrypt(krb5_context context,pkinit_identity_crypto_context id_cryptoctx,PKCS7 * p7,unsigned char ** data_out,unsigned int * len_out)5602*7f2fe78bSCy Schubert pkcs7_decrypt(krb5_context context,
5603*7f2fe78bSCy Schubert               pkinit_identity_crypto_context id_cryptoctx, PKCS7 *p7,
5604*7f2fe78bSCy Schubert               unsigned char **data_out, unsigned int *len_out)
5605*7f2fe78bSCy Schubert {
5606*7f2fe78bSCy Schubert     krb5_error_code ret;
5607*7f2fe78bSCy Schubert     int ok = 0, plaintext_len = 0, final_len;
5608*7f2fe78bSCy Schubert     unsigned int keylen = 0, eklen = 0, blocksize;
5609*7f2fe78bSCy Schubert     unsigned char *ek = NULL, *tkey = NULL, *plaintext = NULL, *use_key;
5610*7f2fe78bSCy Schubert     ASN1_OCTET_STRING *data_body = p7->d.enveloped->enc_data->enc_data;
5611*7f2fe78bSCy Schubert     const EVP_CIPHER *evp_cipher;
5612*7f2fe78bSCy Schubert     EVP_CIPHER_CTX *evp_ctx = NULL;
5613*7f2fe78bSCy Schubert     X509_ALGOR *enc_alg = p7->d.enveloped->enc_data->algorithm;
5614*7f2fe78bSCy Schubert     STACK_OF(PKCS7_RECIP_INFO) *rsk = p7->d.enveloped->recipientinfo;
5615*7f2fe78bSCy Schubert     PKCS7_RECIP_INFO *ri = NULL;
5616*7f2fe78bSCy Schubert 
5617*7f2fe78bSCy Schubert     *data_out = NULL;
5618*7f2fe78bSCy Schubert     *len_out = 0;
5619*7f2fe78bSCy Schubert 
5620*7f2fe78bSCy Schubert     p7->state = PKCS7_S_HEADER;
5621*7f2fe78bSCy Schubert 
5622*7f2fe78bSCy Schubert     /* RFC 4556 section 3.2.3.2 requires that there be exactly one
5623*7f2fe78bSCy Schubert      * recipientInfo. */
5624*7f2fe78bSCy Schubert     if (sk_PKCS7_RECIP_INFO_num(rsk) != 1) {
5625*7f2fe78bSCy Schubert         pkiDebug("invalid number of EnvelopedData RecipientInfos\n");
5626*7f2fe78bSCy Schubert         return 0;
5627*7f2fe78bSCy Schubert     }
5628*7f2fe78bSCy Schubert     ri = sk_PKCS7_RECIP_INFO_value(rsk, 0);
5629*7f2fe78bSCy Schubert 
5630*7f2fe78bSCy Schubert     evp_cipher = EVP_get_cipherbyobj(enc_alg->algorithm);
5631*7f2fe78bSCy Schubert     if (evp_cipher == NULL)
5632*7f2fe78bSCy Schubert         goto cleanup;
5633*7f2fe78bSCy Schubert     keylen = EVP_CIPHER_key_length(evp_cipher);
5634*7f2fe78bSCy Schubert     blocksize = EVP_CIPHER_block_size(evp_cipher);
5635*7f2fe78bSCy Schubert 
5636*7f2fe78bSCy Schubert     evp_ctx = EVP_CIPHER_CTX_new();
5637*7f2fe78bSCy Schubert     if (evp_ctx == NULL)
5638*7f2fe78bSCy Schubert         goto cleanup;
5639*7f2fe78bSCy Schubert     if (!EVP_DecryptInit(evp_ctx, evp_cipher, NULL, NULL) ||
5640*7f2fe78bSCy Schubert         EVP_CIPHER_asn1_to_param(evp_ctx, enc_alg->parameter) <= 0)
5641*7f2fe78bSCy Schubert         goto cleanup;
5642*7f2fe78bSCy Schubert 
5643*7f2fe78bSCy Schubert     /* Generate a random symmetric key to avoid exposing timing data if RSA
5644*7f2fe78bSCy Schubert      * decryption fails the padding check. */
5645*7f2fe78bSCy Schubert     tkey = malloc(keylen);
5646*7f2fe78bSCy Schubert     if (tkey == NULL || !EVP_CIPHER_CTX_rand_key(evp_ctx, tkey))
5647*7f2fe78bSCy Schubert         goto cleanup;
5648*7f2fe78bSCy Schubert 
5649*7f2fe78bSCy Schubert     /* Decrypt the secret key with the private key. */
5650*7f2fe78bSCy Schubert     ret = pkinit_decode_data(context, id_cryptoctx,
5651*7f2fe78bSCy Schubert                              ASN1_STRING_get0_data(ri->enc_key),
5652*7f2fe78bSCy Schubert                              ASN1_STRING_length(ri->enc_key), &ek, &eklen);
5653*7f2fe78bSCy Schubert     use_key = (ret || eklen != keylen) ? tkey : ek;
5654*7f2fe78bSCy Schubert 
5655*7f2fe78bSCy Schubert     /* Allocate a plaintext buffer and decrypt data_body into it. */
5656*7f2fe78bSCy Schubert     plaintext = malloc(data_body->length + blocksize);
5657*7f2fe78bSCy Schubert     if (plaintext == NULL)
5658*7f2fe78bSCy Schubert         goto cleanup;
5659*7f2fe78bSCy Schubert     if (!EVP_DecryptInit(evp_ctx, NULL, use_key, NULL))
5660*7f2fe78bSCy Schubert         goto cleanup;
5661*7f2fe78bSCy Schubert     if (!EVP_DecryptUpdate(evp_ctx, plaintext, &plaintext_len,
5662*7f2fe78bSCy Schubert                            data_body->data, data_body->length))
5663*7f2fe78bSCy Schubert         goto cleanup;
5664*7f2fe78bSCy Schubert     if (!EVP_DecryptFinal(evp_ctx, plaintext + plaintext_len, &final_len))
5665*7f2fe78bSCy Schubert         goto cleanup;
5666*7f2fe78bSCy Schubert     plaintext_len += final_len;
5667*7f2fe78bSCy Schubert 
5668*7f2fe78bSCy Schubert     *len_out = plaintext_len;
5669*7f2fe78bSCy Schubert     *data_out = plaintext;
5670*7f2fe78bSCy Schubert     plaintext = NULL;
5671*7f2fe78bSCy Schubert     ok = 1;
5672*7f2fe78bSCy Schubert 
5673*7f2fe78bSCy Schubert cleanup:
5674*7f2fe78bSCy Schubert     EVP_CIPHER_CTX_free(evp_ctx);
5675*7f2fe78bSCy Schubert     zapfree(plaintext, plaintext_len);
5676*7f2fe78bSCy Schubert     zapfree(ek, eklen);
5677*7f2fe78bSCy Schubert     zapfree(tkey, keylen);
5678*7f2fe78bSCy Schubert     return ok;
5679*7f2fe78bSCy Schubert }
5680*7f2fe78bSCy Schubert 
5681*7f2fe78bSCy Schubert #ifdef DEBUG_DH
5682*7f2fe78bSCy Schubert static void
print_dh(DH * dh,char * msg)5683*7f2fe78bSCy Schubert print_dh(DH * dh, char *msg)
5684*7f2fe78bSCy Schubert {
5685*7f2fe78bSCy Schubert     BIO *bio_err = NULL;
5686*7f2fe78bSCy Schubert 
5687*7f2fe78bSCy Schubert     bio_err = BIO_new(BIO_s_file());
5688*7f2fe78bSCy Schubert     BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
5689*7f2fe78bSCy Schubert 
5690*7f2fe78bSCy Schubert     if (msg)
5691*7f2fe78bSCy Schubert         BIO_puts(bio_err, (const char *)msg);
5692*7f2fe78bSCy Schubert     if (dh)
5693*7f2fe78bSCy Schubert         DHparams_print(bio_err, dh);
5694*7f2fe78bSCy Schubert 
5695*7f2fe78bSCy Schubert     BIO_puts(bio_err, "private key: ");
5696*7f2fe78bSCy Schubert     BN_print(bio_err, dh->priv_key);
5697*7f2fe78bSCy Schubert     BIO_puts(bio_err, (const char *)"\n");
5698*7f2fe78bSCy Schubert     BIO_free(bio_err);
5699*7f2fe78bSCy Schubert 
5700*7f2fe78bSCy Schubert }
5701*7f2fe78bSCy Schubert 
5702*7f2fe78bSCy Schubert static void
print_pubkey(BIGNUM * key,char * msg)5703*7f2fe78bSCy Schubert print_pubkey(BIGNUM * key, char *msg)
5704*7f2fe78bSCy Schubert {
5705*7f2fe78bSCy Schubert     BIO *bio_err = NULL;
5706*7f2fe78bSCy Schubert 
5707*7f2fe78bSCy Schubert     bio_err = BIO_new(BIO_s_file());
5708*7f2fe78bSCy Schubert     BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
5709*7f2fe78bSCy Schubert 
5710*7f2fe78bSCy Schubert     if (msg)
5711*7f2fe78bSCy Schubert         BIO_puts(bio_err, (const char *)msg);
5712*7f2fe78bSCy Schubert     if (key)
5713*7f2fe78bSCy Schubert         BN_print(bio_err, key);
5714*7f2fe78bSCy Schubert     BIO_puts(bio_err, "\n");
5715*7f2fe78bSCy Schubert 
5716*7f2fe78bSCy Schubert     BIO_free(bio_err);
5717*7f2fe78bSCy Schubert 
5718*7f2fe78bSCy Schubert }
5719*7f2fe78bSCy Schubert #endif
5720*7f2fe78bSCy Schubert 
5721*7f2fe78bSCy Schubert static const char *
pkcs11err(int err)5722*7f2fe78bSCy Schubert pkcs11err(int err)
5723*7f2fe78bSCy Schubert {
5724*7f2fe78bSCy Schubert     int i;
5725*7f2fe78bSCy Schubert 
5726*7f2fe78bSCy Schubert     for (i = 0; pkcs11_errstrings[i].text != NULL; i++)
5727*7f2fe78bSCy Schubert         if (pkcs11_errstrings[i].code == err)
5728*7f2fe78bSCy Schubert             break;
5729*7f2fe78bSCy Schubert     if (pkcs11_errstrings[i].text != NULL)
5730*7f2fe78bSCy Schubert         return (pkcs11_errstrings[i].text);
5731*7f2fe78bSCy Schubert 
5732*7f2fe78bSCy Schubert     return "unknown PKCS11 error";
5733*7f2fe78bSCy Schubert }
5734*7f2fe78bSCy Schubert 
5735*7f2fe78bSCy Schubert /*
5736*7f2fe78bSCy Schubert  * Add an item to the pkinit_identity_crypto_context's list of deferred
5737*7f2fe78bSCy Schubert  * identities.
5738*7f2fe78bSCy Schubert  */
5739*7f2fe78bSCy Schubert krb5_error_code
crypto_set_deferred_id(krb5_context context,pkinit_identity_crypto_context id_cryptoctx,const char * identity,const char * password)5740*7f2fe78bSCy Schubert crypto_set_deferred_id(krb5_context context,
5741*7f2fe78bSCy Schubert                        pkinit_identity_crypto_context id_cryptoctx,
5742*7f2fe78bSCy Schubert                        const char *identity, const char *password)
5743*7f2fe78bSCy Schubert {
5744*7f2fe78bSCy Schubert     unsigned long ck_flags;
5745*7f2fe78bSCy Schubert 
5746*7f2fe78bSCy Schubert     ck_flags = pkinit_get_deferred_id_flags(id_cryptoctx->deferred_ids,
5747*7f2fe78bSCy Schubert                                             identity);
5748*7f2fe78bSCy Schubert     return pkinit_set_deferred_id(&id_cryptoctx->deferred_ids,
5749*7f2fe78bSCy Schubert                                   identity, ck_flags, password);
5750*7f2fe78bSCy Schubert }
5751*7f2fe78bSCy Schubert 
5752*7f2fe78bSCy Schubert /*
5753*7f2fe78bSCy Schubert  * Retrieve a read-only copy of the pkinit_identity_crypto_context's list of
5754*7f2fe78bSCy Schubert  * deferred identities, sure to be valid only until the next time someone calls
5755*7f2fe78bSCy Schubert  * either pkinit_set_deferred_id() or crypto_set_deferred_id().
5756*7f2fe78bSCy Schubert  */
5757*7f2fe78bSCy Schubert const pkinit_deferred_id *
crypto_get_deferred_ids(krb5_context context,pkinit_identity_crypto_context id_cryptoctx)5758*7f2fe78bSCy Schubert crypto_get_deferred_ids(krb5_context context,
5759*7f2fe78bSCy Schubert                         pkinit_identity_crypto_context id_cryptoctx)
5760*7f2fe78bSCy Schubert {
5761*7f2fe78bSCy Schubert     pkinit_deferred_id *deferred;
5762*7f2fe78bSCy Schubert     const pkinit_deferred_id *ret;
5763*7f2fe78bSCy Schubert 
5764*7f2fe78bSCy Schubert     deferred = id_cryptoctx->deferred_ids;
5765*7f2fe78bSCy Schubert     ret = (const pkinit_deferred_id *)deferred;
5766*7f2fe78bSCy Schubert     return ret;
5767*7f2fe78bSCy Schubert }
5768*7f2fe78bSCy Schubert 
5769*7f2fe78bSCy Schubert /* Return the received certificate as DER-encoded data. */
5770*7f2fe78bSCy Schubert krb5_error_code
crypto_encode_der_cert(krb5_context context,pkinit_req_crypto_context reqctx,uint8_t ** der_out,size_t * der_len)5771*7f2fe78bSCy Schubert crypto_encode_der_cert(krb5_context context, pkinit_req_crypto_context reqctx,
5772*7f2fe78bSCy Schubert                        uint8_t **der_out, size_t *der_len)
5773*7f2fe78bSCy Schubert {
5774*7f2fe78bSCy Schubert     int len;
5775*7f2fe78bSCy Schubert     unsigned char *der, *p;
5776*7f2fe78bSCy Schubert 
5777*7f2fe78bSCy Schubert     *der_out = NULL;
5778*7f2fe78bSCy Schubert     *der_len = 0;
5779*7f2fe78bSCy Schubert 
5780*7f2fe78bSCy Schubert     if (reqctx->received_cert == NULL)
5781*7f2fe78bSCy Schubert         return EINVAL;
5782*7f2fe78bSCy Schubert     p = NULL;
5783*7f2fe78bSCy Schubert     len = i2d_X509(reqctx->received_cert, NULL);
5784*7f2fe78bSCy Schubert     if (len <= 0)
5785*7f2fe78bSCy Schubert         return EINVAL;
5786*7f2fe78bSCy Schubert     p = der = malloc(len);
5787*7f2fe78bSCy Schubert     if (der == NULL)
5788*7f2fe78bSCy Schubert         return ENOMEM;
5789*7f2fe78bSCy Schubert     if (i2d_X509(reqctx->received_cert, &p) <= 0) {
5790*7f2fe78bSCy Schubert         free(der);
5791*7f2fe78bSCy Schubert         return EINVAL;
5792*7f2fe78bSCy Schubert     }
5793*7f2fe78bSCy Schubert     *der_out = der;
5794*7f2fe78bSCy Schubert     *der_len = len;
5795*7f2fe78bSCy Schubert     return 0;
5796*7f2fe78bSCy Schubert }
5797*7f2fe78bSCy Schubert 
5798*7f2fe78bSCy Schubert /*
5799*7f2fe78bSCy Schubert  * Get the certificate matching data from the request certificate.
5800*7f2fe78bSCy Schubert  */
5801*7f2fe78bSCy Schubert krb5_error_code
crypto_req_cert_matching_data(krb5_context context,pkinit_plg_crypto_context plgctx,pkinit_req_crypto_context reqctx,pkinit_cert_matching_data ** md_out)5802*7f2fe78bSCy Schubert crypto_req_cert_matching_data(krb5_context context,
5803*7f2fe78bSCy Schubert                               pkinit_plg_crypto_context plgctx,
5804*7f2fe78bSCy Schubert                               pkinit_req_crypto_context reqctx,
5805*7f2fe78bSCy Schubert                               pkinit_cert_matching_data **md_out)
5806*7f2fe78bSCy Schubert {
5807*7f2fe78bSCy Schubert     *md_out = NULL;
5808*7f2fe78bSCy Schubert 
5809*7f2fe78bSCy Schubert     if (reqctx == NULL || reqctx->received_cert == NULL)
5810*7f2fe78bSCy Schubert         return ENOENT;
5811*7f2fe78bSCy Schubert 
5812*7f2fe78bSCy Schubert     return get_matching_data(context, plgctx, reqctx, reqctx->received_cert,
5813*7f2fe78bSCy Schubert                              md_out);
5814*7f2fe78bSCy Schubert }
5815