OpenVPN
cryptoapi.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2004 Peter 'Luna' Runestig <peter@runestig.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modifi-
6  * cation, are permitted provided that the following conditions are met:
7  *
8  * o Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * o Redistributions in binary form must reproduce the above copyright no-
12  * tice, this list of conditions and the following disclaimer in the do-
13  * cumentation and/or other materials provided with the distribution.
14  *
15  * o The names of the contributors may not be used to endorse or promote
16  * products derived from this software without specific prior written
17  * permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LI-
23  * ABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUEN-
24  * TIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEV-
26  * ER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABI-
27  * LITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
28  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #elif defined(_MSC_VER)
34 #include "config-msvc.h"
35 #endif
36 
37 #include "syshead.h"
38 
39 #ifdef ENABLE_CRYPTOAPI
40 
41 #include <openssl/ssl.h>
42 #include <openssl/err.h>
43 #include <windows.h>
44 #include <wincrypt.h>
45 #include <stdio.h>
46 #include <ctype.h>
47 #include <assert.h>
48 
49 #include "buffer.h"
50 
51 /* MinGW w32api 3.17 is still incomplete when it comes to CryptoAPI while
52  * MinGW32-w64 defines all macros used. This is a hack around that problem.
53  */
54 #ifndef CERT_SYSTEM_STORE_LOCATION_SHIFT
55 #define CERT_SYSTEM_STORE_LOCATION_SHIFT 16
56 #endif
57 #ifndef CERT_SYSTEM_STORE_CURRENT_USER_ID
58 #define CERT_SYSTEM_STORE_CURRENT_USER_ID 1
59 #endif
60 #ifndef CERT_SYSTEM_STORE_CURRENT_USER
61 #define CERT_SYSTEM_STORE_CURRENT_USER (CERT_SYSTEM_STORE_CURRENT_USER_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT)
62 #endif
63 #ifndef CERT_STORE_READONLY_FLAG
64 #define CERT_STORE_READONLY_FLAG 0x00008000
65 #endif
66 #ifndef CERT_STORE_OPEN_EXISTING_FLAG
67 #define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000
68 #endif
69 
70 /* Size of an SSL signature: MD5+SHA1 */
71 #define SSL_SIG_LENGTH 36
72 
73 /* try to funnel any Windows/CryptoAPI error messages to OpenSSL ERR_... */
74 #define ERR_LIB_CRYPTOAPI (ERR_LIB_USER + 69) /* 69 is just a number... */
75 #define CRYPTOAPIerr(f) err_put_ms_error(GetLastError(), (f), __FILE__, __LINE__)
76 #define CRYPTOAPI_F_CERT_OPEN_SYSTEM_STORE 100
77 #define CRYPTOAPI_F_CERT_FIND_CERTIFICATE_IN_STORE 101
78 #define CRYPTOAPI_F_CRYPT_ACQUIRE_CERTIFICATE_PRIVATE_KEY 102
79 #define CRYPTOAPI_F_CRYPT_CREATE_HASH 103
80 #define CRYPTOAPI_F_CRYPT_GET_HASH_PARAM 104
81 #define CRYPTOAPI_F_CRYPT_SET_HASH_PARAM 105
82 #define CRYPTOAPI_F_CRYPT_SIGN_HASH 106
83 #define CRYPTOAPI_F_LOAD_LIBRARY 107
84 #define CRYPTOAPI_F_GET_PROC_ADDRESS 108
85 
86 static ERR_STRING_DATA CRYPTOAPI_str_functs[] = {
87  { ERR_PACK(ERR_LIB_CRYPTOAPI, 0, 0), "microsoft cryptoapi"},
88  { ERR_PACK(0, CRYPTOAPI_F_CERT_OPEN_SYSTEM_STORE, 0), "CertOpenSystemStore" },
89  { ERR_PACK(0, CRYPTOAPI_F_CERT_FIND_CERTIFICATE_IN_STORE, 0), "CertFindCertificateInStore" },
90  { ERR_PACK(0, CRYPTOAPI_F_CRYPT_ACQUIRE_CERTIFICATE_PRIVATE_KEY, 0), "CryptAcquireCertificatePrivateKey" },
91  { ERR_PACK(0, CRYPTOAPI_F_CRYPT_CREATE_HASH, 0), "CryptCreateHash" },
92  { ERR_PACK(0, CRYPTOAPI_F_CRYPT_GET_HASH_PARAM, 0), "CryptGetHashParam" },
93  { ERR_PACK(0, CRYPTOAPI_F_CRYPT_SET_HASH_PARAM, 0), "CryptSetHashParam" },
94  { ERR_PACK(0, CRYPTOAPI_F_CRYPT_SIGN_HASH, 0), "CryptSignHash" },
95  { ERR_PACK(0, CRYPTOAPI_F_LOAD_LIBRARY, 0), "LoadLibrary" },
96  { ERR_PACK(0, CRYPTOAPI_F_GET_PROC_ADDRESS, 0), "GetProcAddress" },
97  { 0, NULL }
98 };
99 
100 typedef struct _CAPI_DATA {
101  const CERT_CONTEXT *cert_context;
102  HCRYPTPROV crypt_prov;
103  DWORD key_spec;
105 } CAPI_DATA;
106 
107 static char *
108 ms_error_text(DWORD ms_err)
109 {
110  LPVOID lpMsgBuf = NULL;
111  char *rv = NULL;
112 
113  FormatMessage(
114  FORMAT_MESSAGE_ALLOCATE_BUFFER
115  |FORMAT_MESSAGE_FROM_SYSTEM
116  |FORMAT_MESSAGE_IGNORE_INSERTS,
117  NULL, ms_err,
118  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
119  (LPTSTR) &lpMsgBuf, 0, NULL);
120  if (lpMsgBuf)
121  {
122  char *p;
123  rv = string_alloc(lpMsgBuf, NULL);
124  LocalFree(lpMsgBuf);
125  /* trim to the left */
126  if (rv)
127  {
128  for (p = rv + strlen(rv) - 1; p >= rv; p--) {
129  if (isspace(*p))
130  {
131  *p = '\0';
132  }
133  else
134  {
135  break;
136  }
137  }
138  }
139  }
140  return rv;
141 }
142 
143 static void
144 err_put_ms_error(DWORD ms_err, int func, const char *file, int line)
145 {
146  static int init = 0;
147 #define ERR_MAP_SZ 16
148  static struct {
149  int err;
150  DWORD ms_err; /* I don't think we get more than 16 *different* errors */
151  } err_map[ERR_MAP_SZ]; /* in here, before we give up the whole thing... */
152  int i;
153 
154  if (ms_err == 0)
155  {
156  /* 0 is not an error */
157  return;
158  }
159  if (!init)
160  {
161  ERR_load_strings(ERR_LIB_CRYPTOAPI, CRYPTOAPI_str_functs);
162  memset(&err_map, 0, sizeof(err_map));
163  init++;
164  }
165  /* since MS error codes are 32 bit, and the ones in the ERR_... system is
166  * only 12, we must have a mapping table between them. */
167  for (i = 0; i < ERR_MAP_SZ; i++) {
168  if (err_map[i].ms_err == ms_err)
169  {
170  ERR_PUT_error(ERR_LIB_CRYPTOAPI, func, err_map[i].err, file, line);
171  break;
172  }
173  else if (err_map[i].ms_err == 0)
174  {
175  /* end of table, add new entry */
176  ERR_STRING_DATA *esd = calloc(2, sizeof(*esd));
177  if (esd == NULL)
178  {
179  break;
180  }
181  err_map[i].ms_err = ms_err;
182  err_map[i].err = esd->error = i + 100;
183  esd->string = ms_error_text(ms_err);
184  check_malloc_return(esd->string);
185  ERR_load_strings(ERR_LIB_CRYPTOAPI, esd);
186  ERR_PUT_error(ERR_LIB_CRYPTOAPI, func, err_map[i].err, file, line);
187  break;
188  }
189  }
190 }
191 
192 /* encrypt */
193 static int
194 rsa_pub_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
195 {
196  /* I haven't been able to trigger this one, but I want to know if it happens... */
197  assert(0);
198 
199  return 0;
200 }
201 
202 /* verify arbitrary data */
203 static int
204 rsa_pub_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
205 {
206  /* I haven't been able to trigger this one, but I want to know if it happens... */
207  assert(0);
208 
209  return 0;
210 }
211 
212 /* sign arbitrary data */
213 static int
214 rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
215 {
216  CAPI_DATA *cd = (CAPI_DATA *) rsa->meth->app_data;
217  HCRYPTHASH hash;
218  DWORD hash_size, len, i;
219  unsigned char *buf;
220 
221  if (cd == NULL)
222  {
223  RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_PASSED_NULL_PARAMETER);
224  return 0;
225  }
226  if (padding != RSA_PKCS1_PADDING)
227  {
228  /* AFAICS, CryptSignHash() *always* uses PKCS1 padding. */
229  RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE);
230  return 0;
231  }
232  /* Unfortunately, there is no "CryptSign()" function in CryptoAPI, that would
233  * be way to straightforward for M$, I guess... So we have to do it this
234  * tricky way instead, by creating a "Hash", and load the already-made hash
235  * from 'from' into it. */
236  /* For now, we only support NID_md5_sha1 */
237  if (flen != SSL_SIG_LENGTH)
238  {
239  RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, RSA_R_INVALID_MESSAGE_LENGTH);
240  return 0;
241  }
242  if (!CryptCreateHash(cd->crypt_prov, CALG_SSL3_SHAMD5, 0, 0, &hash))
243  {
245  return 0;
246  }
247  len = sizeof(hash_size);
248  if (!CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *) &hash_size, &len, 0))
249  {
251  CryptDestroyHash(hash);
252  return 0;
253  }
254  if ((int) hash_size != flen)
255  {
256  RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, RSA_R_INVALID_MESSAGE_LENGTH);
257  CryptDestroyHash(hash);
258  return 0;
259  }
260  if (!CryptSetHashParam(hash, HP_HASHVAL, (BYTE * ) from, 0))
261  {
263  CryptDestroyHash(hash);
264  return 0;
265  }
266 
267  len = RSA_size(rsa);
268  buf = malloc(len);
269  if (buf == NULL)
270  {
271  RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_MALLOC_FAILURE);
272  CryptDestroyHash(hash);
273  return 0;
274  }
275  if (!CryptSignHash(hash, cd->key_spec, NULL, 0, buf, &len))
276  {
278  CryptDestroyHash(hash);
279  free(buf);
280  return 0;
281  }
282  /* and now, we have to reverse the byte-order in the result from CryptSignHash()... */
283  for (i = 0; i < len; i++)
284  {
285  to[i] = buf[len - i - 1];
286  }
287  free(buf);
288 
289  CryptDestroyHash(hash);
290  return len;
291 }
292 
293 /* decrypt */
294 static int
295 rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
296 {
297  /* I haven't been able to trigger this one, but I want to know if it happens... */
298  assert(0);
299 
300  return 0;
301 }
302 
303 /* called at RSA_new */
304 static int
305 init(RSA *rsa)
306 {
307 
308  return 0;
309 }
310 
311 /* called at RSA_free */
312 static int
313 finish(RSA *rsa)
314 {
315  CAPI_DATA *cd = (CAPI_DATA *) rsa->meth->app_data;
316 
317  if (cd == NULL)
318  {
319  return 0;
320  }
321  if (cd->crypt_prov && cd->free_crypt_prov)
322  {
323  CryptReleaseContext(cd->crypt_prov, 0);
324  }
325  if (cd->cert_context)
326  {
327  CertFreeCertificateContext(cd->cert_context);
328  }
329  free(rsa->meth->app_data);
330  free((char *) rsa->meth);
331  rsa->meth = NULL;
332  return 1;
333 }
334 
335 static const CERT_CONTEXT *
336 find_certificate_in_store(const char *cert_prop, HCERTSTORE cert_store)
337 {
338  /* Find, and use, the desired certificate from the store. The
339  * 'cert_prop' certificate search string can look like this:
340  * SUBJ:<certificate substring to match>
341  * THUMB:<certificate thumbprint hex value>, e.g.
342  * THUMB:f6 49 24 41 01 b4 fb 44 0c ce f4 36 ae d0 c4 c9 df 7a b6 28
343  */
344  const CERT_CONTEXT *rv = NULL;
345 
346  if (!strncmp(cert_prop, "SUBJ:", 5))
347  {
348  /* skip the tag */
349  cert_prop += 5;
350  rv = CertFindCertificateInStore(cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
351  0, CERT_FIND_SUBJECT_STR_A, cert_prop, NULL);
352 
353  }
354  else if (!strncmp(cert_prop, "THUMB:", 6))
355  {
356  unsigned char hash[255];
357  char *p;
358  int i, x = 0;
359  CRYPT_HASH_BLOB blob;
360 
361  /* skip the tag */
362  cert_prop += 6;
363  for (p = (char *) cert_prop, i = 0; *p && i < sizeof(hash); i++) {
364  if (*p >= '0' && *p <= '9')
365  {
366  x = (*p - '0') << 4;
367  }
368  else if (*p >= 'A' && *p <= 'F')
369  {
370  x = (*p - 'A' + 10) << 4;
371  }
372  else if (*p >= 'a' && *p <= 'f')
373  {
374  x = (*p - 'a' + 10) << 4;
375  }
376  if (!*++p) /* unexpected end of string */
377  {
378  break;
379  }
380  if (*p >= '0' && *p <= '9')
381  {
382  x += *p - '0';
383  }
384  else if (*p >= 'A' && *p <= 'F')
385  {
386  x += *p - 'A' + 10;
387  }
388  else if (*p >= 'a' && *p <= 'f')
389  {
390  x += *p - 'a' + 10;
391  }
392  hash[i] = x;
393  /* skip any space(s) between hex numbers */
394  for (p++; *p && *p == ' '; p++)
395  {
396  }
397  }
398  blob.cbData = i;
399  blob.pbData = (unsigned char *) &hash;
400  rv = CertFindCertificateInStore(cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
401  0, CERT_FIND_HASH, &blob, NULL);
402 
403  }
404 
405  return rv;
406 }
407 
408 int
409 SSL_CTX_use_CryptoAPI_certificate(SSL_CTX *ssl_ctx, const char *cert_prop)
410 {
411  HCERTSTORE cs;
412  X509 *cert = NULL;
413  RSA *rsa = NULL, *pub_rsa;
414  CAPI_DATA *cd = calloc(1, sizeof(*cd));
415  RSA_METHOD *my_rsa_method = calloc(1, sizeof(*my_rsa_method));
416 
417  if (cd == NULL || my_rsa_method == NULL)
418  {
419  SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_MALLOC_FAILURE);
420  goto err;
421  }
422  /* search CURRENT_USER first, then LOCAL_MACHINE */
423  cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_CURRENT_USER
425  if (cs == NULL)
426  {
428  goto err;
429  }
430  cd->cert_context = find_certificate_in_store(cert_prop, cs);
431  CertCloseStore(cs, 0);
432  if (!cd->cert_context)
433  {
434  cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE
436  if (cs == NULL)
437  {
439  goto err;
440  }
441  cd->cert_context = find_certificate_in_store(cert_prop, cs);
442  CertCloseStore(cs, 0);
443  if (cd->cert_context == NULL)
444  {
446  goto err;
447  }
448  }
449 
450  /* cert_context->pbCertEncoded is the cert X509 DER encoded. */
451  cert = d2i_X509(NULL, (const unsigned char **) &cd->cert_context->pbCertEncoded,
452  cd->cert_context->cbCertEncoded);
453  if (cert == NULL)
454  {
455  SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_ASN1_LIB);
456  goto err;
457  }
458 
459  /* set up stuff to use the private key */
460  if (!CryptAcquireCertificatePrivateKey(cd->cert_context, CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
461  NULL, &cd->crypt_prov, &cd->key_spec, &cd->free_crypt_prov))
462  {
463  /* if we don't have a smart card reader here, and we try to access a
464  * smart card certificate, we get:
465  * "Error 1223: The operation was canceled by the user." */
467  goto err;
468  }
469  /* here we don't need to do CryptGetUserKey() or anything; all necessary key
470  * info is in cd->cert_context, and then, in cd->crypt_prov. */
471 
472  my_rsa_method->name = "Microsoft CryptoAPI RSA Method";
473  my_rsa_method->rsa_pub_enc = rsa_pub_enc;
474  my_rsa_method->rsa_pub_dec = rsa_pub_dec;
475  my_rsa_method->rsa_priv_enc = rsa_priv_enc;
476  my_rsa_method->rsa_priv_dec = rsa_priv_dec;
477  /* my_rsa_method->init = init; */
478  my_rsa_method->finish = finish;
479  my_rsa_method->flags = RSA_METHOD_FLAG_NO_CHECK;
480  my_rsa_method->app_data = (char *) cd;
481 
482  rsa = RSA_new();
483  if (rsa == NULL)
484  {
485  SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_MALLOC_FAILURE);
486  goto err;
487  }
488 
489  /* cert->cert_info->key->pkey is NULL until we call SSL_CTX_use_certificate(),
490  * so we do it here then... */
491  if (!SSL_CTX_use_certificate(ssl_ctx, cert))
492  {
493  goto err;
494  }
495  /* the public key */
496  pub_rsa = cert->cert_info->key->pkey->pkey.rsa;
497  /* SSL_CTX_use_certificate() increased the reference count in 'cert', so
498  * we decrease it here with X509_free(), or it will never be cleaned up. */
499  X509_free(cert);
500  cert = NULL;
501 
502  /* I'm not sure about what we have to fill in in the RSA, trying out stuff... */
503  /* rsa->n indicates the key size */
504  rsa->n = BN_dup(pub_rsa->n);
505  rsa->flags |= RSA_FLAG_EXT_PKEY;
506  if (!RSA_set_method(rsa, my_rsa_method))
507  {
508  goto err;
509  }
510 
511  if (!SSL_CTX_use_RSAPrivateKey(ssl_ctx, rsa))
512  {
513  goto err;
514  }
515  /* SSL_CTX_use_RSAPrivateKey() increased the reference count in 'rsa', so
516  * we decrease it here with RSA_free(), or it will never be cleaned up. */
517  RSA_free(rsa);
518  return 1;
519 
520 err:
521  if (cert)
522  {
523  X509_free(cert);
524  }
525  if (rsa)
526  {
527  RSA_free(rsa);
528  }
529  else
530  {
531  if (my_rsa_method)
532  {
533  free(my_rsa_method);
534  }
535  if (cd)
536  {
537  if (cd->free_crypt_prov && cd->crypt_prov)
538  {
539  CryptReleaseContext(cd->crypt_prov, 0);
540  }
541  if (cd->cert_context)
542  {
543  CertFreeCertificateContext(cd->cert_context);
544  }
545  free(cd);
546  }
547  }
548  return 0;
549 }
550 
551 #else /* ifdef ENABLE_CRYPTOAPI */
552 #ifdef _MSC_VER /* Dummy function needed to avoid empty file compiler warning in Microsoft VC */
553 static void
554 dummy(void)
555 {
556 }
557 #endif
558 #endif /* _WIN32 */
#define CRYPTOAPI_F_CRYPT_ACQUIRE_CERTIFICATE_PRIVATE_KEY
Definition: cryptoapi.c:78
static ERR_STRING_DATA CRYPTOAPI_str_functs[]
Definition: cryptoapi.c:86
#define CRYPTOAPI_F_CRYPT_SET_HASH_PARAM
Definition: cryptoapi.c:81
static const CERT_CONTEXT * find_certificate_in_store(const char *cert_prop, HCERTSTORE cert_store)
Definition: cryptoapi.c:336
char * string_alloc(const char *str, struct gc_arena *gc)
Definition: buffer.c:626
#define CRYPTOAPI_F_CERT_FIND_CERTIFICATE_IN_STORE
Definition: cryptoapi.c:77
#define CRYPTOAPIerr(f)
Definition: cryptoapi.c:75
struct _CAPI_DATA CAPI_DATA
BOOL free_crypt_prov
Definition: cryptoapi.c:104
#define CERT_STORE_READONLY_FLAG
Definition: cryptoapi.c:64
static int rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
Definition: cryptoapi.c:214
static int rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
Definition: cryptoapi.c:295
#define CRYPTOAPI_F_CRYPT_SIGN_HASH
Definition: cryptoapi.c:82
static void dummy(void)
Definition: comp-lz4.c:319
#define ERR_MAP_SZ
int SSL_CTX_use_CryptoAPI_certificate(SSL_CTX *ssl_ctx, const char *cert_prop)
Definition: cryptoapi.c:409
static int rsa_pub_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
Definition: cryptoapi.c:194
const CERT_CONTEXT * cert_context
Definition: cryptoapi.c:101
#define CRYPTOAPI_F_CRYPT_GET_HASH_PARAM
Definition: cryptoapi.c:80
DWORD key_spec
Definition: cryptoapi.c:103
#define CERT_STORE_OPEN_EXISTING_FLAG
Definition: cryptoapi.c:67
static char * ms_error_text(DWORD ms_err)
Definition: cryptoapi.c:108
static int rsa_pub_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)
Definition: cryptoapi.c:204
static void err_put_ms_error(DWORD ms_err, int func, const char *file, int line)
Definition: cryptoapi.c:144
#define ERR_LIB_CRYPTOAPI
Definition: cryptoapi.c:74
#define SSL_SIG_LENGTH
Definition: cryptoapi.c:71
static int init(RSA *rsa)
Definition: cryptoapi.c:305
static void check_malloc_return(const void *p)
Definition: buffer.h:1060
#define CRYPTOAPI_F_GET_PROC_ADDRESS
Definition: cryptoapi.c:84
static int finish(RSA *rsa)
Definition: cryptoapi.c:313
#define CRYPTOAPI_F_LOAD_LIBRARY
Definition: cryptoapi.c:83
#define CRYPTOAPI_F_CRYPT_CREATE_HASH
Definition: cryptoapi.c:79
HCRYPTPROV crypt_prov
Definition: cryptoapi.c:102
#define CERT_SYSTEM_STORE_CURRENT_USER
Definition: cryptoapi.c:61
Definition: list.h:60
#define CRYPTOAPI_F_CERT_OPEN_SYSTEM_STORE
Definition: cryptoapi.c:76