1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 2011-2020 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * 4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 5e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 8e1051a39Sopenharmony_ci */ 9e1051a39Sopenharmony_ci 10e1051a39Sopenharmony_ci/* We need to use some engine deprecated APIs */ 11e1051a39Sopenharmony_ci#define OPENSSL_SUPPRESS_DEPRECATED 12e1051a39Sopenharmony_ci 13e1051a39Sopenharmony_ci#include <openssl/opensslconf.h> 14e1051a39Sopenharmony_ci 15e1051a39Sopenharmony_ci#include <stdio.h> 16e1051a39Sopenharmony_ci#include <string.h> 17e1051a39Sopenharmony_ci#include "crypto/engine.h" 18e1051a39Sopenharmony_ci#include "internal/cryptlib.h" 19e1051a39Sopenharmony_ci#include <openssl/rand.h> 20e1051a39Sopenharmony_ci#include <openssl/err.h> 21e1051a39Sopenharmony_ci#include <openssl/crypto.h> 22e1051a39Sopenharmony_ci 23e1051a39Sopenharmony_ci#if (defined(__i386) || defined(__i386__) || defined(_M_IX86) || \ 24e1051a39Sopenharmony_ci defined(__x86_64) || defined(__x86_64__) || \ 25e1051a39Sopenharmony_ci defined(_M_AMD64) || defined (_M_X64)) && defined(OPENSSL_CPUID_OBJ) 26e1051a39Sopenharmony_ci 27e1051a39Sopenharmony_cisize_t OPENSSL_ia32_rdrand_bytes(unsigned char *buf, size_t len); 28e1051a39Sopenharmony_ci 29e1051a39Sopenharmony_cistatic int get_random_bytes(unsigned char *buf, int num) 30e1051a39Sopenharmony_ci{ 31e1051a39Sopenharmony_ci if (num < 0) { 32e1051a39Sopenharmony_ci return 0; 33e1051a39Sopenharmony_ci } 34e1051a39Sopenharmony_ci 35e1051a39Sopenharmony_ci return (size_t)num == OPENSSL_ia32_rdrand_bytes(buf, (size_t)num); 36e1051a39Sopenharmony_ci} 37e1051a39Sopenharmony_ci 38e1051a39Sopenharmony_cistatic int random_status(void) 39e1051a39Sopenharmony_ci{ 40e1051a39Sopenharmony_ci return 1; 41e1051a39Sopenharmony_ci} 42e1051a39Sopenharmony_ci 43e1051a39Sopenharmony_cistatic RAND_METHOD rdrand_meth = { 44e1051a39Sopenharmony_ci NULL, /* seed */ 45e1051a39Sopenharmony_ci get_random_bytes, 46e1051a39Sopenharmony_ci NULL, /* cleanup */ 47e1051a39Sopenharmony_ci NULL, /* add */ 48e1051a39Sopenharmony_ci get_random_bytes, 49e1051a39Sopenharmony_ci random_status, 50e1051a39Sopenharmony_ci}; 51e1051a39Sopenharmony_ci 52e1051a39Sopenharmony_cistatic int rdrand_init(ENGINE *e) 53e1051a39Sopenharmony_ci{ 54e1051a39Sopenharmony_ci return 1; 55e1051a39Sopenharmony_ci} 56e1051a39Sopenharmony_ci 57e1051a39Sopenharmony_cistatic const char *engine_e_rdrand_id = "rdrand"; 58e1051a39Sopenharmony_cistatic const char *engine_e_rdrand_name = "Intel RDRAND engine"; 59e1051a39Sopenharmony_ci 60e1051a39Sopenharmony_cistatic int bind_helper(ENGINE *e) 61e1051a39Sopenharmony_ci{ 62e1051a39Sopenharmony_ci if (!ENGINE_set_id(e, engine_e_rdrand_id) || 63e1051a39Sopenharmony_ci !ENGINE_set_name(e, engine_e_rdrand_name) || 64e1051a39Sopenharmony_ci !ENGINE_set_flags(e, ENGINE_FLAGS_NO_REGISTER_ALL) || 65e1051a39Sopenharmony_ci !ENGINE_set_init_function(e, rdrand_init) || 66e1051a39Sopenharmony_ci !ENGINE_set_RAND(e, &rdrand_meth)) 67e1051a39Sopenharmony_ci return 0; 68e1051a39Sopenharmony_ci 69e1051a39Sopenharmony_ci return 1; 70e1051a39Sopenharmony_ci} 71e1051a39Sopenharmony_ci 72e1051a39Sopenharmony_cistatic ENGINE *ENGINE_rdrand(void) 73e1051a39Sopenharmony_ci{ 74e1051a39Sopenharmony_ci ENGINE *ret = ENGINE_new(); 75e1051a39Sopenharmony_ci if (ret == NULL) 76e1051a39Sopenharmony_ci return NULL; 77e1051a39Sopenharmony_ci if (!bind_helper(ret)) { 78e1051a39Sopenharmony_ci ENGINE_free(ret); 79e1051a39Sopenharmony_ci return NULL; 80e1051a39Sopenharmony_ci } 81e1051a39Sopenharmony_ci return ret; 82e1051a39Sopenharmony_ci} 83e1051a39Sopenharmony_ci 84e1051a39Sopenharmony_civoid engine_load_rdrand_int(void) 85e1051a39Sopenharmony_ci{ 86e1051a39Sopenharmony_ci if (OPENSSL_ia32cap_P[1] & (1 << (62 - 32))) { 87e1051a39Sopenharmony_ci ENGINE *toadd = ENGINE_rdrand(); 88e1051a39Sopenharmony_ci if (!toadd) 89e1051a39Sopenharmony_ci return; 90e1051a39Sopenharmony_ci ERR_set_mark(); 91e1051a39Sopenharmony_ci ENGINE_add(toadd); 92e1051a39Sopenharmony_ci /* 93e1051a39Sopenharmony_ci * If the "add" worked, it gets a structural reference. So either way, we 94e1051a39Sopenharmony_ci * release our just-created reference. 95e1051a39Sopenharmony_ci */ 96e1051a39Sopenharmony_ci ENGINE_free(toadd); 97e1051a39Sopenharmony_ci /* 98e1051a39Sopenharmony_ci * If the "add" didn't work, it was probably a conflict because it was 99e1051a39Sopenharmony_ci * already added (eg. someone calling ENGINE_load_blah then calling 100e1051a39Sopenharmony_ci * ENGINE_load_builtin_engines() perhaps). 101e1051a39Sopenharmony_ci */ 102e1051a39Sopenharmony_ci ERR_pop_to_mark(); 103e1051a39Sopenharmony_ci } 104e1051a39Sopenharmony_ci} 105e1051a39Sopenharmony_ci#else 106e1051a39Sopenharmony_civoid engine_load_rdrand_int(void) 107e1051a39Sopenharmony_ci{ 108e1051a39Sopenharmony_ci} 109e1051a39Sopenharmony_ci#endif 110