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