1/*
2 * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the OpenSSL license (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 <openssl/opensslconf.h>
11
12#ifndef OPENSSL_SYS_VXWORKS
13NON_EMPTY_TRANSLATION_UNIT
14#else
15# include <openssl/rand.h>
16# include "rand_local.h"
17# include "crypto/rand.h"
18# include "internal/cryptlib.h"
19# include <version.h>
20# include <taskLib.h>
21
22# if defined(OPENSSL_RAND_SEED_NONE)
23/* none means none */
24# undef OPENSSL_RAND_SEED_OS
25# endif
26
27# if defined(OPENSSL_RAND_SEED_OS)
28# if _WRS_VXWORKS_MAJOR >= 7
29# define RAND_SEED_VXRANDLIB
30# else
31# error "VxWorks <7 only support RAND_SEED_NONE"
32# endif
33# endif
34
35# if defined(RAND_SEED_VXRANDLIB)
36# include <randomNumGen.h>
37# endif
38
39/* Macro to convert two thirty two bit values into a sixty four bit one */
40# define TWO32TO64(a, b) ((((uint64_t)(a)) << 32) + (b))
41
42static uint64_t get_time_stamp(void)
43{
44 struct timespec ts;
45
46 if (clock_gettime(CLOCK_REALTIME, &ts) == 0)
47 return TWO32TO64(ts.tv_sec, ts.tv_nsec);
48 return time(NULL);
49}
50
51static uint64_t get_timer_bits(void)
52{
53 uint64_t res = OPENSSL_rdtsc();
54 struct timespec ts;
55
56 if (res != 0)
57 return res;
58
59 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
60 return TWO32TO64(ts.tv_sec, ts.tv_nsec);
61 return time(NULL);
62}
63
64/*
65 * empty implementation
66 * vxworks does not need to init/cleanup or keep open the random lib
67 */
68int rand_pool_init(void)
69{
70 return 1;
71}
72
73void rand_pool_cleanup(void)
74{
75}
76
77void rand_pool_keep_random_devices_open(int keep)
78{
79}
80
81int rand_pool_add_additional_data(RAND_POOL *pool)
82{
83 struct {
84 CRYPTO_THREAD_ID tid;
85 uint64_t time;
86 } data;
87
88 memset(&data, 0, sizeof(data));
89
90 /*
91 * Add some noise from the thread id and a high resolution timer.
92 * The thread id adds a little randomness if the drbg is accessed
93 * concurrently (which is the case for the <master> drbg).
94 */
95 data.tid = CRYPTO_THREAD_get_current_id();
96 data.time = get_timer_bits();
97
98 return rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0);
99}
100
101int rand_pool_add_nonce_data(RAND_POOL *pool)
102{
103 struct {
104 pid_t pid;
105 CRYPTO_THREAD_ID tid;
106 uint64_t time;
107 } data;
108
109 memset(&data, 0, sizeof(data));
110
111 /*
112 * Add process id, thread id, and a high resolution timestamp to
113 * ensure that the nonce is unique with high probability for
114 * different process instances.
115 */
116 data.pid = getpid();
117 data.tid = CRYPTO_THREAD_get_current_id();
118 data.time = get_time_stamp();
119
120 return rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0);
121}
122
123size_t rand_pool_acquire_entropy(RAND_POOL *pool)
124{
125# if defined(RAND_SEED_VXRANDLIB)
126 /* vxRandLib based entropy method */
127 size_t bytes_needed;
128
129 bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/);
130 if (bytes_needed > 0)
131 {
132 int retryCount = 0;
133 STATUS result = ERROR;
134 unsigned char *buffer;
135
136 buffer = rand_pool_add_begin(pool, bytes_needed);
137 while ((result != OK) && (retryCount < 10)) {
138 RANDOM_NUM_GEN_STATUS status = randStatus();
139
140 if ((status == RANDOM_NUM_GEN_ENOUGH_ENTROPY)
141 || (status == RANDOM_NUM_GEN_MAX_ENTROPY) ) {
142 result = randBytes(buffer, bytes_needed);
143 if (result == OK)
144 rand_pool_add_end(pool, bytes_needed, 8 * bytes_needed);
145 /*
146 * no else here: randStatus said ok, if randBytes failed
147 * it will result in another loop or no entropy
148 */
149 } else {
150 /*
151 * give a minimum delay here to allow OS to collect more
152 * entropy. taskDelay duration will depend on the system tick,
153 * this is by design as the sw-random lib uses interrupts
154 * which will at least happen during ticks
155 */
156 taskDelay(5);
157 }
158 retryCount++;
159 }
160 }
161 return rand_pool_entropy_available(pool);
162# else
163 /*
164 * SEED_NONE means none, without randlib we dont have entropy and
165 * rely on it being added externally
166 */
167 return rand_pool_entropy_available(pool);
168# endif /* defined(RAND_SEED_VXRANDLIB) */
169}
170
171#endif /* OPENSSL_SYS_VXWORKS */
172