share rand_pool between libcrypto and providers
[openssl.git] / providers / implementations / rands / seeding / rand_cpu_x86.c
1 /*
2  * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
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>
12 #include "prov/rand_pool.h"
13
14 #ifdef OPENSSL_RAND_SEED_RDCPU
15 size_t OPENSSL_ia32_rdseed_bytes(unsigned char *buf, size_t len);
16 size_t OPENSSL_ia32_rdrand_bytes(unsigned char *buf, size_t len);
17
18 /*
19  * Acquire entropy using Intel-specific cpu instructions
20  *
21  * Uses the RDSEED instruction if available, otherwise uses
22  * RDRAND if available.
23  *
24  * For the differences between RDSEED and RDRAND, and why RDSEED
25  * is the preferred choice, see https://goo.gl/oK3KcN
26  *
27  * Returns the total entropy count, if it exceeds the requested
28  * entropy count. Otherwise, returns an entropy count of 0.
29  */
30 size_t prov_acquire_entropy_from_cpu(RAND_POOL *pool)
31 {
32     size_t bytes_needed;
33     unsigned char *buffer;
34
35     bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/);
36     if (bytes_needed > 0) {
37         buffer = rand_pool_add_begin(pool, bytes_needed);
38
39         if (buffer != NULL) {
40             /* Whichever comes first, use RDSEED, RDRAND or nothing */
41             if ((OPENSSL_ia32cap_P[2] & (1 << 18)) != 0) {
42                 if (OPENSSL_ia32_rdseed_bytes(buffer, bytes_needed)
43                     == bytes_needed) {
44                     rand_pool_add_end(pool, bytes_needed, 8 * bytes_needed);
45                 }
46             } else if ((OPENSSL_ia32cap_P[1] & (1 << (62 - 32))) != 0) {
47                 if (OPENSSL_ia32_rdrand_bytes(buffer, bytes_needed)
48                     == bytes_needed) {
49                     rand_pool_add_end(pool, bytes_needed, 8 * bytes_needed);
50                 }
51             } else {
52                 rand_pool_add_end(pool, 0, 0);
53             }
54         }
55     }
56
57     return rand_pool_entropy_available(pool);
58 }
59 #else
60 NON_EMPTY_TRANSLATION_UNIT
61 #endif