]>
Commit | Line | Data |
---|---|---|
e1c5b1f6 | 1 | /* |
3c2bdd7d | 2 | * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. |
e1c5b1f6 P |
3 | * |
4 | * Licensed under the Apache License 2.0 (the "License"). You may not use | |
5 | * this file except in compliance with the License. You can obtain a copy | |
6 | * in the file LICENSE in the source distribution or at | |
7 | * https://www.openssl.org/source/license.html | |
8 | */ | |
9 | ||
10 | #include "internal/cryptlib.h" | |
11 | #include <openssl/opensslconf.h> | |
08edd447 | 12 | #include "crypto/rand_pool.h" |
7f791b25 | 13 | #include "prov/seeding.h" |
e1c5b1f6 P |
14 | |
15 | #ifdef OPENSSL_RAND_SEED_RDCPU | |
d3edef83 RB |
16 | # if defined(OPENSSL_SYS_TANDEM) && defined(_TNS_X_TARGET) |
17 | # include <builtin.h> /* _rdrand64 */ | |
18 | # include <string.h> /* memcpy */ | |
d3edef83 | 19 | # else |
e1c5b1f6 P |
20 | size_t OPENSSL_ia32_rdseed_bytes(unsigned char *buf, size_t len); |
21 | size_t OPENSSL_ia32_rdrand_bytes(unsigned char *buf, size_t len); | |
d3edef83 | 22 | # endif |
e1c5b1f6 | 23 | |
53c4992e P |
24 | static size_t get_hardware_random_value(unsigned char *buf, size_t len); |
25 | ||
e1c5b1f6 P |
26 | /* |
27 | * Acquire entropy using Intel-specific cpu instructions | |
28 | * | |
29 | * Uses the RDSEED instruction if available, otherwise uses | |
30 | * RDRAND if available. | |
31 | * | |
32 | * For the differences between RDSEED and RDRAND, and why RDSEED | |
33 | * is the preferred choice, see https://goo.gl/oK3KcN | |
34 | * | |
35 | * Returns the total entropy count, if it exceeds the requested | |
36 | * entropy count. Otherwise, returns an entropy count of 0. | |
37 | */ | |
9fe4f5bc | 38 | size_t ossl_prov_acquire_entropy_from_cpu(RAND_POOL *pool) |
e1c5b1f6 P |
39 | { |
40 | size_t bytes_needed; | |
41 | unsigned char *buffer; | |
42 | ||
1335ca4b | 43 | bytes_needed = ossl_rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); |
e1c5b1f6 | 44 | if (bytes_needed > 0) { |
1335ca4b | 45 | buffer = ossl_rand_pool_add_begin(pool, bytes_needed); |
e1c5b1f6 P |
46 | |
47 | if (buffer != NULL) { | |
d3edef83 | 48 | if (get_hardware_random_value(buffer, bytes_needed) == bytes_needed) { |
1335ca4b | 49 | ossl_rand_pool_add_end(pool, bytes_needed, 8 * bytes_needed); |
e1c5b1f6 | 50 | } else { |
1335ca4b | 51 | ossl_rand_pool_add_end(pool, 0, 0); |
e1c5b1f6 P |
52 | } |
53 | } | |
54 | } | |
55 | ||
1335ca4b | 56 | return ossl_rand_pool_entropy_available(pool); |
e1c5b1f6 | 57 | } |
d3edef83 RB |
58 | |
59 | #if defined(OPENSSL_SYS_TANDEM) && defined(_TNS_X_TARGET) | |
60 | /* Obtain random bytes from the x86 hardware random function in 64 bit chunks */ | |
61 | static size_t get_hardware_random_value(unsigned char *buf, size_t len) | |
62 | { | |
63 | size_t bytes_remaining = len; | |
64 | ||
65 | while (bytes_remaining > 0) { | |
66 | /* Always use 64 bit fetch, then use the lower bytes as needed. */ | |
67 | /* The platform is big-endian. */ | |
68 | uint64_t random_value = 0; | |
69 | ||
70 | if (_rdrand64(&random_value) != 0) { | |
71 | unsigned char *random_buffer = (unsigned char *)&random_value; | |
72 | ||
73 | if (bytes_remaining >= sizeof(random_value)) { | |
74 | memcpy(buf, random_buffer, sizeof(random_value)); | |
75 | bytes_remaining -= sizeof(random_value); | |
76 | buf += sizeof(random_value); | |
77 | } else { | |
78 | memcpy(buf, | |
79 | random_buffer + (sizeof(random_value) - bytes_remaining), | |
80 | bytes_remaining); | |
81 | bytes_remaining = 0; /* This will terminate the loop */ | |
82 | } | |
83 | } else | |
84 | break; | |
85 | } | |
86 | if (bytes_remaining == 0) | |
87 | return len; | |
88 | return 0; | |
89 | } | |
90 | #else | |
91 | static size_t get_hardware_random_value(unsigned char *buf, size_t len) { | |
92 | /* Whichever comes first, use RDSEED, RDRAND or nothing */ | |
93 | if ((OPENSSL_ia32cap_P[2] & (1 << 18)) != 0) { | |
94 | if (OPENSSL_ia32_rdseed_bytes(buf, len) != len) | |
95 | return 0; | |
96 | } else if ((OPENSSL_ia32cap_P[1] & (1 << (62 - 32))) != 0) { | |
97 | if (OPENSSL_ia32_rdrand_bytes(buf, len) != len) | |
98 | return 0; | |
99 | } else | |
100 | return 0; | |
101 | return len; | |
102 | } | |
103 | #endif | |
104 | ||
e1c5b1f6 P |
105 | #else |
106 | NON_EMPTY_TRANSLATION_UNIT | |
107 | #endif |