OpenVPN
cryptoapi.c
Go to the documentation of this file.
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 #include "xkey_common.h"
56 
57 #ifndef HAVE_XKEY_PROVIDER
58 /* index for storing external data in EC_KEY: < 0 means uninitialized */
59 static int ec_data_idx = -1;
60 
61 /* Global EVP_PKEY_METHOD used to override the sign operation */
62 static EVP_PKEY_METHOD *pmethod;
63 static int (*default_pkey_sign_init) (EVP_PKEY_CTX *ctx);
64 static int (*default_pkey_sign) (EVP_PKEY_CTX *ctx, unsigned char *sig,
65  size_t *siglen, const unsigned char *tbs, size_t tbslen);
66 #else /* ifndef HAVE_XKEY_PROVIDER */
67 static XKEY_EXTERNAL_SIGN_fn xkey_cng_sign;
68 #endif /* HAVE_XKEY_PROVIDER */
69 
70 typedef struct _CAPI_DATA {
71  const CERT_CONTEXT *cert_context;
72  HCRYPTPROV_OR_NCRYPT_KEY_HANDLE crypt_prov;
73  EVP_PKEY *pubkey;
74  DWORD key_spec;
76  int ref_count;
77 } CAPI_DATA;
78 
79 /*
80  * Translate OpenSSL hash OID to CNG algorithm name. Returns
81  * "UNKNOWN" for unsupported algorithms and NULL for MD5+SHA1
82  * mixed hash used in TLS 1.1 and earlier.
83  */
84 static const wchar_t *
85 cng_hash_algo(int md_type)
86 {
87  const wchar_t *alg = L"UNKNOWN";
88  switch (md_type)
89  {
90  case NID_md5:
91  alg = BCRYPT_MD5_ALGORITHM;
92  break;
93 
94  case NID_sha1:
95  alg = BCRYPT_SHA1_ALGORITHM;
96  break;
97 
98  case NID_sha256:
99  alg = BCRYPT_SHA256_ALGORITHM;
100  break;
101 
102  case NID_sha384:
103  alg = BCRYPT_SHA384_ALGORITHM;
104  break;
105 
106  case NID_sha512:
107  alg = BCRYPT_SHA512_ALGORITHM;
108  break;
109 
110  case NID_md5_sha1:
111  case 0:
112  alg = NULL;
113  break;
114 
115  default:
116  msg(M_WARN|M_INFO, "cryptoapicert: Unknown hash type NID=0x%x", md_type);
117  break;
118  }
119  return alg;
120 }
121 
122 static void
124 {
125  if (!cd || cd->ref_count-- > 0)
126  {
127  return;
128  }
129  if (cd->free_crypt_prov && cd->crypt_prov)
130  {
131  if (cd->key_spec == CERT_NCRYPT_KEY_SPEC)
132  {
133  NCryptFreeObject(cd->crypt_prov);
134  }
135  else
136  {
137  CryptReleaseContext(cd->crypt_prov, 0);
138  }
139  }
140  if (cd->cert_context)
141  {
142  CertFreeCertificateContext(cd->cert_context);
143  }
144  EVP_PKEY_free(cd->pubkey); /* passing NULL is okay */
145 
146  free(cd);
147 }
148 
149 #ifndef HAVE_XKEY_PROVIDER
150 
151 /* Translate OpenSSL padding type to CNG padding type
152  * Returns 0 for unknown/unsupported padding.
153  */
154 static DWORD
155 cng_padding_type(int padding)
156 {
157  DWORD pad = 0;
158 
159  switch (padding)
160  {
161  case RSA_NO_PADDING:
162  break;
163 
164  case RSA_PKCS1_PADDING:
165  pad = BCRYPT_PAD_PKCS1;
166  break;
167 
168  case RSA_PKCS1_PSS_PADDING:
169  pad = BCRYPT_PAD_PSS;
170  break;
171 
172  default:
173  msg(M_WARN|M_INFO, "cryptoapicert: unknown OpenSSL padding type %d.",
174  padding);
175  }
176 
177  return pad;
178 }
179 
192 static int
193 priv_enc_CNG(const CAPI_DATA *cd, const wchar_t *hash_algo, const unsigned char *from,
194  int flen, unsigned char *to, int tlen, DWORD padding, DWORD saltlen)
195 {
196  NCRYPT_KEY_HANDLE hkey = cd->crypt_prov;
197  DWORD len = 0;
198  ASSERT(cd->key_spec == CERT_NCRYPT_KEY_SPEC);
199 
200  DWORD status;
201 
202  msg(D_LOW, "Signing hash using CNG: data size = %d padding = %lu", flen, padding);
203 
204  if (padding == BCRYPT_PAD_PKCS1)
205  {
206  BCRYPT_PKCS1_PADDING_INFO padinfo = {hash_algo};
207  status = NCryptSignHash(hkey, &padinfo, (BYTE *)from, flen,
208  to, tlen, &len, padding);
209  }
210  else if (padding == BCRYPT_PAD_PSS)
211  {
212  BCRYPT_PSS_PADDING_INFO padinfo = {hash_algo, saltlen};
213  status = NCryptSignHash(hkey, &padinfo, (BYTE *)from, flen,
214  to, tlen, &len, padding);
215  }
216  else
217  {
218  msg(M_NONFATAL, "Error in cryptoapicert: Unknown padding type");
219  return 0;
220  }
221 
222  if (status != ERROR_SUCCESS)
223  {
224  SetLastError(status);
225  msg(M_NONFATAL|M_ERRNO, "Error in cryptoapicert: NCryptSignHash failed");
226  len = 0;
227  }
228 
229  /* Unlike CAPI, CNG signature is in big endian order. No reversing needed. */
230  return len;
231 }
232 
233 /* called at RSA_free */
234 static int
235 rsa_finish(RSA *rsa)
236 {
237  const RSA_METHOD *rsa_meth = RSA_get_method(rsa);
238  CAPI_DATA *cd = (CAPI_DATA *) RSA_meth_get0_app_data(rsa_meth);
239 
240  if (cd == NULL)
241  {
242  return 0;
243  }
244  CAPI_DATA_free(cd);
245  RSA_meth_free((RSA_METHOD *) rsa_meth);
246  return 1;
247 }
248 
249 static EC_KEY_METHOD *ec_method = NULL;
250 
252 static void
253 ec_finish(EC_KEY *ec)
254 {
255  EC_KEY_METHOD_free(ec_method);
256  ec_method = NULL;
257  CAPI_DATA *cd = EC_KEY_get_ex_data(ec, ec_data_idx);
258  CAPI_DATA_free(cd);
259  EC_KEY_set_ex_data(ec, ec_data_idx, NULL);
260 }
261 
263 static int
264 ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp)
265 {
266  return 1;
267 }
268 #endif /* HAVE_XKEY_PROVIDER */
269 
276 static ECDSA_SIG *
277 ecdsa_bin2sig(unsigned char *buf, int len)
278 {
279  ECDSA_SIG *ecsig = NULL;
280  DWORD rlen = len/2;
281  BIGNUM *r = BN_bin2bn(buf, rlen, NULL);
282  BIGNUM *s = BN_bin2bn(buf+rlen, rlen, NULL);
283  if (!r || !s)
284  {
285  goto err;
286  }
287  ecsig = ECDSA_SIG_new(); /* in openssl 1.1 this does not allocate r, s */
288  if (!ecsig)
289  {
290  goto err;
291  }
292  if (!ECDSA_SIG_set0(ecsig, r, s)) /* ecsig takes ownership of r and s */
293  {
294  ECDSA_SIG_free(ecsig);
295  goto err;
296  }
297  return ecsig;
298 err:
299  BN_free(r); /* it is ok to free NULL BN */
300  BN_free(s);
301  return NULL;
302 }
303 
304 #ifndef HAVE_XKEY_PROVIDER
305 
307 static ECDSA_SIG *
308 ecdsa_sign_sig(const unsigned char *dgst, int dgstlen,
309  const BIGNUM *in_kinv, const BIGNUM *in_r, EC_KEY *ec)
310 {
311  ECDSA_SIG *ecsig = NULL;
312  CAPI_DATA *cd = (CAPI_DATA *)EC_KEY_get_ex_data(ec, ec_data_idx);
313 
314  ASSERT(cd->key_spec == CERT_NCRYPT_KEY_SPEC);
315 
316  NCRYPT_KEY_HANDLE hkey = cd->crypt_prov;
317  BYTE buf[512]; /* large enough buffer for signature to avoid malloc */
318  DWORD len = _countof(buf);
319 
320  msg(D_LOW, "Cryptoapi: signing hash using EC key: data size = %d", dgstlen);
321 
322  DWORD status = NCryptSignHash(hkey, NULL, (BYTE *)dgst, dgstlen, (BYTE *)buf, len, &len, 0);
323  if (status != ERROR_SUCCESS)
324  {
325  SetLastError(status);
326  msg(M_NONFATAL|M_ERRNO, "Error in cryptoapticert: NCryptSignHash failed");
327  }
328  else
329  {
330  /* NCryptSignHash returns r, s concatenated in buf[] */
331  ecsig = ecdsa_bin2sig(buf, len);
332  }
333  return ecsig;
334 }
335 
337 static int
338 ecdsa_sign(int type, const unsigned char *dgst, int dgstlen, unsigned char *sig,
339  unsigned int *siglen, const BIGNUM *kinv, const BIGNUM *r, EC_KEY *ec)
340 {
341  ECDSA_SIG *s;
342 
343  *siglen = 0;
344  s = ecdsa_sign_sig(dgst, dgstlen, NULL, NULL, ec);
345  if (s == NULL)
346  {
347  return 0;
348  }
349 
350  /* convert internal signature structure 's' to DER encoded byte array in sig */
351  int len = i2d_ECDSA_SIG(s, NULL);
352  if (len > ECDSA_size(ec))
353  {
354  ECDSA_SIG_free(s);
355  msg(M_NONFATAL, "Error in cryptoapicert: DER encoded ECDSA signature is too long (%d bytes)", len);
356  return 0;
357  }
358  *siglen = i2d_ECDSA_SIG(s, &sig);
359  ECDSA_SIG_free(s);
360 
361  return 1;
362 }
363 
364 static int
365 ssl_ctx_set_eckey(SSL_CTX *ssl_ctx, CAPI_DATA *cd, EVP_PKEY *pkey)
366 {
367  EC_KEY *ec = NULL;
368  EVP_PKEY *privkey = NULL;
369 
370  /* create a method struct with default callbacks filled in */
371  ec_method = EC_KEY_METHOD_new(EC_KEY_OpenSSL());
372  if (!ec_method)
373  {
374  goto err;
375  }
376 
377  /* We only need to set finish among init methods, and sign methods */
378  EC_KEY_METHOD_set_init(ec_method, NULL, ec_finish, NULL, NULL, NULL, NULL);
379  EC_KEY_METHOD_set_sign(ec_method, ecdsa_sign, ecdsa_sign_setup, ecdsa_sign_sig);
380 
381  ec = EC_KEY_dup(EVP_PKEY_get0_EC_KEY(pkey));
382  if (!ec)
383  {
384  goto err;
385  }
386  if (!EC_KEY_set_method(ec, ec_method))
387  {
388  goto err;
389  }
390 
391  /* get an index to store cd as external data */
392  if (ec_data_idx < 0)
393  {
394  ec_data_idx = EC_KEY_get_ex_new_index(0, "cryptapicert ec key", NULL, NULL, NULL);
395  if (ec_data_idx < 0)
396  {
397  goto err;
398  }
399  }
400  EC_KEY_set_ex_data(ec, ec_data_idx, cd);
401 
402  /* cd assigned to ec as ex_data, increase its refcount */
403  cd->ref_count++;
404 
405  privkey = EVP_PKEY_new();
406  if (!EVP_PKEY_assign_EC_KEY(privkey, ec))
407  {
408  EC_KEY_free(ec);
409  goto err;
410  }
411  /* from here on ec will get freed with privkey */
412 
413  if (!SSL_CTX_use_PrivateKey(ssl_ctx, privkey))
414  {
415  goto err;
416  }
417  EVP_PKEY_free(privkey); /* this will dn_ref or free ec as well */
418  return 1;
419 
420 err:
421  if (privkey)
422  {
423  EVP_PKEY_free(privkey);
424  }
425  else if (ec)
426  {
427  EC_KEY_free(ec);
428  }
429  if (ec_method) /* do always set ec_method = NULL after freeing it */
430  {
431  EC_KEY_METHOD_free(ec_method);
432  ec_method = NULL;
433  }
434  return 0;
435 }
436 
437 #endif /* !HAVE_XKEY_PROVIDER */
438 
439 static const CERT_CONTEXT *
440 find_certificate_in_store(const char *cert_prop, HCERTSTORE cert_store)
441 {
442  /* Find, and use, the desired certificate from the store. The
443  * 'cert_prop' certificate search string can look like this:
444  * SUBJ:<certificate substring to match>
445  * THUMB:<certificate thumbprint hex value>, e.g.
446  * THUMB:f6 49 24 41 01 b4 fb 44 0c ce f4 36 ae d0 c4 c9 df 7a b6 28
447  * The first matching certificate that has not expired is returned.
448  */
449  const CERT_CONTEXT *rv = NULL;
450  DWORD find_type;
451  const void *find_param;
452  unsigned char hash[255];
453  CRYPT_HASH_BLOB blob = {.cbData = 0, .pbData = hash};
454  struct gc_arena gc = gc_new();
455 
456  if (!strncmp(cert_prop, "SUBJ:", 5))
457  {
458  /* skip the tag */
459  find_param = wide_string(cert_prop + 5, &gc);
460  find_type = CERT_FIND_SUBJECT_STR_W;
461  }
462  else if (!strncmp(cert_prop, "THUMB:", 6))
463  {
464  const char *p;
465  int i, x = 0;
466  find_type = CERT_FIND_HASH;
467  find_param = &blob;
468 
469  /* skip the tag */
470  cert_prop += 6;
471  for (p = cert_prop, i = 0; *p && i < sizeof(hash); i++)
472  {
473  if (*p >= '0' && *p <= '9')
474  {
475  x = (*p - '0') << 4;
476  }
477  else if (*p >= 'A' && *p <= 'F')
478  {
479  x = (*p - 'A' + 10) << 4;
480  }
481  else if (*p >= 'a' && *p <= 'f')
482  {
483  x = (*p - 'a' + 10) << 4;
484  }
485  if (!*++p) /* unexpected end of string */
486  {
487  msg(M_WARN|M_INFO, "WARNING: cryptoapicert: error parsing <THUMB:%s>.", cert_prop);
488  goto out;
489  }
490  if (*p >= '0' && *p <= '9')
491  {
492  x += *p - '0';
493  }
494  else if (*p >= 'A' && *p <= 'F')
495  {
496  x += *p - 'A' + 10;
497  }
498  else if (*p >= 'a' && *p <= 'f')
499  {
500  x += *p - 'a' + 10;
501  }
502  hash[i] = x;
503  /* skip any space(s) between hex numbers */
504  for (p++; *p && *p == ' '; p++)
505  {
506  }
507  }
508  blob.cbData = i;
509  }
510  else
511  {
512  msg(M_NONFATAL, "Error in cryptoapicert: unsupported certificate specification <%s>", cert_prop);
513  goto out;
514  }
515 
516  while (true)
517  {
518  int validity = 1;
519  /* this frees previous rv, if not NULL */
520  rv = CertFindCertificateInStore(cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
521  0, find_type, find_param, rv);
522  if (rv)
523  {
524  validity = CertVerifyTimeValidity(NULL, rv->pCertInfo);
525  }
526  if (!rv || validity == 0)
527  {
528  break;
529  }
530  msg(M_WARN|M_INFO, "WARNING: cryptoapicert: ignoring certificate in store %s.",
531  validity < 0 ? "not yet valid" : "that has expired");
532  }
533 
534 out:
535  gc_free(&gc);
536  return rv;
537 }
538 
539 #ifndef HAVE_XKEY_PROVIDER
540 
541 static const CAPI_DATA *
542 retrieve_capi_data(EVP_PKEY *pkey)
543 {
544  const CAPI_DATA *cd = NULL;
545 
546  if (pkey && EVP_PKEY_id(pkey) == EVP_PKEY_RSA)
547  {
548  RSA *rsa = EVP_PKEY_get0_RSA(pkey);
549  if (rsa)
550  {
551  cd = (CAPI_DATA *)RSA_meth_get0_app_data(RSA_get_method(rsa));
552  }
553  }
554  return cd;
555 }
556 
557 static int
558 pkey_rsa_sign_init(EVP_PKEY_CTX *ctx)
559 {
560  msg(D_LOW, "cryptoapicert: enter pkey_rsa_sign_init");
561 
562  EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);
563 
564  if (pkey && retrieve_capi_data(pkey))
565  {
566  return 1; /* Return success */
567  }
568  else if (default_pkey_sign_init) /* Not our key. Call the default method */
569  {
570  return default_pkey_sign_init(ctx);
571  }
572  return 1;
573 }
574 
581 static int
582 pkey_rsa_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
583  const unsigned char *tbs, size_t tbslen)
584 {
585  EVP_PKEY *pkey = NULL;
586  const CAPI_DATA *cd = NULL;
587  EVP_MD *md = NULL;
588  const wchar_t *alg = NULL;
589 
590  int padding = 0;
591  int hashlen = 0;
592  int saltlen = 0;
593 
594  pkey = EVP_PKEY_CTX_get0_pkey(ctx);
595  if (pkey)
596  {
597  cd = retrieve_capi_data(pkey);
598  }
599 
600  /*
601  * We intercept all sign requests, not just the one's for our key.
602  * Check the key and call the saved OpenSSL method for unknown keys.
603  */
604  if (!pkey || !cd)
605  {
606  if (default_pkey_sign)
607  {
608  return default_pkey_sign(ctx, sig, siglen, tbs, tbslen);
609  }
610  else /* This should not happen */
611  {
612  msg(M_FATAL, "Error in cryptoapicert: Unknown key and no default sign operation to fallback on");
613  return -1;
614  }
615  }
616 
617  if (!EVP_PKEY_CTX_get_rsa_padding(ctx, &padding))
618  {
619  padding = RSA_PKCS1_PADDING; /* Default padding for RSA */
620  }
621 
622  if (EVP_PKEY_CTX_get_signature_md(ctx, &md))
623  {
624  hashlen = EVP_MD_size(md);
625  alg = cng_hash_algo(EVP_MD_type(md));
626 
627  /*
628  * alg == NULL indicates legacy MD5+SHA1 hash, else alg should be a valid
629  * digest algorithm.
630  */
631  if (alg && wcscmp(alg, L"UNKNOWN") == 0)
632  {
633  msg(M_NONFATAL, "Error in cryptoapicert: Unknown hash algorithm <%d>", EVP_MD_type(md));
634  return -1;
635  }
636  }
637  else
638  {
639  msg(M_NONFATAL, "Error in cryptoapicert: could not determine the signature digest algorithm");
640  return -1;
641  }
642 
643  if (tbslen != (size_t)hashlen)
644  {
645  msg(M_NONFATAL, "Error in cryptoapicert: data size does not match hash");
646  return -1;
647  }
648 
649  /* If padding is PSS, determine parameters to pass to CNG */
650  if (padding == RSA_PKCS1_PSS_PADDING)
651  {
652  /*
653  * Ensure the digest type for signature and mask generation match.
654  * In CNG there is no option to specify separate hash functions for
655  * the two, but OpenSSL supports it. However, I have not seen the
656  * two being different in practice. Also the recommended practice is
657  * to use the same for both (rfc 8017 sec 8.1).
658  */
659  EVP_MD *mgf1md;
660  if (!EVP_PKEY_CTX_get_rsa_mgf1_md(ctx, &mgf1md)
661  || EVP_MD_type(mgf1md) != EVP_MD_type(md))
662  {
663  msg(M_NONFATAL, "Error in cryptoapicert: Unknown MGF1 digest type or does"
664  " not match the signature digest type.");
665  return -1;
666  }
667 
668  if (!EVP_PKEY_CTX_get_rsa_pss_saltlen(ctx, &saltlen))
669  {
670  msg(M_WARN|M_INFO, "cryptoapicert: unable to get the salt length from context."
671  " Using the default value.");
672  saltlen = -1;
673  }
674 
675  /*
676  * In OpenSSL saltlen = -1 indicates to use the size of the digest as
677  * size of the salt. A value of -2 or -3 indicates maximum salt length
678  * that will fit. See RSA_padding_add_PKCS1_PSS_mgf1() of OpenSSL.
679  */
680  if (saltlen == -1)
681  {
682  saltlen = hashlen;
683  }
684  else if (saltlen < 0)
685  {
686  const RSA *rsa = EVP_PKEY_get0_RSA(pkey);
687  saltlen = RSA_size(rsa) - hashlen - 2; /* max salt length for RSASSA-PSS */
688  if (RSA_bits(rsa) &0x7) /* number of bits in the key not a multiple of 8 */
689  {
690  saltlen--;
691  }
692  }
693 
694  if (saltlen < 0)
695  {
696  msg(M_NONFATAL, "Error in cryptoapicert: invalid salt length (%d). Digest too large for keysize?", saltlen);
697  return -1;
698  }
699  msg(D_LOW, "cryptoapicert: PSS padding using saltlen = %d", saltlen);
700  }
701 
702  msg(D_LOW, "cryptoapicert: calling priv_enc_CNG with alg = %ls", alg);
703  *siglen = priv_enc_CNG(cd, alg, tbs, (int)tbslen, sig, (int)*siglen,
704  cng_padding_type(padding), (DWORD)saltlen);
705 
706  return (*siglen == 0) ? 0 : 1;
707 }
708 
709 static int
710 ssl_ctx_set_rsakey(SSL_CTX *ssl_ctx, CAPI_DATA *cd, EVP_PKEY *pkey)
711 {
712  RSA *rsa = NULL;
713  RSA_METHOD *my_rsa_method = NULL;
714  EVP_PKEY *privkey = NULL;
715  int ret = 0;
716 
717  my_rsa_method = RSA_meth_new("Microsoft Cryptography API RSA Method",
718  RSA_METHOD_FLAG_NO_CHECK);
719  check_malloc_return(my_rsa_method);
720  RSA_meth_set_finish(my_rsa_method, rsa_finish); /* we use this callback to cleanup CAPI_DATA */
721  RSA_meth_set0_app_data(my_rsa_method, cd);
722 
723  /* pmethod is global -- initialize only if NULL */
724  if (!pmethod)
725  {
726  pmethod = EVP_PKEY_meth_new(EVP_PKEY_RSA, 0);
727  if (!pmethod)
728  {
729  msg(M_NONFATAL, "Error in cryptoapicert: failed to create EVP_PKEY_METHOD");
730  return 0;
731  }
732  const EVP_PKEY_METHOD *default_pmethod = EVP_PKEY_meth_find(EVP_PKEY_RSA);
733  EVP_PKEY_meth_copy(pmethod, default_pmethod);
734 
735  /* We want to override only sign_init() and sign() */
736  EVP_PKEY_meth_set_sign(pmethod, pkey_rsa_sign_init, pkey_rsa_sign);
737  EVP_PKEY_meth_add0(pmethod);
738 
739  /* Keep a copy of the default sign and sign_init methods */
740 
741  EVP_PKEY_meth_get_sign(default_pmethod, &default_pkey_sign_init,
743  }
744 
745  rsa = EVP_PKEY_get1_RSA(pkey);
746 
747  RSA_set_flags(rsa, RSA_flags(rsa) | RSA_FLAG_EXT_PKEY);
748  if (!RSA_set_method(rsa, my_rsa_method))
749  {
750  goto cleanup;
751  }
752  my_rsa_method = NULL; /* we do not want to free it in cleanup */
753  cd->ref_count++; /* with method, cd gets assigned to the key as well */
754 
755  privkey = EVP_PKEY_new();
756  if (!EVP_PKEY_assign_RSA(privkey, rsa))
757  {
758  goto cleanup;
759  }
760  rsa = NULL; /* privkey has taken ownership */
761 
762  if (!SSL_CTX_use_PrivateKey(ssl_ctx, privkey))
763  {
764  goto cleanup;
765  }
766  ret = 1;
767 
768 cleanup:
769  if (rsa)
770  {
771  RSA_free(rsa);
772  }
773  if (my_rsa_method)
774  {
775  RSA_meth_free(my_rsa_method);
776  }
777  if (privkey)
778  {
779  EVP_PKEY_free(privkey);
780  }
781 
782  return ret;
783 }
784 
785 #else /* HAVE_XKEY_PROVIDER */
786 
788 static int
789 xkey_cng_ec_sign(CAPI_DATA *cd, unsigned char *sig, size_t *siglen, const unsigned char *tbs,
790  size_t tbslen)
791 {
792  BYTE buf[1024]; /* large enough for EC keys upto 1024 bits */
793  DWORD len = _countof(buf);
794 
795  msg(D_LOW, "Signing using NCryptSignHash with EC key");
796 
797  DWORD status = NCryptSignHash(cd->crypt_prov, NULL, (BYTE *)tbs, tbslen, buf, len, &len, 0);
798 
799  if (status != ERROR_SUCCESS)
800  {
801  SetLastError(status);
802  msg(M_NONFATAL|M_ERRNO, "Error in cryptoapicert: ECDSA signature using CNG failed.");
803  return 0;
804  }
805 
806  /* NCryptSignHash returns r|s -- convert to OpenSSL's ECDSA_SIG */
807  ECDSA_SIG *ecsig = ecdsa_bin2sig(buf, len);
808  if (!ecsig)
809  {
810  msg(M_NONFATAL, "Error in cryptopicert: Failed to convert ECDSA signature");
811  return 0;
812  }
813 
814  /* convert internal signature structure 's' to DER encoded byte array in sig */
815  if (i2d_ECDSA_SIG(ecsig, NULL) > EVP_PKEY_size(cd->pubkey))
816  {
817  ECDSA_SIG_free(ecsig);
818  msg(M_NONFATAL, "Error in cryptoapicert: DER encoded ECDSA signature is too long");
819  return 0;
820  }
821 
822  *siglen = i2d_ECDSA_SIG(ecsig, &sig);
823  ECDSA_SIG_free(ecsig);
824 
825  return (*siglen > 0);
826 }
827 
829 static int
830 xkey_cng_rsa_sign(CAPI_DATA *cd, unsigned char *sig, size_t *siglen, const unsigned char *tbs,
831  size_t tbslen, XKEY_SIGALG sigalg)
832 {
833  dmsg(D_LOW, "In xkey_cng_rsa_sign");
834 
835  ASSERT(cd);
836  ASSERT(sig);
837  ASSERT(tbs);
838 
839  DWORD status = ERROR_SUCCESS;
840  DWORD len = 0;
841 
842  const wchar_t *hashalg = cng_hash_algo(OBJ_sn2nid(sigalg.mdname));
843 
844  if (hashalg && wcscmp(hashalg, L"UNKNOWN") == 0)
845  {
846  msg(M_NONFATAL, "Error in cryptoapicert: Unknown hash name <%s>", sigalg.mdname);
847  return 0;
848  }
849 
850  if (!strcmp(sigalg.padmode, "pkcs1"))
851  {
852  msg(D_LOW, "Signing using NCryptSignHash with PKCS1 padding: hashalg <%s>", sigalg.mdname);
853 
854  BCRYPT_PKCS1_PADDING_INFO padinfo = {hashalg};
855  status = NCryptSignHash(cd->crypt_prov, &padinfo, (BYTE *)tbs, (DWORD)tbslen,
856  sig, (DWORD)*siglen, &len, BCRYPT_PAD_PKCS1);
857  }
858  else if (!strcmp(sigalg.padmode, "pss"))
859  {
860  int saltlen = tbslen; /* digest size by default */
861  if (!strcmp(sigalg.saltlen, "max"))
862  {
863  saltlen = xkey_max_saltlen(EVP_PKEY_bits(cd->pubkey), tbslen);
864  if (saltlen < 0)
865  {
866  msg(M_NONFATAL, "Error in cryptoapicert: invalid salt length (%d)", saltlen);
867  return 0;
868  }
869  }
870 
871  msg(D_LOW, "Signing using NCryptSignHash with PSS padding: hashalg <%s>, saltlen <%d>",
872  sigalg.mdname, saltlen);
873 
874  BCRYPT_PSS_PADDING_INFO padinfo = {hashalg, (DWORD) saltlen}; /* cast is safe as saltlen >= 0 */
875  status = NCryptSignHash(cd->crypt_prov, &padinfo, (BYTE *)tbs, (DWORD) tbslen,
876  sig, (DWORD)*siglen, &len, BCRYPT_PAD_PSS);
877  }
878  else
879  {
880  msg(M_NONFATAL, "Error in cryptoapicert: Unsupported padding mode <%s>", sigalg.padmode);
881  return 0;
882  }
883 
884  if (status != ERROR_SUCCESS)
885  {
886  SetLastError(status);
887  msg(M_NONFATAL|M_ERRNO, "Error in cryptoapicert: RSA signature using CNG failed.");
888  return 0;
889  }
890 
891  *siglen = len;
892  return (*siglen > 0);
893 }
894 
896 static int
897 xkey_cng_sign(void *handle, unsigned char *sig, size_t *siglen, const unsigned char *tbs,
898  size_t tbslen, XKEY_SIGALG sigalg)
899 {
900  dmsg(D_LOW, "In xkey_cng_sign");
901 
902  CAPI_DATA *cd = handle;
903  ASSERT(cd);
904  ASSERT(sig);
905  ASSERT(tbs);
906 
907  unsigned char mdbuf[EVP_MAX_MD_SIZE];
908  size_t buflen = _countof(mdbuf);
909 
910  /* compute digest if required */
911  if (!strcmp(sigalg.op, "DigestSign"))
912  {
913  if (!xkey_digest(tbs, tbslen, mdbuf, &buflen, sigalg.mdname))
914  {
915  return 0;
916  }
917  tbs = mdbuf;
918  tbslen = buflen;
919  }
920 
921  if (!strcmp(sigalg.keytype, "EC"))
922  {
923  return xkey_cng_ec_sign(cd, sig, siglen, tbs, tbslen);
924  }
925  else if (!strcmp(sigalg.keytype, "RSA"))
926  {
927  return xkey_cng_rsa_sign(cd, sig, siglen, tbs, tbslen, sigalg);
928  }
929  else
930  {
931  return 0; /* Unknown keytype -- should not happen */
932  }
933 }
934 
935 #endif /* HAVE_XKEY_PROVIDER */
936 
937 int
938 SSL_CTX_use_CryptoAPI_certificate(SSL_CTX *ssl_ctx, const char *cert_prop)
939 {
940  HCERTSTORE cs;
941  X509 *cert = NULL;
942  CAPI_DATA *cd = calloc(1, sizeof(*cd));
943 
944  if (cd == NULL)
945  {
946  msg(M_NONFATAL, "Error in cryptoapicert: out of memory");
947  goto err;
948  }
949  /* search CURRENT_USER first, then LOCAL_MACHINE */
950  cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_CURRENT_USER
951  |CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG, L"MY");
952  if (cs == NULL)
953  {
954  msg(M_NONFATAL|M_ERRNO, "Error in cryptoapicert: failed to open user certficate store");
955  goto err;
956  }
957  cd->cert_context = find_certificate_in_store(cert_prop, cs);
958  CertCloseStore(cs, 0);
959  if (!cd->cert_context)
960  {
961  cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE
962  |CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG, L"MY");
963  if (cs == NULL)
964  {
965  msg(M_NONFATAL|M_ERRNO, "Error in cryptoapicert: failed to open machine certficate store");
966  goto err;
967  }
968  cd->cert_context = find_certificate_in_store(cert_prop, cs);
969  CertCloseStore(cs, 0);
970  if (cd->cert_context == NULL)
971  {
972  msg(M_NONFATAL, "Error in cryptoapicert: certificate matching <%s> not found", cert_prop);
973  goto err;
974  }
975  }
976 
977  /* cert_context->pbCertEncoded is the cert X509 DER encoded. */
978  cert = d2i_X509(NULL, (const unsigned char **) &cd->cert_context->pbCertEncoded,
979  cd->cert_context->cbCertEncoded);
980  if (cert == NULL)
981  {
982  msg(M_NONFATAL, "Error in cryptoapicert: X509 certificate decode failed");
983  goto err;
984  }
985 
986  /* set up stuff to use the private key */
987  /* We support NCRYPT key handles only */
988  DWORD flags = CRYPT_ACQUIRE_COMPARE_KEY_FLAG
989  | CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG;
990  if (!CryptAcquireCertificatePrivateKey(cd->cert_context, flags, NULL,
991  &cd->crypt_prov, &cd->key_spec, &cd->free_crypt_prov))
992  {
993  /* private key may be in a token not available, or incompatible with CNG */
994  msg(M_NONFATAL|M_ERRNO, "Error in cryptoapicert: failed to acquire key. Key not present or "
995  "is in a legacy token not supported by Windows CNG API");
996  goto err;
997  }
998 
999  /* Public key in cert is NULL until we call SSL_CTX_use_certificate(),
1000  * so we do it here then... */
1001  if (!SSL_CTX_use_certificate(ssl_ctx, cert))
1002  {
1003  goto err;
1004  }
1005 
1006  /* the public key */
1007  EVP_PKEY *pkey = X509_get_pubkey(cert);
1008  cd->pubkey = pkey; /* will be freed with cd */
1009 
1010  /* SSL_CTX_use_certificate() increased the reference count in 'cert', so
1011  * we decrease it here with X509_free(), or it will never be cleaned up. */
1012  X509_free(cert);
1013  cert = NULL;
1014 
1015 #ifdef HAVE_XKEY_PROVIDER
1016 
1017  EVP_PKEY *privkey = xkey_load_generic_key(tls_libctx, cd, pkey,
1018  xkey_cng_sign, (XKEY_PRIVKEY_FREE_fn *) CAPI_DATA_free);
1019  SSL_CTX_use_PrivateKey(ssl_ctx, privkey);
1020  return 1; /* do not free cd -- its kept by xkey provider */
1021 
1022 #else /* ifdef HAVE_XKEY_PROVIDER */
1023 
1024  if (EVP_PKEY_id(pkey) == EVP_PKEY_RSA)
1025  {
1026  if (!ssl_ctx_set_rsakey(ssl_ctx, cd, pkey))
1027  {
1028  goto err;
1029  }
1030  }
1031  else if (EVP_PKEY_id(pkey) == EVP_PKEY_EC)
1032  {
1033  if (!ssl_ctx_set_eckey(ssl_ctx, cd, pkey))
1034  {
1035  goto err;
1036  }
1037  }
1038  else
1039  {
1040  msg(M_WARN|M_INFO, "WARNING: cryptoapicert: key type <%d> not supported",
1041  EVP_PKEY_id(pkey));
1042  goto err;
1043  }
1044  CAPI_DATA_free(cd); /* this will do a ref_count-- */
1045  return 1;
1046 
1047 #endif /* HAVE_XKEY_PROVIDER */
1048 
1049 err:
1050  CAPI_DATA_free(cd);
1051  return 0;
1052 }
1053 #endif /* _WIN32 */
CAPI_DATA
struct _CAPI_DATA CAPI_DATA
cng_padding_type
static DWORD cng_padding_type(int padding)
Definition: cryptoapi.c:155
M_INFO
#define M_INFO
Definition: errlevel.h:55
EVP_PKEY_get0_RSA
static RSA * EVP_PKEY_get0_RSA(EVP_PKEY *pkey)
Get the RSA object of a public key.
Definition: openssl_compat.h:236
gc_new
static struct gc_arena gc_new(void)
Definition: buffer.h:998
M_ERRNO
#define M_ERRNO
Definition: error.h:100
M_FATAL
#define M_FATAL
Definition: error.h:95
win32.h
M_NONFATAL
#define M_NONFATAL
Definition: error.h:96
ssl_ctx_set_rsakey
static int ssl_ctx_set_rsakey(SSL_CTX *ssl_ctx, CAPI_DATA *cd, EVP_PKEY *pkey)
Definition: cryptoapi.c:710
priv_enc_CNG
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)
Sign the hash in 'from' using NCryptSignHash().
Definition: cryptoapi.c:193
hash
Definition: list.h:58
cng_hash_algo
static const wchar_t * cng_hash_algo(int md_type)
Definition: cryptoapi.c:85
config-msvc.h
_CAPI_DATA::pubkey
EVP_PKEY * pubkey
Definition: cryptoapi.c:73
xkey_common.h
CAPI_DATA_free
static void CAPI_DATA_free(CAPI_DATA *cd)
Definition: cryptoapi.c:123
ec_finish
static void ec_finish(EC_KEY *ec)
EC_KEY_METHOD callback: called when the key is freed.
Definition: cryptoapi.c:253
dmsg
#define dmsg(flags,...)
Definition: error.h:154
D_LOW
#define D_LOW
Definition: errlevel.h:97
RSA_meth_set_finish
static int RSA_meth_set_finish(RSA_METHOD *meth, int(*finish)(RSA *rsa))
Set the finish function of an RSA_METHOD object.
Definition: openssl_compat.h:565
ecdsa_sign
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)
EC_KEY_METHOD callback sign(): sign and return a DER encoded signature.
Definition: cryptoapi.c:338
pmethod
static EVP_PKEY_METHOD * pmethod
Definition: cryptoapi.c:62
RSA_set_flags
static void RSA_set_flags(RSA *rsa, int flags)
Set the RSA flags.
Definition: openssl_compat.h:273
ecdsa_sign_sig
static ECDSA_SIG * ecdsa_sign_sig(const unsigned char *dgst, int dgstlen, const BIGNUM *in_kinv, const BIGNUM *in_r, EC_KEY *ec)
EC_KEY_METHOD callback sign_sig(): sign and return an ECDSA_SIG pointer.
Definition: cryptoapi.c:308
RSA_meth_new
static RSA_METHOD * RSA_meth_new(const char *name, int flags)
Allocate a new RSA method object.
Definition: openssl_compat.h:406
ASSERT
#define ASSERT(x)
Definition: error.h:201
_CAPI_DATA::cert_context
const CERT_CONTEXT * cert_context
Definition: cryptoapi.c:71
_CAPI_DATA::ref_count
int ref_count
Definition: cryptoapi.c:76
find_certificate_in_store
static const CERT_CONTEXT * find_certificate_in_store(const char *cert_prop, HCERTSTORE cert_store)
Definition: cryptoapi.c:440
default_pkey_sign_init
static int(* default_pkey_sign_init)(EVP_PKEY_CTX *ctx)
Definition: cryptoapi.c:63
pkey_rsa_sign_init
static int pkey_rsa_sign_init(EVP_PKEY_CTX *ctx)
Definition: cryptoapi.c:558
M_WARN
#define M_WARN
Definition: error.h:97
wide_string
WCHAR * wide_string(const char *utf8, struct gc_arena *gc)
Definition: win32-util.c:43
check_malloc_return
static void check_malloc_return(const void *p)
Definition: buffer.h:1076
_CAPI_DATA
Definition: cryptoapi.c:70
openssl_compat.h
buffer.h
syshead.h
RSA_meth_get0_app_data
static void * RSA_meth_get0_app_data(const RSA_METHOD *meth)
Get the application data of an RSA_METHOD object.
Definition: openssl_compat.h:600
ec_data_idx
static int ec_data_idx
Definition: cryptoapi.c:59
gc_arena
Garbage collection arena used to keep track of dynamically allocated memory.
Definition: buffer.h:116
ssl_ctx_set_eckey
static int ssl_ctx_set_eckey(SSL_CTX *ssl_ctx, CAPI_DATA *cd, EVP_PKEY *pkey)
Definition: cryptoapi.c:365
ecdsa_bin2sig
static ECDSA_SIG * ecdsa_bin2sig(unsigned char *buf, int len)
Helper to convert ECDSA signature returned by NCryptSignHash to an ECDSA_SIG structure.
Definition: cryptoapi.c:277
_CAPI_DATA::crypt_prov
HCRYPTPROV_OR_NCRYPT_KEY_HANDLE crypt_prov
Definition: cryptoapi.c:72
status
static SERVICE_STATUS status
Definition: interactive.c:56
SSL_CTX_use_CryptoAPI_certificate
int SSL_CTX_use_CryptoAPI_certificate(SSL_CTX *ssl_ctx, const char *cert_prop)
Definition: cryptoapi.c:938
rsa_finish
static int rsa_finish(RSA *rsa)
Definition: cryptoapi.c:235
gc_free
static void gc_free(struct gc_arena *a)
Definition: buffer.h:1006
retrieve_capi_data
static const CAPI_DATA * retrieve_capi_data(EVP_PKEY *pkey)
Definition: cryptoapi.c:542
EVP_PKEY_get0_EC_KEY
static EC_KEY * EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey)
Get the EC_KEY object of a public key.
Definition: openssl_compat.h:248
RSA_meth_set0_app_data
static int RSA_meth_set0_app_data(RSA_METHOD *meth, void *app_data)
Set the application data of an RSA_METHOD object.
Definition: openssl_compat.h:583
config.h
RSA_meth_free
static void RSA_meth_free(RSA_METHOD *meth)
Free an existing RSA_METHOD object.
Definition: openssl_compat.h:421
RSA_bits
static int RSA_bits(const RSA *rsa)
Number of significant RSA bits.
Definition: openssl_compat.h:351
_CAPI_DATA::key_spec
DWORD key_spec
Definition: cryptoapi.c:74
tls_libctx
OSSL_LIB_CTX * tls_libctx
Definition: ssl_openssl.c:73
ec_method
static EC_KEY_METHOD * ec_method
Definition: cryptoapi.c:249
pkey_rsa_sign
static int pkey_rsa_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, const unsigned char *tbs, size_t tbslen)
Implementation of EVP_PKEY_sign() using CNG: sign the digest in |tbs| and save the the signature in |...
Definition: cryptoapi.c:582
_CAPI_DATA::free_crypt_prov
BOOL free_crypt_prov
Definition: cryptoapi.c:75
ecdsa_sign_setup
static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp)
EC_KEY_METHOD callback sign_setup(): we do nothing here.
Definition: cryptoapi.c:264
msg
#define msg(flags,...)
Definition: error.h:150
default_pkey_sign
static int(* default_pkey_sign)(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, const unsigned char *tbs, size_t tbslen)
Definition: cryptoapi.c:64