xref: /freebsd-src/crypto/openssl/providers/implementations/rands/seeding/rand_cpu_x86.c (revision b077aed33b7b6aefca7b17ddb250cf521f938613)
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