1 /*
2  * Copyright (c) 2004 Peter 'Luna' Runestig <peter@runestig.com>
3  * Copyright (c) 2018 Selva Nair <selva.nair@gmail.com>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without modifi-
7  * cation, are permitted provided that the following conditions are met:
8  *
9  *   o  Redistributions of source code must retain the above copyright notice,
10  *      this list of conditions and the following disclaimer.
11  *
12  *   o  Redistributions in binary form must reproduce the above copyright no-
13  *      tice, this list of conditions and the following disclaimer in the do-
14  *      cumentation and/or other materials provided with the distribution.
15  *
16  *   o  The names of the contributors may not be used to endorse or promote
17  *      products derived from this software without specific prior written
18  *      permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LI-
24  * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
25  * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
27  * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
28  * LITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
29  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #elif defined(_MSC_VER)
35 #include "config-msvc.h"
36 #endif
37 
38 #include "syshead.h"
39 
40 #ifdef ENABLE_CRYPTOAPI
41 
42 #include <openssl/ssl.h>
43 #include <openssl/evp.h>
44 #include <openssl/err.h>
45 #include <windows.h>
46 #include <wincrypt.h>
47 #include <ncrypt.h>
48 #include <stdio.h>
49 #include <ctype.h>
50 #include <assert.h>
51 
52 #include "buffer.h"
53 #include "openssl_compat.h"
54 #include "win32.h"
55 
56 /* MinGW w32api 3.17 is still incomplete when it comes to CryptoAPI while
57  * MinGW32-w64 defines all macros used. This is a hack around that problem.
58  */
59 #ifndef CERT_SYSTEM_STORE_LOCATION_SHIFT
60 #define CERT_SYSTEM_STORE_LOCATION_SHIFT 16
61 #endif
62 #ifndef CERT_SYSTEM_STORE_CURRENT_USER_ID
63 #define CERT_SYSTEM_STORE_CURRENT_USER_ID 1
64 #endif
65 #ifndef CERT_SYSTEM_STORE_CURRENT_USER
66 #define CERT_SYSTEM_STORE_CURRENT_USER (CERT_SYSTEM_STORE_CURRENT_USER_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT)
67 #endif
68 #ifndef CERT_STORE_READONLY_FLAG
69 #define CERT_STORE_READONLY_FLAG 0x00008000
70 #endif
71 #ifndef CERT_STORE_OPEN_EXISTING_FLAG
72 #define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000
73 #endif
74 
75 /* Size of an SSL signature: MD5+SHA1 */
76 #define SSL_SIG_LENGTH  36
77 
78 /* try to funnel any Windows/CryptoAPI error messages to OpenSSL ERR_... */
79 #define ERR_LIB_CRYPTOAPI (ERR_LIB_USER + 69)   /* 69 is just a number... */
80 #define CRYPTOAPIerr(f)   err_put_ms_error(GetLastError(), (f), __FILE__, __LINE__)
81 #define CRYPTOAPI_F_CERT_OPEN_SYSTEM_STORE                  100
82 #define CRYPTOAPI_F_CERT_FIND_CERTIFICATE_IN_STORE          101
83 #define CRYPTOAPI_F_CRYPT_ACQUIRE_CERTIFICATE_PRIVATE_KEY   102
84 #define CRYPTOAPI_F_CRYPT_CREATE_HASH                       103
85 #define CRYPTOAPI_F_CRYPT_GET_HASH_PARAM                    104
86 #define CRYPTOAPI_F_CRYPT_SET_HASH_PARAM                    105
87 #define CRYPTOAPI_F_CRYPT_SIGN_HASH                         106
88 #define CRYPTOAPI_F_LOAD_LIBRARY                            107
89 #define CRYPTOAPI_F_GET_PROC_ADDRESS                        108
90 #define CRYPTOAPI_F_NCRYPT_SIGN_HASH                        109
91 
92 static ERR_STRING_DATA CRYPTOAPI_str_functs[] = {
93     { ERR_PACK(ERR_LIB_CRYPTOAPI, 0, 0),                                    "microsoft cryptoapi"},
94     { ERR_PACK(0, CRYPTOAPI_F_CERT_OPEN_SYSTEM_STORE, 0),                   "CertOpenSystemStore" },
95     { ERR_PACK(0, CRYPTOAPI_F_CERT_FIND_CERTIFICATE_IN_STORE, 0),           "CertFindCertificateInStore" },
96     { ERR_PACK(0, CRYPTOAPI_F_CRYPT_ACQUIRE_CERTIFICATE_PRIVATE_KEY, 0),    "CryptAcquireCertificatePrivateKey" },
97     { ERR_PACK(0, CRYPTOAPI_F_CRYPT_CREATE_HASH, 0),                        "CryptCreateHash" },
98     { ERR_PACK(0, CRYPTOAPI_F_CRYPT_GET_HASH_PARAM, 0),                     "CryptGetHashParam" },
99     { ERR_PACK(0, CRYPTOAPI_F_CRYPT_SET_HASH_PARAM, 0),                     "CryptSetHashParam" },
100     { ERR_PACK(0, CRYPTOAPI_F_CRYPT_SIGN_HASH, 0),                          "CryptSignHash" },
101     { ERR_PACK(0, CRYPTOAPI_F_LOAD_LIBRARY, 0),                             "LoadLibrary" },
102     { ERR_PACK(0, CRYPTOAPI_F_GET_PROC_ADDRESS, 0),                         "GetProcAddress" },
103     { ERR_PACK(0, CRYPTOAPI_F_NCRYPT_SIGN_HASH, 0),                         "NCryptSignHash" },
104     { 0, NULL }
105 };
106 
107 /* index for storing external data in EC_KEY: < 0 means uninitialized */
108 static int ec_data_idx = -1;
109 
110 /* Global EVP_PKEY_METHOD used to override the sign operation */
111 static EVP_PKEY_METHOD *pmethod;
112 static int (*default_pkey_sign_init) (EVP_PKEY_CTX *ctx);
113 static int (*default_pkey_sign) (EVP_PKEY_CTX *ctx, unsigned char *sig,
114                                  size_t *siglen, const unsigned char *tbs, size_t tbslen);
115 
116 typedef struct _CAPI_DATA {
117     const CERT_CONTEXT *cert_context;
118     HCRYPTPROV_OR_NCRYPT_KEY_HANDLE crypt_prov;
119     DWORD key_spec;
120     BOOL free_crypt_prov;
121     int ref_count;
122 } CAPI_DATA;
123 
124 /* Translate OpenSSL padding type to CNG padding type
125  * Returns 0 for unknown/unsupported padding.
126  */
127 static DWORD
cng_padding_type(int padding)128 cng_padding_type(int padding)
129 {
130     DWORD pad = 0;
131 
132     switch (padding)
133     {
134         case RSA_NO_PADDING:
135             break;
136 
137         case RSA_PKCS1_PADDING:
138             pad = BCRYPT_PAD_PKCS1;
139             break;
140 
141         case RSA_PKCS1_PSS_PADDING:
142             pad = BCRYPT_PAD_PSS;
143             break;
144 
145         default:
146             msg(M_WARN|M_INFO, "cryptoapicert: unknown OpenSSL padding type %d.",
147                 padding);
148     }
149 
150     return pad;
151 }
152 
153 /*
154  * Translate OpenSSL hash OID to CNG algorithm name. Returns
155  * "UNKNOWN" for unsupported algorithms and NULL for MD5+SHA1
156  * mixed hash used in TLS 1.1 and earlier.
157  */
158 static const wchar_t *
cng_hash_algo(int md_type)159 cng_hash_algo(int md_type)
160 {
161     const wchar_t *alg = L"UNKNOWN";
162     switch (md_type)
163     {
164         case NID_md5:
165             alg = BCRYPT_MD5_ALGORITHM;
166             break;
167 
168         case NID_sha1:
169             alg = BCRYPT_SHA1_ALGORITHM;
170             break;
171 
172         case NID_sha256:
173             alg = BCRYPT_SHA256_ALGORITHM;
174             break;
175 
176         case NID_sha384:
177             alg = BCRYPT_SHA384_ALGORITHM;
178             break;
179 
180         case NID_sha512:
181             alg = BCRYPT_SHA512_ALGORITHM;
182             break;
183 
184         case NID_md5_sha1:
185         case 0:
186             alg = NULL;
187             break;
188 
189         default:
190             msg(M_WARN|M_INFO, "cryptoapicert: Unknown hash type NID=0x%x", md_type);
191             break;
192     }
193     return alg;
194 }
195 
196 static void
CAPI_DATA_free(CAPI_DATA * cd)197 CAPI_DATA_free(CAPI_DATA *cd)
198 {
199     if (!cd || cd->ref_count-- > 0)
200     {
201         return;
202     }
203     if (cd->free_crypt_prov && cd->crypt_prov)
204     {
205         if (cd->key_spec == CERT_NCRYPT_KEY_SPEC)
206         {
207             NCryptFreeObject(cd->crypt_prov);
208         }
209         else
210         {
211             CryptReleaseContext(cd->crypt_prov, 0);
212         }
213     }
214     if (cd->cert_context)
215     {
216         CertFreeCertificateContext(cd->cert_context);
217     }
218     free(cd);
219 }
220 
221 static char *
ms_error_text(DWORD ms_err)222 ms_error_text(DWORD ms_err)
223 {
224     LPVOID lpMsgBuf = NULL;
225     char *rv = NULL;
226 
227     FormatMessage(
228         FORMAT_MESSAGE_ALLOCATE_BUFFER
229         |FORMAT_MESSAGE_FROM_SYSTEM
230         |FORMAT_MESSAGE_IGNORE_INSERTS,
231         NULL, ms_err,
232         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
233         (LPTSTR) &lpMsgBuf, 0, NULL);
234     if (lpMsgBuf)
235     {
236         char *p;
237         rv = string_alloc(lpMsgBuf, NULL);
238         LocalFree(lpMsgBuf);
239         /* trim to the left */
240         if (rv)
241         {
242             for (p = rv + strlen(rv) - 1; p >= rv; p--)
243             {
244                 if (isspace(*p))
245                 {
246                     *p = '\0';
247                 }
248                 else
249                 {
250                     break;
251                 }
252             }
253         }
254     }
255     return rv;
256 }
257 
258 static void
err_put_ms_error(DWORD ms_err,int func,const char * file,int line)259 err_put_ms_error(DWORD ms_err, int func, const char *file, int line)
260 {
261     static int init = 0;
262 #define ERR_MAP_SZ 16
263     static struct {
264         int err;
265         DWORD ms_err;       /* I don't think we get more than 16 *different* errors */
266     } err_map[ERR_MAP_SZ];  /* in here, before we give up the whole thing...        */
267     int i;
268 
269     if (ms_err == 0)
270     {
271         /* 0 is not an error */
272         return;
273     }
274     if (!init)
275     {
276         ERR_load_strings(ERR_LIB_CRYPTOAPI, CRYPTOAPI_str_functs);
277         memset(&err_map, 0, sizeof(err_map));
278         init++;
279     }
280     /* since MS error codes are 32 bit, and the ones in the ERR_... system is
281      * only 12, we must have a mapping table between them.  */
282     for (i = 0; i < ERR_MAP_SZ; i++)
283     {
284         if (err_map[i].ms_err == ms_err)
285         {
286             ERR_PUT_error(ERR_LIB_CRYPTOAPI, func, err_map[i].err, file, line);
287             break;
288         }
289         else if (err_map[i].ms_err == 0)
290         {
291             /* end of table, add new entry */
292             ERR_STRING_DATA *esd = calloc(2, sizeof(*esd));
293             if (esd == NULL)
294             {
295                 break;
296             }
297             err_map[i].ms_err = ms_err;
298             err_map[i].err = esd->error = i + 100;
299             esd->string = ms_error_text(ms_err);
300             check_malloc_return(esd->string);
301             ERR_load_strings(ERR_LIB_CRYPTOAPI, esd);
302             ERR_PUT_error(ERR_LIB_CRYPTOAPI, func, err_map[i].err, file, line);
303             break;
304         }
305     }
306 }
307 
308 /* encrypt */
309 static int
rsa_pub_enc(int flen,const unsigned char * from,unsigned char * to,RSA * rsa,int padding)310 rsa_pub_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
311 {
312     /* I haven't been able to trigger this one, but I want to know if it happens... */
313     assert(0);
314 
315     return 0;
316 }
317 
318 /* verify arbitrary data */
319 static int
rsa_pub_dec(int flen,const unsigned char * from,unsigned char * to,RSA * rsa,int padding)320 rsa_pub_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
321 {
322     /* I haven't been able to trigger this one, but I want to know if it happens... */
323     assert(0);
324 
325     return 0;
326 }
327 
328 /**
329  * Sign the hash in 'from' using NCryptSignHash(). This requires an NCRYPT
330  * key handle in cd->crypt_prov. On return the signature is in 'to'. Returns
331  * the length of the signature or 0 on error.
332  * This is used only for RSA and padding should be BCRYPT_PAD_PKCS1 or
333  * BCRYPT_PAD_PSS.
334  * If the hash_algo is not NULL, PKCS #1 DigestInfo header gets added
335  * to |from|, else it is signed as is. Use NULL for MD5 + SHA1 hash used
336  * in TLS 1.1 and earlier.
337  * In case of PSS padding, |saltlen| should specify the size of salt to use.
338  * If |to| is NULL returns the required buffer size.
339  */
340 static int
priv_enc_CNG(const CAPI_DATA * cd,const wchar_t * hash_algo,const unsigned char * from,int flen,unsigned char * to,int tlen,DWORD padding,DWORD saltlen)341 priv_enc_CNG(const CAPI_DATA *cd, const wchar_t *hash_algo, const unsigned char *from,
342              int flen, unsigned char *to, int tlen, DWORD padding, DWORD saltlen)
343 {
344     NCRYPT_KEY_HANDLE hkey = cd->crypt_prov;
345     DWORD len = 0;
346     ASSERT(cd->key_spec == CERT_NCRYPT_KEY_SPEC);
347 
348     DWORD status;
349 
350     msg(D_LOW, "Signing hash using CNG: data size = %d padding = %lu", flen, padding);
351 
352     if (padding == BCRYPT_PAD_PKCS1)
353     {
354         BCRYPT_PKCS1_PADDING_INFO padinfo = {hash_algo};
355         status = NCryptSignHash(hkey, &padinfo, (BYTE *)from, flen,
356                                 to, tlen, &len, padding);
357     }
358     else if (padding == BCRYPT_PAD_PSS)
359     {
360         BCRYPT_PSS_PADDING_INFO padinfo = {hash_algo, saltlen};
361         status = NCryptSignHash(hkey, &padinfo, (BYTE *)from, flen,
362                                 to, tlen, &len, padding);
363     }
364     else
365     {
366         RSAerr(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE);
367         return 0;
368     }
369 
370     if (status != ERROR_SUCCESS)
371     {
372         SetLastError(status);
373         CRYPTOAPIerr(CRYPTOAPI_F_NCRYPT_SIGN_HASH);
374         len = 0;
375     }
376 
377     /* Unlike CAPI, CNG signature is in big endian order. No reversing needed. */
378     return len;
379 }
380 
381 /* sign arbitrary data */
382 static int
rsa_priv_enc(int flen,const unsigned char * from,unsigned char * to,RSA * rsa,int padding)383 rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
384 {
385     CAPI_DATA *cd = (CAPI_DATA *) RSA_meth_get0_app_data(RSA_get_method(rsa));
386     HCRYPTHASH hash;
387     DWORD hash_size, len, i;
388     unsigned char *buf;
389 
390     if (cd == NULL)
391     {
392         RSAerr(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT, ERR_R_PASSED_NULL_PARAMETER);
393         return 0;
394     }
395 
396     if (padding != RSA_PKCS1_PADDING)
397     {
398         /* AFAICS, CryptSignHash() *always* uses PKCS1 padding. */
399         RSAerr(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE);
400         return 0;
401     }
402 
403     if (cd->key_spec == CERT_NCRYPT_KEY_SPEC)
404     {
405         return priv_enc_CNG(cd, NULL, from, flen, to, RSA_size(rsa),
406                             cng_padding_type(padding), 0);
407     }
408 
409     /* Unfortunately, there is no "CryptSign()" function in CryptoAPI, that would
410      * be way to straightforward for M$, I guess... So we have to do it this
411      * tricky way instead, by creating a "Hash", and load the already-made hash
412      * from 'from' into it.  */
413     /* For now, we only support NID_md5_sha1 */
414     if (flen != SSL_SIG_LENGTH)
415     {
416         RSAerr(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT, RSA_R_INVALID_MESSAGE_LENGTH);
417         return 0;
418     }
419     if (!CryptCreateHash(cd->crypt_prov, CALG_SSL3_SHAMD5, 0, 0, &hash))
420     {
421         CRYPTOAPIerr(CRYPTOAPI_F_CRYPT_CREATE_HASH);
422         return 0;
423     }
424     len = sizeof(hash_size);
425     if (!CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *) &hash_size, &len, 0))
426     {
427         CRYPTOAPIerr(CRYPTOAPI_F_CRYPT_GET_HASH_PARAM);
428         CryptDestroyHash(hash);
429         return 0;
430     }
431     if ((int) hash_size != flen)
432     {
433         RSAerr(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT, RSA_R_INVALID_MESSAGE_LENGTH);
434         CryptDestroyHash(hash);
435         return 0;
436     }
437     if (!CryptSetHashParam(hash, HP_HASHVAL, (BYTE * ) from, 0))
438     {
439         CRYPTOAPIerr(CRYPTOAPI_F_CRYPT_SET_HASH_PARAM);
440         CryptDestroyHash(hash);
441         return 0;
442     }
443 
444     len = RSA_size(rsa);
445     buf = malloc(len);
446     if (buf == NULL)
447     {
448         RSAerr(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT, ERR_R_MALLOC_FAILURE);
449         CryptDestroyHash(hash);
450         return 0;
451     }
452     if (!CryptSignHash(hash, cd->key_spec, NULL, 0, buf, &len))
453     {
454         CRYPTOAPIerr(CRYPTOAPI_F_CRYPT_SIGN_HASH);
455         CryptDestroyHash(hash);
456         free(buf);
457         return 0;
458     }
459     /* and now, we have to reverse the byte-order in the result from CryptSignHash()... */
460     for (i = 0; i < len; i++)
461     {
462         to[i] = buf[len - i - 1];
463     }
464     free(buf);
465 
466     CryptDestroyHash(hash);
467     return len;
468 }
469 
470 /**
471  * Sign the hash in |m| and return the signature in |sig|.
472  * Returns 1 on success, 0 on error.
473  * NCryptSignHash() is used to sign and it is instructed to add the
474  * the PKCS #1 DigestInfo header to |m| unless the hash algorithm is
475  * the MD5/SHA1 combination used in TLS 1.1 and earlier versions.
476  * OpenSSL exercises this callback only when padding is PKCS1 v1.5.
477  */
478 static int
rsa_sign_CNG(int type,const unsigned char * m,unsigned int m_len,unsigned char * sig,unsigned int * siglen,const RSA * rsa)479 rsa_sign_CNG(int type, const unsigned char *m, unsigned int m_len,
480              unsigned char *sig, unsigned int *siglen, const RSA *rsa)
481 {
482     CAPI_DATA *cd = (CAPI_DATA *) RSA_meth_get0_app_data(RSA_get_method(rsa));
483     const wchar_t *alg = NULL;
484     int padding = RSA_PKCS1_PADDING;
485 
486     *siglen = 0;
487     if (cd == NULL)
488     {
489         RSAerr(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT, ERR_R_PASSED_NULL_PARAMETER);
490         return 0;
491     }
492 
493     alg = cng_hash_algo(type);
494     if (alg && wcscmp(alg, L"UNKNOWN") == 0)
495     {
496         RSAerr(RSA_F_RSA_SIGN, RSA_R_UNKNOWN_ALGORITHM_TYPE);
497         return 0;
498     }
499 
500     *siglen = priv_enc_CNG(cd, alg, m, (int)m_len, sig, RSA_size(rsa),
501                            cng_padding_type(padding), 0);
502 
503     return (*siglen == 0) ? 0 : 1;
504 }
505 
506 /* decrypt */
507 static int
rsa_priv_dec(int flen,const unsigned char * from,unsigned char * to,RSA * rsa,int padding)508 rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
509 {
510     /* I haven't been able to trigger this one, but I want to know if it happens... */
511     assert(0);
512 
513     return 0;
514 }
515 
516 /* called at RSA_new */
517 static int
init(RSA * rsa)518 init(RSA *rsa)
519 {
520 
521     return 0;
522 }
523 
524 /* called at RSA_free */
525 static int
finish(RSA * rsa)526 finish(RSA *rsa)
527 {
528     const RSA_METHOD *rsa_meth = RSA_get_method(rsa);
529     CAPI_DATA *cd = (CAPI_DATA *) RSA_meth_get0_app_data(rsa_meth);
530 
531     if (cd == NULL)
532     {
533         return 0;
534     }
535     CAPI_DATA_free(cd);
536     RSA_meth_free((RSA_METHOD *) rsa_meth);
537     return 1;
538 }
539 
540 #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(OPENSSL_NO_EC)
541 
542 static EC_KEY_METHOD *ec_method = NULL;
543 
544 /** EC_KEY_METHOD callback: called when the key is freed */
545 static void
ec_finish(EC_KEY * ec)546 ec_finish(EC_KEY *ec)
547 {
548     EC_KEY_METHOD_free(ec_method);
549     ec_method = NULL;
550     CAPI_DATA *cd = EC_KEY_get_ex_data(ec, ec_data_idx);
551     CAPI_DATA_free(cd);
552     EC_KEY_set_ex_data(ec, ec_data_idx, NULL);
553 }
554 
555 /** EC_KEY_METHOD callback sign_setup(): we do nothing here */
556 static int
ecdsa_sign_setup(EC_KEY * eckey,BN_CTX * ctx_in,BIGNUM ** kinvp,BIGNUM ** rp)557 ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp)
558 {
559     return 1;
560 }
561 
562 /**
563  * Helper to convert ECDSA signature returned by NCryptSignHash
564  * to an ECDSA_SIG structure.
565  * On entry 'buf[]' of length len contains r and s concatenated.
566  * Returns a newly allocated ECDSA_SIG or NULL (on error).
567  */
568 static ECDSA_SIG *
ecdsa_bin2sig(unsigned char * buf,int len)569 ecdsa_bin2sig(unsigned char *buf, int len)
570 {
571     ECDSA_SIG *ecsig = NULL;
572     DWORD rlen = len/2;
573     BIGNUM *r = BN_bin2bn(buf, rlen, NULL);
574     BIGNUM *s = BN_bin2bn(buf+rlen, rlen, NULL);
575     if (!r || !s)
576     {
577         goto err;
578     }
579     ecsig = ECDSA_SIG_new(); /* in openssl 1.1 this does not allocate r, s */
580     if (!ecsig)
581     {
582         goto err;
583     }
584     if (!ECDSA_SIG_set0(ecsig, r, s)) /* ecsig takes ownership of r and s */
585     {
586         ECDSA_SIG_free(ecsig);
587         goto err;
588     }
589     return ecsig;
590 err:
591     BN_free(r); /* it is ok to free NULL BN */
592     BN_free(s);
593     return NULL;
594 }
595 
596 /** EC_KEY_METHOD callback sign_sig(): sign and return an ECDSA_SIG pointer. */
597 static ECDSA_SIG *
ecdsa_sign_sig(const unsigned char * dgst,int dgstlen,const BIGNUM * in_kinv,const BIGNUM * in_r,EC_KEY * ec)598 ecdsa_sign_sig(const unsigned char *dgst, int dgstlen,
599                const BIGNUM *in_kinv, const BIGNUM *in_r, EC_KEY *ec)
600 {
601     ECDSA_SIG *ecsig = NULL;
602     CAPI_DATA *cd = (CAPI_DATA *)EC_KEY_get_ex_data(ec, ec_data_idx);
603 
604     ASSERT(cd->key_spec == CERT_NCRYPT_KEY_SPEC);
605 
606     NCRYPT_KEY_HANDLE hkey = cd->crypt_prov;
607     BYTE buf[512]; /* large enough buffer for signature to avoid malloc */
608     DWORD len = _countof(buf);
609 
610     msg(D_LOW, "Cryptoapi: signing hash using EC key: data size = %d", dgstlen);
611 
612     DWORD status = NCryptSignHash(hkey, NULL, (BYTE *)dgst, dgstlen, (BYTE *)buf, len, &len, 0);
613     if (status != ERROR_SUCCESS)
614     {
615         SetLastError(status);
616         CRYPTOAPIerr(CRYPTOAPI_F_NCRYPT_SIGN_HASH);
617     }
618     else
619     {
620         /* NCryptSignHash returns r, s concatenated in buf[] */
621         ecsig = ecdsa_bin2sig(buf, len);
622     }
623     return ecsig;
624 }
625 
626 /** EC_KEY_METHOD callback sign(): sign and return a DER encoded signature */
627 static int
ecdsa_sign(int type,const unsigned char * dgst,int dgstlen,unsigned char * sig,unsigned int * siglen,const BIGNUM * kinv,const BIGNUM * r,EC_KEY * ec)628 ecdsa_sign(int type, const unsigned char *dgst, int dgstlen, unsigned char *sig,
629            unsigned int *siglen, const BIGNUM *kinv, const BIGNUM *r, EC_KEY *ec)
630 {
631     ECDSA_SIG *s;
632 
633     *siglen = 0;
634     s = ecdsa_sign_sig(dgst, dgstlen, NULL, NULL, ec);
635     if (s == NULL)
636     {
637         return 0;
638     }
639 
640     /* convert internal signature structure 's' to DER encoded byte array in sig */
641     int len = i2d_ECDSA_SIG(s, NULL);
642     if (len > ECDSA_size(ec))
643     {
644         ECDSA_SIG_free(s);
645         msg(M_NONFATAL,"Error: DER encoded ECDSA signature is too long (%d bytes)", len);
646         return 0;
647     }
648     *siglen = i2d_ECDSA_SIG(s, &sig);
649     ECDSA_SIG_free(s);
650 
651     return 1;
652 }
653 
654 static int
ssl_ctx_set_eckey(SSL_CTX * ssl_ctx,CAPI_DATA * cd,EVP_PKEY * pkey)655 ssl_ctx_set_eckey(SSL_CTX *ssl_ctx, CAPI_DATA *cd, EVP_PKEY *pkey)
656 {
657     EC_KEY *ec = NULL;
658     EVP_PKEY *privkey = NULL;
659 
660     if (cd->key_spec != CERT_NCRYPT_KEY_SPEC)
661     {
662         msg(M_NONFATAL, "ERROR: cryptoapicert with only legacy private key handle available."
663             " EC certificate not supported.");
664         goto err;
665     }
666     /* create a method struct with default callbacks filled in */
667     ec_method = EC_KEY_METHOD_new(EC_KEY_OpenSSL());
668     if (!ec_method)
669     {
670         goto err;
671     }
672 
673     /* We only need to set finish among init methods, and sign methods */
674     EC_KEY_METHOD_set_init(ec_method, NULL, ec_finish, NULL, NULL, NULL, NULL);
675     EC_KEY_METHOD_set_sign(ec_method, ecdsa_sign, ecdsa_sign_setup, ecdsa_sign_sig);
676 
677     ec = EC_KEY_dup(EVP_PKEY_get0_EC_KEY(pkey));
678     if (!ec)
679     {
680         goto err;
681     }
682     if (!EC_KEY_set_method(ec, ec_method))
683     {
684         goto err;
685     }
686 
687     /* get an index to store cd as external data */
688     if (ec_data_idx < 0)
689     {
690         ec_data_idx = EC_KEY_get_ex_new_index(0, "cryptapicert ec key", NULL, NULL, NULL);
691         if (ec_data_idx < 0)
692         {
693             goto err;
694         }
695     }
696     EC_KEY_set_ex_data(ec, ec_data_idx, cd);
697 
698     /* cd assigned to ec as ex_data, increase its refcount */
699     cd->ref_count++;
700 
701     privkey = EVP_PKEY_new();
702     if (!EVP_PKEY_assign_EC_KEY(privkey, ec))
703     {
704         EC_KEY_free(ec);
705         goto err;
706     }
707     /* from here on ec will get freed with privkey */
708 
709     if (!SSL_CTX_use_PrivateKey(ssl_ctx, privkey))
710     {
711         goto err;
712     }
713     EVP_PKEY_free(privkey); /* this will dn_ref or free ec as well */
714     return 1;
715 
716 err:
717     if (privkey)
718     {
719         EVP_PKEY_free(privkey);
720     }
721     else if (ec)
722     {
723         EC_KEY_free(ec);
724     }
725     if (ec_method) /* do always set ec_method = NULL after freeing it */
726     {
727         EC_KEY_METHOD_free(ec_method);
728         ec_method = NULL;
729     }
730     return 0;
731 }
732 
733 #endif /* OPENSSL_VERSION_NUMBER >= 1.1.0 */
734 
735 static const CERT_CONTEXT *
find_certificate_in_store(const char * cert_prop,HCERTSTORE cert_store)736 find_certificate_in_store(const char *cert_prop, HCERTSTORE cert_store)
737 {
738     /* Find, and use, the desired certificate from the store. The
739      * 'cert_prop' certificate search string can look like this:
740      * SUBJ:<certificate substring to match>
741      * THUMB:<certificate thumbprint hex value>, e.g.
742      *     THUMB:f6 49 24 41 01 b4 fb 44 0c ce f4 36 ae d0 c4 c9 df 7a b6 28
743      * The first matching certificate that has not expired is returned.
744      */
745     const CERT_CONTEXT *rv = NULL;
746     DWORD find_type;
747     const void *find_param;
748     unsigned char hash[255];
749     CRYPT_HASH_BLOB blob = {.cbData = 0, .pbData = hash};
750     struct gc_arena gc = gc_new();
751 
752     if (!strncmp(cert_prop, "SUBJ:", 5))
753     {
754         /* skip the tag */
755         find_param = wide_string(cert_prop + 5, &gc);
756         find_type = CERT_FIND_SUBJECT_STR_W;
757     }
758     else if (!strncmp(cert_prop, "THUMB:", 6))
759     {
760         const char *p;
761         int i, x = 0;
762         find_type = CERT_FIND_HASH;
763         find_param = &blob;
764 
765         /* skip the tag */
766         cert_prop += 6;
767         for (p = cert_prop, i = 0; *p && i < sizeof(hash); i++)
768         {
769             if (*p >= '0' && *p <= '9')
770             {
771                 x = (*p - '0') << 4;
772             }
773             else if (*p >= 'A' && *p <= 'F')
774             {
775                 x = (*p - 'A' + 10) << 4;
776             }
777             else if (*p >= 'a' && *p <= 'f')
778             {
779                 x = (*p - 'a' + 10) << 4;
780             }
781             if (!*++p)  /* unexpected end of string */
782             {
783                 msg(M_WARN, "WARNING: cryptoapicert: error parsing <THUMB:%s>.", cert_prop);
784                 goto out;
785             }
786             if (*p >= '0' && *p <= '9')
787             {
788                 x += *p - '0';
789             }
790             else if (*p >= 'A' && *p <= 'F')
791             {
792                 x += *p - 'A' + 10;
793             }
794             else if (*p >= 'a' && *p <= 'f')
795             {
796                 x += *p - 'a' + 10;
797             }
798             hash[i] = x;
799             /* skip any space(s) between hex numbers */
800             for (p++; *p && *p == ' '; p++)
801             {
802             }
803         }
804         blob.cbData = i;
805     }
806     else
807     {
808         msg(M_WARN, "WARNING: cryptoapicert: unsupported certificate specification <%s>", cert_prop);
809         goto out;
810     }
811 
812     while (true)
813     {
814         int validity = 1;
815         /* this frees previous rv, if not NULL */
816         rv = CertFindCertificateInStore(cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
817                                         0, find_type, find_param, rv);
818         if (rv)
819         {
820             validity = CertVerifyTimeValidity(NULL, rv->pCertInfo);
821         }
822         if (!rv || validity == 0)
823         {
824             break;
825         }
826         msg(M_WARN, "WARNING: cryptoapicert: ignoring certificate in store %s.",
827             validity < 0 ? "not yet valid" : "that has expired");
828     }
829 
830 out:
831     gc_free(&gc);
832     return rv;
833 }
834 
835 #if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
836 
837 static const CAPI_DATA *
retrieve_capi_data(EVP_PKEY * pkey)838 retrieve_capi_data(EVP_PKEY *pkey)
839 {
840     const CAPI_DATA *cd = NULL;
841 
842     if (pkey && EVP_PKEY_id(pkey) == EVP_PKEY_RSA)
843     {
844         RSA *rsa = EVP_PKEY_get0_RSA(pkey);
845         if (rsa)
846         {
847             cd = (CAPI_DATA *)RSA_meth_get0_app_data(RSA_get_method(rsa));
848         }
849     }
850     return cd;
851 }
852 
853 static int
pkey_rsa_sign_init(EVP_PKEY_CTX * ctx)854 pkey_rsa_sign_init(EVP_PKEY_CTX *ctx)
855 {
856     msg(D_LOW, "cryptoapicert: enter pkey_rsa_sign_init");
857 
858     EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);
859 
860     if (pkey && retrieve_capi_data(pkey))
861     {
862         return 1; /* Return success */
863     }
864     else if (default_pkey_sign_init)  /* Not our key. Call the default method */
865     {
866         return default_pkey_sign_init(ctx);
867     }
868     return 1;
869 }
870 
871 /**
872  * Implementation of EVP_PKEY_sign() using CNG: sign the digest in |tbs|
873  * and save the the signature in |sig| and its size in |*siglen|.
874  * If |sig| is NULL the required buffer size is returned in |*siglen|.
875  * Returns value is 1 on success, 0 or a negative integer on error.
876  */
877 static int
pkey_rsa_sign(EVP_PKEY_CTX * ctx,unsigned char * sig,size_t * siglen,const unsigned char * tbs,size_t tbslen)878 pkey_rsa_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
879               const unsigned char *tbs, size_t tbslen)
880 {
881     EVP_PKEY *pkey = NULL;
882     const CAPI_DATA *cd = NULL;
883     EVP_MD *md = NULL;
884     const wchar_t *alg = NULL;
885 
886     int padding = 0;
887     int hashlen = 0;
888     int saltlen = 0;
889 
890     pkey = EVP_PKEY_CTX_get0_pkey(ctx);
891     if (pkey)
892     {
893         cd = retrieve_capi_data(pkey);
894     }
895 
896     /*
897      * We intercept all sign requests, not just the one's for our key.
898      * Check the key and call the saved OpenSSL method for unknown keys.
899      */
900     if (!pkey || !cd)
901     {
902         if (default_pkey_sign)
903         {
904             return default_pkey_sign(ctx, sig, siglen, tbs, tbslen);
905         }
906         else  /* This should not happen */
907         {
908             msg(M_FATAL, "cryptopaicert: Unknown key and no default sign operation to fallback on");
909             return -1;
910         }
911     }
912 
913     if (!EVP_PKEY_CTX_get_rsa_padding(ctx, &padding))
914     {
915         padding = RSA_PKCS1_PADDING; /* Default padding for RSA */
916     }
917 
918     if (EVP_PKEY_CTX_get_signature_md(ctx, &md))
919     {
920         hashlen = EVP_MD_size(md);
921         alg = cng_hash_algo(EVP_MD_type(md));
922 
923         /*
924          * alg == NULL indicates legacy MD5+SHA1 hash, else alg should be a valid
925          * digest algorithm.
926          */
927         if (alg && wcscmp(alg, L"UNKNOWN") == 0)
928         {
929             RSAerr(RSA_F_PKEY_RSA_SIGN, RSA_R_UNKNOWN_ALGORITHM_TYPE);
930             return -1;
931         }
932     }
933     else
934     {
935         msg(M_NONFATAL, "cryptoapicert: could not determine the signature digest algorithm");
936         RSAerr(RSA_F_PKEY_RSA_SIGN, RSA_R_UNKNOWN_ALGORITHM_TYPE);
937         return -1;
938     }
939 
940     if (tbslen != (size_t)hashlen)
941     {
942         RSAerr(RSA_F_PKEY_RSA_SIGN, RSA_R_INVALID_DIGEST_LENGTH);
943         return -1;
944     }
945 
946     /* If padding is PSS, determine parameters to pass to CNG */
947     if (padding == RSA_PKCS1_PSS_PADDING)
948     {
949         /*
950          * Ensure the digest type for signature and mask generation match.
951          * In CNG there is no option to specify separate hash functions for
952          * the two, but OpenSSL supports it. However, I have not seen the
953          * two being different in practice. Also the recommended practice is
954          * to use the same for both (rfc 8017 sec 8.1).
955          */
956         EVP_MD *mgf1md;
957         if (!EVP_PKEY_CTX_get_rsa_mgf1_md(ctx, &mgf1md)
958             || EVP_MD_type(mgf1md) != EVP_MD_type(md))
959         {
960             msg(M_NONFATAL, "cryptoapicert: Unknown MGF1 digest type or does"
961                 " not match the signature digest type.");
962             RSAerr(RSA_F_PKEY_RSA_SIGN, RSA_R_UNSUPPORTED_MASK_PARAMETER);
963         }
964 
965         if (!EVP_PKEY_CTX_get_rsa_pss_saltlen(ctx, &saltlen))
966         {
967             msg(M_WARN, "cryptoapicert: unable to get the salt length from context."
968                 " Using the default value.");
969             saltlen = -1;
970         }
971 
972         /*
973          * In OpenSSL saltlen = -1 indicates to use the size of the digest as
974          * size of the salt. A value of -2 or -3 indicates maximum salt length
975          * that will fit. See RSA_padding_add_PKCS1_PSS_mgf1() of OpenSSL.
976          */
977         if (saltlen == -1)
978         {
979             saltlen = hashlen;
980         }
981         else if (saltlen < 0)
982         {
983             const RSA *rsa = EVP_PKEY_get0_RSA(pkey);
984             saltlen = RSA_size(rsa) - hashlen - 2; /* max salt length for RSASSA-PSS */
985             if (RSA_bits(rsa) &0x7) /* number of bits in the key not a multiple of 8 */
986             {
987                 saltlen--;
988             }
989         }
990 
991         if (saltlen < 0)
992         {
993             RSAerr(RSA_F_PKEY_RSA_SIGN, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
994             return -1;
995         }
996         msg(D_LOW, "cryptoapicert: PSS padding using saltlen = %d", saltlen);
997     }
998 
999     msg(D_LOW, "cryptoapicert: calling priv_enc_CNG with alg = %ls", alg);
1000     *siglen = priv_enc_CNG(cd, alg, tbs, (int)tbslen, sig, (int)*siglen,
1001                            cng_padding_type(padding), (DWORD)saltlen);
1002 
1003     return (*siglen == 0) ? 0 : 1;
1004 }
1005 
1006 #endif /* OPENSSL_VERSION >= 1.1.0 */
1007 
1008 static int
ssl_ctx_set_rsakey(SSL_CTX * ssl_ctx,CAPI_DATA * cd,EVP_PKEY * pkey)1009 ssl_ctx_set_rsakey(SSL_CTX *ssl_ctx, CAPI_DATA *cd, EVP_PKEY *pkey)
1010 {
1011     RSA *rsa = NULL, *pub_rsa;
1012     RSA_METHOD *my_rsa_method = NULL;
1013     bool rsa_method_set = false;
1014 
1015     my_rsa_method = RSA_meth_new("Microsoft Cryptography API RSA Method",
1016                                  RSA_METHOD_FLAG_NO_CHECK);
1017     check_malloc_return(my_rsa_method);
1018     RSA_meth_set_pub_enc(my_rsa_method, rsa_pub_enc);
1019     RSA_meth_set_pub_dec(my_rsa_method, rsa_pub_dec);
1020     RSA_meth_set_priv_enc(my_rsa_method, rsa_priv_enc);
1021     RSA_meth_set_priv_dec(my_rsa_method, rsa_priv_dec);
1022     RSA_meth_set_init(my_rsa_method, NULL);
1023     RSA_meth_set_finish(my_rsa_method, finish);
1024     RSA_meth_set0_app_data(my_rsa_method, cd);
1025 
1026     /*
1027      * For CNG, set the RSA_sign method which gets priority over priv_enc().
1028      * This method is called with the raw hash without the digestinfo
1029      * header and works better when using NCryptSignHash() with some tokens.
1030      * However, if PSS padding is in use, openssl does not call this
1031      * function but adds the padding and then calls rsa_priv_enc()
1032      * with padding set to NONE which is not supported by CNG.
1033      * So, when posisble (OpenSSL 1.1.0 and up), we hook on to the sign
1034      * operation in EVP_PKEY_METHOD struct.
1035      */
1036     if (cd->key_spec == CERT_NCRYPT_KEY_SPEC)
1037     {
1038 #if (OPENSSL_VERSION_NUMBER < 0x10100000L)
1039         RSA_meth_set_sign(my_rsa_method, rsa_sign_CNG);
1040 #else
1041         /* pmethod is global -- initialize only if NULL */
1042         if (!pmethod)
1043         {
1044             pmethod = EVP_PKEY_meth_new(EVP_PKEY_RSA, 0);
1045             if (!pmethod)
1046             {
1047                 SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_MALLOC_FAILURE);
1048                 goto err;
1049             }
1050             const EVP_PKEY_METHOD *default_pmethod = EVP_PKEY_meth_find(EVP_PKEY_RSA);
1051             EVP_PKEY_meth_copy(pmethod, default_pmethod);
1052 
1053             /* We want to override only sign_init() and sign() */
1054             EVP_PKEY_meth_set_sign(pmethod, pkey_rsa_sign_init, pkey_rsa_sign);
1055             EVP_PKEY_meth_add0(pmethod);
1056 
1057             /* Keep a copy of the default sign and sign_init methods */
1058 
1059 #if (OPENSSL_VERSION_NUMBER < 0x1010009fL)   /* > version 1.1.0i */
1060             /* The function signature is not const-correct in these versions */
1061             EVP_PKEY_meth_get_sign((EVP_PKEY_METHOD *)default_pmethod, &default_pkey_sign_init,
1062                                    &default_pkey_sign);
1063 #else
1064             EVP_PKEY_meth_get_sign(default_pmethod, &default_pkey_sign_init,
1065                                    &default_pkey_sign);
1066 
1067 #endif
1068         }
1069 #endif /* (OPENSSL_VERSION_NUMBER < 0x10100000L) */
1070     }
1071 
1072     rsa = RSA_new();
1073     if (rsa == NULL)
1074     {
1075         SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_MALLOC_FAILURE);
1076         goto err;
1077     }
1078 
1079     pub_rsa = EVP_PKEY_get0_RSA(pkey);
1080     if (!pub_rsa)
1081     {
1082         goto err;
1083     }
1084 
1085     /* Our private key is external, so we fill in only n and e from the public key */
1086     const BIGNUM *n = NULL;
1087     const BIGNUM *e = NULL;
1088     RSA_get0_key(pub_rsa, &n, &e, NULL);
1089     BIGNUM *rsa_n = BN_dup(n);
1090     BIGNUM *rsa_e = BN_dup(e);
1091     if (!rsa_n || !rsa_e || !RSA_set0_key(rsa, rsa_n, rsa_e, NULL))
1092     {
1093         BN_free(rsa_n); /* ok to free even if NULL */
1094         BN_free(rsa_e);
1095         msg(M_NONFATAL, "ERROR: %s: out of memory", __func__);
1096         goto err;
1097     }
1098     RSA_set_flags(rsa, RSA_flags(rsa) | RSA_FLAG_EXT_PKEY);
1099     if (!RSA_set_method(rsa, my_rsa_method))
1100     {
1101         goto err;
1102     }
1103     rsa_method_set = true; /* flag that method pointer will get freed with the key */
1104     cd->ref_count++;       /* with method, cd gets assigned to the key as well */
1105 
1106     if (!SSL_CTX_use_RSAPrivateKey(ssl_ctx, rsa))
1107     {
1108         goto err;
1109     }
1110     /* SSL_CTX_use_RSAPrivateKey() increased the reference count in 'rsa', so
1111     * we decrease it here with RSA_free(), or it will never be cleaned up. */
1112     RSA_free(rsa);
1113     return 1;
1114 
1115 err:
1116     if (rsa)
1117     {
1118         RSA_free(rsa);
1119     }
1120     if (my_rsa_method && !rsa_method_set)
1121     {
1122         RSA_meth_free(my_rsa_method);
1123     }
1124     return 0;
1125 }
1126 
1127 int
SSL_CTX_use_CryptoAPI_certificate(SSL_CTX * ssl_ctx,const char * cert_prop)1128 SSL_CTX_use_CryptoAPI_certificate(SSL_CTX *ssl_ctx, const char *cert_prop)
1129 {
1130     HCERTSTORE cs;
1131     X509 *cert = NULL;
1132     CAPI_DATA *cd = calloc(1, sizeof(*cd));
1133 
1134     if (cd == NULL)
1135     {
1136         SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_MALLOC_FAILURE);
1137         goto err;
1138     }
1139     /* search CURRENT_USER first, then LOCAL_MACHINE */
1140     cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_CURRENT_USER
1141                        |CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG, L"MY");
1142     if (cs == NULL)
1143     {
1144         CRYPTOAPIerr(CRYPTOAPI_F_CERT_OPEN_SYSTEM_STORE);
1145         goto err;
1146     }
1147     cd->cert_context = find_certificate_in_store(cert_prop, cs);
1148     CertCloseStore(cs, 0);
1149     if (!cd->cert_context)
1150     {
1151         cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE
1152                            |CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG, L"MY");
1153         if (cs == NULL)
1154         {
1155             CRYPTOAPIerr(CRYPTOAPI_F_CERT_OPEN_SYSTEM_STORE);
1156             goto err;
1157         }
1158         cd->cert_context = find_certificate_in_store(cert_prop, cs);
1159         CertCloseStore(cs, 0);
1160         if (cd->cert_context == NULL)
1161         {
1162             CRYPTOAPIerr(CRYPTOAPI_F_CERT_FIND_CERTIFICATE_IN_STORE);
1163             goto err;
1164         }
1165     }
1166 
1167     /* cert_context->pbCertEncoded is the cert X509 DER encoded. */
1168     cert = d2i_X509(NULL, (const unsigned char **) &cd->cert_context->pbCertEncoded,
1169                     cd->cert_context->cbCertEncoded);
1170     if (cert == NULL)
1171     {
1172         SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_ASN1_LIB);
1173         goto err;
1174     }
1175 
1176     /* set up stuff to use the private key */
1177     /* We prefer to get an NCRYPT key handle so that TLS1.2 can be supported */
1178     DWORD flags = CRYPT_ACQUIRE_COMPARE_KEY_FLAG
1179                   | CRYPT_ACQUIRE_PREFER_NCRYPT_KEY_FLAG;
1180     if (!CryptAcquireCertificatePrivateKey(cd->cert_context, flags, NULL,
1181                                            &cd->crypt_prov, &cd->key_spec, &cd->free_crypt_prov))
1182     {
1183         /* if we don't have a smart card reader here, and we try to access a
1184          * smart card certificate, we get:
1185          * "Error 1223: The operation was canceled by the user." */
1186         CRYPTOAPIerr(CRYPTOAPI_F_CRYPT_ACQUIRE_CERTIFICATE_PRIVATE_KEY);
1187         goto err;
1188     }
1189     /* here we don't need to do CryptGetUserKey() or anything; all necessary key
1190      * info is in cd->cert_context, and then, in cd->crypt_prov.  */
1191 
1192     /* if we do not have an NCRYPT key handle restrict TLS to v1.1 or lower */
1193     int max_version = SSL_CTX_get_max_proto_version(ssl_ctx);
1194     if ((!max_version || max_version > TLS1_1_VERSION)
1195         && cd->key_spec != CERT_NCRYPT_KEY_SPEC)
1196     {
1197         msg(M_WARN, "WARNING: cryptoapicert: private key is in a legacy store."
1198             " Restricting TLS version to 1.1");
1199         if (SSL_CTX_get_min_proto_version(ssl_ctx) > TLS1_1_VERSION)
1200         {
1201             msg(M_NONFATAL,
1202                 "ERROR: cryptoapicert: min TLS version larger than 1.1."
1203                 " Try config option --tls-version-min 1.1");
1204             goto err;
1205         }
1206         if (!SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_1_VERSION))
1207         {
1208             msg(M_NONFATAL, "ERROR: cryptoapicert: set max TLS version failed");
1209             goto err;
1210         }
1211     }
1212 
1213     /* Public key in cert is NULL until we call SSL_CTX_use_certificate(),
1214      * so we do it here then...  */
1215     if (!SSL_CTX_use_certificate(ssl_ctx, cert))
1216     {
1217         goto err;
1218     }
1219 
1220     /* the public key */
1221     EVP_PKEY *pkey = X509_get0_pubkey(cert);
1222 
1223     /* SSL_CTX_use_certificate() increased the reference count in 'cert', so
1224      * we decrease it here with X509_free(), or it will never be cleaned up. */
1225     X509_free(cert);
1226     cert = NULL;
1227 
1228     if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA)
1229     {
1230         if (!ssl_ctx_set_rsakey(ssl_ctx, cd, pkey))
1231         {
1232             goto err;
1233         }
1234     }
1235 #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(OPENSSL_NO_EC)
1236     else if (EVP_PKEY_id(pkey) == EVP_PKEY_EC)
1237     {
1238         if (!ssl_ctx_set_eckey(ssl_ctx, cd, pkey))
1239         {
1240             goto err;
1241         }
1242     }
1243 #endif /* OPENSSL_VERSION_NUMBER >= 1.1.0 */
1244     else
1245     {
1246         msg(M_WARN, "WARNING: cryptoapicert: certificate type not supported");
1247         goto err;
1248     }
1249     CAPI_DATA_free(cd); /* this will do a ref_count-- */
1250     return 1;
1251 
1252 err:
1253     CAPI_DATA_free(cd);
1254     return 0;
1255 }
1256 #endif                          /* _WIN32 */
1257