1 /* 2 * Copyright 1995-2021 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 "crypto/rand_pool.h" 13 #include "prov/seeding.h" 14 15 #ifdef OPENSSL_RAND_SEED_RDCPU 16 # if defined(OPENSSL_SYS_TANDEM) && defined(_TNS_X_TARGET) 17 # include <builtin.h> /* _rdrand64 */ 18 # include <string.h> /* memcpy */ 19 # else 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); 22 # endif 23 24 static size_t get_hardware_random_value(unsigned char *buf, size_t len); 25 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 */ 38 size_t ossl_prov_acquire_entropy_from_cpu(RAND_POOL *pool) 39 { 40 size_t bytes_needed; 41 unsigned char *buffer; 42 43 bytes_needed = ossl_rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); 44 if (bytes_needed > 0) { 45 buffer = ossl_rand_pool_add_begin(pool, bytes_needed); 46 47 if (buffer != NULL) { 48 if (get_hardware_random_value(buffer, bytes_needed) == bytes_needed) { 49 ossl_rand_pool_add_end(pool, bytes_needed, 8 * bytes_needed); 50 } else { 51 ossl_rand_pool_add_end(pool, 0, 0); 52 } 53 } 54 } 55 56 return ossl_rand_pool_entropy_available(pool); 57 } 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 105 #else 106 NON_EMPTY_TRANSLATION_UNIT 107 #endif 108