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