1/* Copyright (c) 2014, Google Inc.
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14
15#include <openssl/rand.h>
16
17#include <openssl/thread.h>
18
19
20#if defined(OPENSSL_WINDOWS)
21
22#include <stdlib.h>
23#include <Windows.h>
24#include <Wincrypt.h>
25
26static char global_provider_init;
27static HCRYPTPROV global_provider;
28
29void RAND_cleanup(void) {
30  CRYPTO_w_lock(CRYPTO_LOCK_RAND);
31  CryptReleaseContext(global_provider, 0);
32  global_provider_init = 0;
33  CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
34}
35
36int RAND_bytes(uint8_t *out, size_t requested) {
37  HCRYPTPROV provider = 0;
38  int ok;
39
40  CRYPTO_r_lock(CRYPTO_LOCK_RAND);
41  if (!global_provider_init) {
42    CRYPTO_r_unlock(CRYPTO_LOCK_RAND);
43    CRYPTO_w_lock(CRYPTO_LOCK_RAND);
44    if (!global_provider_init) {
45      if (CryptAcquireContext(&global_provider, NULL, NULL, PROV_RSA_FULL,
46                              CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
47        global_provider_init = 1;
48      }
49    }
50    CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
51    CRYPTO_r_lock(CRYPTO_LOCK_RAND);
52  }
53
54  ok = global_provider_init;
55  provider = global_provider;
56  CRYPTO_r_unlock(CRYPTO_LOCK_RAND);
57
58  if (!ok) {
59    abort();
60    return ok;
61  }
62
63  if (TRUE != CryptGenRandom(provider, requested, out)) {
64    abort();
65    return 0;
66  }
67
68  return 1;
69}
70
71#endif  /* OPENSSL_WINDOWS */
72