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)
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, *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)
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
1257 #else /* ifdef ENABLE_CRYPTOAPI */
1258 #ifdef _MSC_VER /* Dummy function needed to avoid empty file compiler warning in Microsoft VC */
1259 static void
dummy(void)1260 dummy(void)
1261 {
1262 }
1263 #endif
1264 #endif /* _WIN32 */
1265