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