Home | History | Annotate | Line # | Download | only in seeding
      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 {
     93     /* Whichever comes first, use RDSEED, RDRAND or nothing */
     94     if ((OPENSSL_ia32cap_P[2] & (1 << 18)) != 0) {
     95         if (OPENSSL_ia32_rdseed_bytes(buf, len) != len)
     96             return 0;
     97     } else if ((OPENSSL_ia32cap_P[1] & (1 << (62 - 32))) != 0) {
     98         if (OPENSSL_ia32_rdrand_bytes(buf, len) != len)
     99             return 0;
    100     } else
    101         return 0;
    102     return len;
    103 }
    104 #endif
    105 
    106 #else
    107 NON_EMPTY_TRANSLATION_UNIT
    108 #endif
    109