/src/h2o/deps/picotls/lib/cifra/random.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2016-2019 DeNA Co., Ltd., Kazuho Oku, Christian Huitema |
3 | | * |
4 | | * Permission is hereby granted, free of charge, to any person obtaining a copy |
5 | | * of this software and associated documentation files (the "Software"), to |
6 | | * deal in the Software without restriction, including without limitation the |
7 | | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
8 | | * sell copies of the Software, and to permit persons to whom the Software is |
9 | | * furnished to do so, subject to the following conditions: |
10 | | * |
11 | | * The above copyright notice and this permission notice shall be included in |
12 | | * all copies or substantial portions of the Software. |
13 | | * |
14 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
15 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
16 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
17 | | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
18 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
19 | | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
20 | | * IN THE SOFTWARE. |
21 | | */ |
22 | | #ifndef _XOPEN_SOURCE |
23 | | #define _XOPEN_SOURCE 700 /* required for glibc to use getaddrinfo, etc. */ |
24 | | #endif |
25 | | #include <errno.h> |
26 | | #include <fcntl.h> |
27 | | #include <stdio.h> |
28 | | #include <stdlib.h> |
29 | | #ifdef _WINDOWS |
30 | | #include "wincompat.h" |
31 | | #else |
32 | | #include <unistd.h> |
33 | | #endif |
34 | | #include "drbg.h" |
35 | | #include "picotls.h" |
36 | | #include "picotls/minicrypto.h" |
37 | | #include <stdio.h> |
38 | | #ifdef _WINDOWS |
39 | | #ifdef _WINDOWS_XP |
40 | | /* The modern BCrypt API is only available on Windows Vista and later versions. |
41 | | * If compiling on Windows XP, we need to use the olded "wincrypt" API */ |
42 | | #include <wincrypt.h> |
43 | | |
44 | | static void read_entropy(uint8_t *entropy, size_t size) |
45 | | { |
46 | | HCRYPTPROV hCryptProv = 0; |
47 | | BOOL ret = FALSE; |
48 | | |
49 | | if (CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, 0)) { |
50 | | ret = CryptGenRandom(hCryptProv, (DWORD)size, entropy); |
51 | | (void)CryptReleaseContext(hCryptProv, 0); |
52 | | } |
53 | | |
54 | | if (ret == FALSE) { |
55 | | perror("ptls_minicrypto_random_bytes: could not use CryptGenRandom"); |
56 | | abort(); |
57 | | } |
58 | | } |
59 | | #else |
60 | | /* The old "Wincrypt" API requires access to default security containers. |
61 | | * This can cause access control errors on some systems. We prefer |
62 | | * to use the modern BCrypt API when available */ |
63 | | #include <bcrypt.h> |
64 | | |
65 | | static void read_entropy(uint8_t *entropy, size_t size) |
66 | | { |
67 | | NTSTATUS nts = 0; |
68 | | BCRYPT_ALG_HANDLE hAlgorithm = 0; |
69 | | |
70 | | nts = BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_RNG_ALGORITHM, NULL, 0); |
71 | | |
72 | | if (BCRYPT_SUCCESS(nts)) { |
73 | | nts = BCryptGenRandom(hAlgorithm, (PUCHAR)entropy, (ULONG)size, 0); |
74 | | |
75 | | (void)BCryptCloseAlgorithmProvider(hAlgorithm, 0); |
76 | | } |
77 | | |
78 | | if (!BCRYPT_SUCCESS(nts)) { |
79 | | perror("ptls_minicrypto_random_bytes: could not open BCrypt RNG Algorithm"); |
80 | | abort(); |
81 | | } |
82 | | } |
83 | | #endif |
84 | | #else |
85 | | static void read_entropy(uint8_t *entropy, size_t size) |
86 | 0 | { |
87 | 0 | int fd; |
88 | |
|
89 | 0 | if ((fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC)) == -1) { |
90 | 0 | if ((fd = open("/dev/random", O_RDONLY | O_CLOEXEC)) == -1) { |
91 | 0 | perror("ptls_minicrypto_random_bytes: could not open neither /dev/random or /dev/urandom"); |
92 | 0 | abort(); |
93 | 0 | } |
94 | 0 | } |
95 | | |
96 | 0 | while (size != 0) { |
97 | 0 | ssize_t rret; |
98 | 0 | while ((rret = read(fd, entropy, size)) == -1 && errno == EINTR) |
99 | 0 | ; |
100 | 0 | if (rret < 0) { |
101 | 0 | perror("ptls_minicrypto_random_bytes"); |
102 | 0 | abort(); |
103 | 0 | } |
104 | 0 | entropy += rret; |
105 | 0 | size -= rret; |
106 | 0 | } |
107 | | |
108 | 0 | close(fd); |
109 | 0 | } |
110 | | #endif |
111 | | |
112 | | void ptls_minicrypto_random_bytes(void *buf, size_t len) |
113 | 0 | { |
114 | 0 | static PTLS_THREADLOCAL cf_hash_drbg_sha256 ctx; |
115 | |
|
116 | 0 | if (cf_hash_drbg_sha256_needs_reseed(&ctx)) { |
117 | 0 | uint8_t entropy[256]; |
118 | 0 | read_entropy(entropy, sizeof(entropy)); |
119 | 0 | cf_hash_drbg_sha256_init(&ctx, entropy, sizeof(entropy) / 2, entropy + sizeof(entropy) / 2, sizeof(entropy) / 2, "ptls", 4); |
120 | 0 | } |
121 | 0 | cf_hash_drbg_sha256_gen(&ctx, buf, len); |
122 | 0 | } |