xref: /src/crypto/openssl/providers/implementations/rands/seeding/rand_vms.c (revision f25b8c9fb4f58cf61adb47d7570abe7caa6d385d)
1 /*
2  * Copyright 2001-2022 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/e_os.h"
11 
12 #define __NEW_STARLET 1 /* New starlet definitions since VMS 7.0 */
13 #include <unistd.h>
14 #include "internal/cryptlib.h"
15 #include "internal/nelem.h"
16 #include <openssl/rand.h>
17 #include "crypto/rand.h"
18 #include "crypto/rand_pool.h"
19 #include "prov/seeding.h"
20 #include <descrip.h>
21 #include <dvidef.h>
22 #include <jpidef.h>
23 #include <rmidef.h>
24 #include <syidef.h>
25 #include <ssdef.h>
26 #include <starlet.h>
27 #include <efndef.h>
28 #include <gen64def.h>
29 #include <iosbdef.h>
30 #include <iledef.h>
31 #include <lib$routines.h>
32 #ifdef __DECC
33 #pragma message disable DOLLARID
34 #endif
35 
36 #include <dlfcn.h> /* SYS$GET_ENTROPY presence */
37 
38 #ifndef OPENSSL_RAND_SEED_OS
39 #error "Unsupported seeding method configured; must be os"
40 #endif
41 
42 /*
43  * DATA COLLECTION METHOD
44  * ======================
45  *
46  * This is a method to get low quality entropy.
47  * It works by collecting all kinds of statistical data that
48  * VMS offers and using them as random seed.
49  */
50 
51 /* We need to make sure we have the right size pointer in some cases */
52 #if __INITIAL_POINTER_SIZE == 64
53 #pragma pointer_size save
54 #pragma pointer_size 32
55 #endif
56 typedef uint32_t *uint32_t__ptr32;
57 #if __INITIAL_POINTER_SIZE == 64
58 #pragma pointer_size restore
59 #endif
60 
61 struct item_st {
62     short length, code; /* length is number of bytes */
63 };
64 
65 static const struct item_st DVI_item_data[] = {
66     { 4, DVI$_ERRCNT },
67     { 4, DVI$_REFCNT },
68 };
69 
70 static const struct item_st JPI_item_data[] = {
71     { 4, JPI$_BUFIO },
72     { 4, JPI$_CPUTIM },
73     { 4, JPI$_DIRIO },
74     { 4, JPI$_IMAGECOUNT },
75     { 4, JPI$_PAGEFLTS },
76     { 4, JPI$_PID },
77     { 4, JPI$_PPGCNT },
78     { 4, JPI$_WSPEAK },
79     /*
80      * Note: the direct result is just a 32-bit address.  However, it points
81      * to a list of 4 32-bit words, so we make extra space for them so we can
82      * do in-place replacement of values
83      */
84     { 16, JPI$_FINALEXC },
85 };
86 
87 static const struct item_st JPI_item_data_64bit[] = {
88     { 8, JPI$_LAST_LOGIN_I },
89     { 8, JPI$_LOGINTIM },
90 };
91 
92 static const struct item_st RMI_item_data[] = {
93     { 4, RMI$_COLPG },
94     { 4, RMI$_MWAIT },
95     { 4, RMI$_CEF },
96     { 4, RMI$_PFW },
97     { 4, RMI$_LEF },
98     { 4, RMI$_LEFO },
99     { 4, RMI$_HIB },
100     { 4, RMI$_HIBO },
101     { 4, RMI$_SUSP },
102     { 4, RMI$_SUSPO },
103     { 4, RMI$_FPG },
104     { 4, RMI$_COM },
105     { 4, RMI$_COMO },
106     { 4, RMI$_CUR },
107 #if defined __alpha
108     { 4, RMI$_FRLIST },
109     { 4, RMI$_MODLIST },
110 #endif
111     { 4, RMI$_FAULTS },
112     { 4, RMI$_PREADS },
113     { 4, RMI$_PWRITES },
114     { 4, RMI$_PWRITIO },
115     { 4, RMI$_PREADIO },
116     { 4, RMI$_GVALFLTS },
117     { 4, RMI$_WRTINPROG },
118     { 4, RMI$_FREFLTS },
119     { 4, RMI$_DZROFLTS },
120     { 4, RMI$_SYSFAULTS },
121     { 4, RMI$_ISWPCNT },
122     { 4, RMI$_DIRIO },
123     { 4, RMI$_BUFIO },
124     { 4, RMI$_MBREADS },
125     { 4, RMI$_MBWRITES },
126     { 4, RMI$_LOGNAM },
127     { 4, RMI$_FCPCALLS },
128     { 4, RMI$_FCPREAD },
129     { 4, RMI$_FCPWRITE },
130     { 4, RMI$_FCPCACHE },
131     { 4, RMI$_FCPCPU },
132     { 4, RMI$_FCPHIT },
133     { 4, RMI$_FCPSPLIT },
134     { 4, RMI$_FCPFAULT },
135     { 4, RMI$_ENQNEW },
136     { 4, RMI$_ENQCVT },
137     { 4, RMI$_DEQ },
138     { 4, RMI$_BLKAST },
139     { 4, RMI$_ENQWAIT },
140     { 4, RMI$_ENQNOTQD },
141     { 4, RMI$_DLCKSRCH },
142     { 4, RMI$_DLCKFND },
143     { 4, RMI$_NUMLOCKS },
144     { 4, RMI$_NUMRES },
145     { 4, RMI$_ARRLOCPK },
146     { 4, RMI$_DEPLOCPK },
147     { 4, RMI$_ARRTRAPK },
148     { 4, RMI$_TRCNGLOS },
149     { 4, RMI$_RCVBUFFL },
150     { 4, RMI$_ENQNEWLOC },
151     { 4, RMI$_ENQNEWIN },
152     { 4, RMI$_ENQNEWOUT },
153     { 4, RMI$_ENQCVTLOC },
154     { 4, RMI$_ENQCVTIN },
155     { 4, RMI$_ENQCVTOUT },
156     { 4, RMI$_DEQLOC },
157     { 4, RMI$_DEQIN },
158     { 4, RMI$_DEQOUT },
159     { 4, RMI$_BLKLOC },
160     { 4, RMI$_BLKIN },
161     { 4, RMI$_BLKOUT },
162     { 4, RMI$_DIRIN },
163     { 4, RMI$_DIROUT },
164 /* We currently get a fault when trying these */
165 #if 0
166     {140, RMI$_MSCP_EVERYTHING},   /* 35 32-bit words */
167     {152, RMI$_DDTM_ALL},          /* 38 32-bit words */
168     {80,  RMI$_TMSCP_EVERYTHING}   /* 20 32-bit words */
169 #endif
170     { 4, RMI$_LPZ_PAGCNT },
171     { 4, RMI$_LPZ_HITS },
172     { 4, RMI$_LPZ_MISSES },
173     { 4, RMI$_LPZ_EXPCNT },
174     { 4, RMI$_LPZ_ALLOCF },
175     { 4, RMI$_LPZ_ALLOC2 },
176     { 4, RMI$_ACCESS },
177     { 4, RMI$_ALLOC },
178     { 4, RMI$_FCPCREATE },
179     { 4, RMI$_VOLWAIT },
180     { 4, RMI$_FCPTURN },
181     { 4, RMI$_FCPERASE },
182     { 4, RMI$_OPENS },
183     { 4, RMI$_FIDHIT },
184     { 4, RMI$_FIDMISS },
185     { 4, RMI$_FILHDR_HIT },
186     { 4, RMI$_DIRFCB_HIT },
187     { 4, RMI$_DIRFCB_MISS },
188     { 4, RMI$_DIRDATA_HIT },
189     { 4, RMI$_EXTHIT },
190     { 4, RMI$_EXTMISS },
191     { 4, RMI$_QUOHIT },
192     { 4, RMI$_QUOMISS },
193     { 4, RMI$_STORAGMAP_HIT },
194     { 4, RMI$_VOLLCK },
195     { 4, RMI$_SYNCHLCK },
196     { 4, RMI$_SYNCHWAIT },
197     { 4, RMI$_ACCLCK },
198     { 4, RMI$_XQPCACHEWAIT },
199     { 4, RMI$_DIRDATA_MISS },
200     { 4, RMI$_FILHDR_MISS },
201     { 4, RMI$_STORAGMAP_MISS },
202     { 4, RMI$_PROCCNTMAX },
203     { 4, RMI$_PROCBATCNT },
204     { 4, RMI$_PROCINTCNT },
205     { 4, RMI$_PROCNETCNT },
206     { 4, RMI$_PROCSWITCHCNT },
207     { 4, RMI$_PROCBALSETCNT },
208     { 4, RMI$_PROCLOADCNT },
209     { 4, RMI$_BADFLTS },
210     { 4, RMI$_EXEFAULTS },
211     { 4, RMI$_HDRINSWAPS },
212     { 4, RMI$_HDROUTSWAPS },
213     { 4, RMI$_IOPAGCNT },
214     { 4, RMI$_ISWPCNTPG },
215     { 4, RMI$_OSWPCNT },
216     { 4, RMI$_OSWPCNTPG },
217     { 4, RMI$_RDFAULTS },
218     { 4, RMI$_TRANSFLTS },
219     { 4, RMI$_WRTFAULTS },
220 #if defined __alpha
221     { 4, RMI$_USERPAGES },
222 #endif
223     { 4, RMI$_VMSPAGES },
224     { 4, RMI$_TTWRITES },
225     { 4, RMI$_BUFOBJPAG },
226     { 4, RMI$_BUFOBJPAGPEAK },
227     { 4, RMI$_BUFOBJPAGS01 },
228     { 4, RMI$_BUFOBJPAGS2 },
229     { 4, RMI$_BUFOBJPAGMAXS01 },
230     { 4, RMI$_BUFOBJPAGMAXS2 },
231     { 4, RMI$_BUFOBJPAGPEAKS01 },
232     { 4, RMI$_BUFOBJPAGPEAKS2 },
233     { 4, RMI$_BUFOBJPGLTMAXS01 },
234     { 4, RMI$_BUFOBJPGLTMAXS2 },
235     { 4, RMI$_DLCK_INCMPLT },
236     { 4, RMI$_DLCKMSGS_IN },
237     { 4, RMI$_DLCKMSGS_OUT },
238     { 4, RMI$_MCHKERRS },
239     { 4, RMI$_MEMERRS },
240 };
241 
242 static const struct item_st RMI_item_data_64bit[] = {
243 #if defined __ia64
244     { 8, RMI$_FRLIST },
245     { 8, RMI$_MODLIST },
246 #endif
247     { 8, RMI$_LCKMGR_REQCNT },
248     { 8, RMI$_LCKMGR_REQTIME },
249     { 8, RMI$_LCKMGR_SPINCNT },
250     { 8, RMI$_LCKMGR_SPINTIME },
251     { 8, RMI$_CPUINTSTK },
252     { 8, RMI$_CPUMPSYNCH },
253     { 8, RMI$_CPUKERNEL },
254     { 8, RMI$_CPUEXEC },
255     { 8, RMI$_CPUSUPER },
256     { 8, RMI$_CPUUSER },
257 #if defined __ia64
258     { 8, RMI$_USERPAGES },
259 #endif
260     { 8, RMI$_TQETOTAL },
261     { 8, RMI$_TQESYSUB },
262     { 8, RMI$_TQEUSRTIMR },
263     { 8, RMI$_TQEUSRWAKE },
264 };
265 
266 static const struct item_st SYI_item_data[] = {
267     { 4, SYI$_PAGEFILE_FREE },
268 };
269 
270 /*
271  * Input:
272  * items_data           - an array of lengths and codes
273  * items_data_num       - number of elements in that array
274  *
275  * Output:
276  * items                - pre-allocated ILE3 array to be filled.
277  *                        It's assumed to have items_data_num elements plus
278  *                        one extra for the terminating NULL element
279  * databuffer           - pre-allocated 32-bit word array.
280  *
281  * Returns the number of elements used in databuffer
282  */
prepare_item_list(const struct item_st * items_input,size_t items_input_num,ILE3 * items,uint32_t__ptr32 databuffer)283 static size_t prepare_item_list(const struct item_st *items_input,
284     size_t items_input_num,
285     ILE3 *items,
286     uint32_t__ptr32 databuffer)
287 {
288     size_t data_sz = 0;
289 
290     for (; items_input_num-- > 0; items_input++, items++) {
291 
292         items->ile3$w_code = items_input->code;
293         /* Special treatment of JPI$_FINALEXC */
294         if (items->ile3$w_code == JPI$_FINALEXC)
295             items->ile3$w_length = 4;
296         else
297             items->ile3$w_length = items_input->length;
298 
299         items->ile3$ps_bufaddr = databuffer;
300         items->ile3$ps_retlen_addr = 0;
301 
302         databuffer += items_input->length / sizeof(databuffer[0]);
303         data_sz += items_input->length;
304     }
305     /* Terminating NULL entry */
306     items->ile3$w_length = items->ile3$w_code = 0;
307     items->ile3$ps_bufaddr = items->ile3$ps_retlen_addr = NULL;
308 
309     return data_sz / sizeof(databuffer[0]);
310 }
311 
massage_JPI(ILE3 * items)312 static void massage_JPI(ILE3 *items)
313 {
314     /*
315      * Special treatment of JPI$_FINALEXC
316      * The result of that item's data buffer is a 32-bit address to a list of
317      * 4 32-bit words.
318      */
319     for (; items->ile3$w_length != 0; items++) {
320         if (items->ile3$w_code == JPI$_FINALEXC) {
321             uint32_t *data = items->ile3$ps_bufaddr;
322             uint32_t *ptr = (uint32_t *)*data;
323             size_t j;
324 
325             /*
326              * We know we made space for 4 32-bit words, so we can do in-place
327              * replacement.
328              */
329             for (j = 0; j < 4; j++)
330                 data[j] = ptr[j];
331 
332             break;
333         }
334     }
335 }
336 
337 /*
338  * This number expresses how many bits of data contain 1 bit of entropy.
339  *
340  * For the moment, we assume about 0.05 entropy bits per data bit, or 1
341  * bit of entropy per 20 data bits.
342  */
343 #define ENTROPY_FACTOR 20
344 
data_collect_method(RAND_POOL * pool)345 size_t data_collect_method(RAND_POOL *pool)
346 {
347     ILE3 JPI_items_64bit[OSSL_NELEM(JPI_item_data_64bit) + 1];
348     ILE3 RMI_items_64bit[OSSL_NELEM(RMI_item_data_64bit) + 1];
349     ILE3 DVI_items[OSSL_NELEM(DVI_item_data) + 1];
350     ILE3 JPI_items[OSSL_NELEM(JPI_item_data) + 1];
351     ILE3 RMI_items[OSSL_NELEM(RMI_item_data) + 1];
352     ILE3 SYI_items[OSSL_NELEM(SYI_item_data) + 1];
353     union {
354         /* This ensures buffer starts at 64 bit boundary */
355         uint64_t dummy;
356         uint32_t buffer[OSSL_NELEM(JPI_item_data_64bit) * 2
357             + OSSL_NELEM(RMI_item_data_64bit) * 2
358             + OSSL_NELEM(DVI_item_data)
359             + OSSL_NELEM(JPI_item_data)
360             + OSSL_NELEM(RMI_item_data)
361             + OSSL_NELEM(SYI_item_data)
362             + 4 /* For JPI$_FINALEXC */];
363     } data;
364     size_t total_elems = 0;
365     size_t total_length = 0;
366     size_t bytes_needed = ossl_rand_pool_bytes_needed(pool, ENTROPY_FACTOR);
367     size_t bytes_remaining = ossl_rand_pool_bytes_remaining(pool);
368 
369     /* Take all the 64-bit items first, to ensure proper alignment of data */
370     total_elems += prepare_item_list(JPI_item_data_64bit, OSSL_NELEM(JPI_item_data_64bit),
371         JPI_items_64bit, &data.buffer[total_elems]);
372     total_elems += prepare_item_list(RMI_item_data_64bit, OSSL_NELEM(RMI_item_data_64bit),
373         RMI_items_64bit, &data.buffer[total_elems]);
374     /* Now the 32-bit items */
375     total_elems += prepare_item_list(DVI_item_data, OSSL_NELEM(DVI_item_data),
376         DVI_items, &data.buffer[total_elems]);
377     total_elems += prepare_item_list(JPI_item_data, OSSL_NELEM(JPI_item_data),
378         JPI_items, &data.buffer[total_elems]);
379     total_elems += prepare_item_list(RMI_item_data, OSSL_NELEM(RMI_item_data),
380         RMI_items, &data.buffer[total_elems]);
381     total_elems += prepare_item_list(SYI_item_data, OSSL_NELEM(SYI_item_data),
382         SYI_items, &data.buffer[total_elems]);
383     total_length = total_elems * sizeof(data.buffer[0]);
384 
385     /* Fill data.buffer with various info bits from this process */
386     {
387         uint32_t status;
388         uint32_t efn;
389         IOSB iosb;
390         $DESCRIPTOR(SYSDEVICE, "SYS$SYSDEVICE:");
391 
392         if ((status = sys$getdviw(EFN$C_ENF, 0, &SYSDEVICE, DVI_items,
393                  0, 0, 0, 0, 0))
394             != SS$_NORMAL) {
395             lib$signal(status);
396             return 0;
397         }
398         if ((status = sys$getjpiw(EFN$C_ENF, 0, 0, JPI_items_64bit, 0, 0, 0))
399             != SS$_NORMAL) {
400             lib$signal(status);
401             return 0;
402         }
403         if ((status = sys$getjpiw(EFN$C_ENF, 0, 0, JPI_items, 0, 0, 0))
404             != SS$_NORMAL) {
405             lib$signal(status);
406             return 0;
407         }
408         if ((status = sys$getsyiw(EFN$C_ENF, 0, 0, SYI_items, 0, 0, 0))
409             != SS$_NORMAL) {
410             lib$signal(status);
411             return 0;
412         }
413         /*
414          * The RMI service is a bit special, as there is no synchronous
415          * variant, so we MUST create an event flag to synchronise on.
416          */
417         if ((status = lib$get_ef(&efn)) != SS$_NORMAL) {
418             lib$signal(status);
419             return 0;
420         }
421         if ((status = sys$getrmi(efn, 0, 0, RMI_items_64bit, &iosb, 0, 0))
422             != SS$_NORMAL) {
423             lib$signal(status);
424             return 0;
425         }
426         if ((status = sys$synch(efn, &iosb)) != SS$_NORMAL) {
427             lib$signal(status);
428             return 0;
429         }
430         if (iosb.iosb$l_getxxi_status != SS$_NORMAL) {
431             lib$signal(iosb.iosb$l_getxxi_status);
432             return 0;
433         }
434         if ((status = sys$getrmi(efn, 0, 0, RMI_items, &iosb, 0, 0))
435             != SS$_NORMAL) {
436             lib$signal(status);
437             return 0;
438         }
439         if ((status = sys$synch(efn, &iosb)) != SS$_NORMAL) {
440             lib$signal(status);
441             return 0;
442         }
443         if (iosb.iosb$l_getxxi_status != SS$_NORMAL) {
444             lib$signal(iosb.iosb$l_getxxi_status);
445             return 0;
446         }
447         if ((status = lib$free_ef(&efn)) != SS$_NORMAL) {
448             lib$signal(status);
449             return 0;
450         }
451     }
452 
453     massage_JPI(JPI_items);
454 
455     /*
456      * If we can't feed the requirements from the caller, we're in deep trouble.
457      */
458     if (!ossl_assert(total_length >= bytes_needed)) {
459         ERR_raise_data(ERR_LIB_RAND, RAND_R_RANDOM_POOL_UNDERFLOW,
460             "Needed: %zu, Available: %zu",
461             bytes_needed, total_length);
462         return 0;
463     }
464 
465     /*
466      * Try not to overfeed the pool
467      */
468     if (total_length > bytes_remaining)
469         total_length = bytes_remaining;
470 
471     /* We give the pessimistic value for the amount of entropy */
472     ossl_rand_pool_add(pool, (unsigned char *)data.buffer, total_length,
473         8 * total_length / ENTROPY_FACTOR);
474     return ossl_rand_pool_entropy_available(pool);
475 }
476 
477 /*
478  * SYS$GET_ENTROPY METHOD
479  * ======================
480  *
481  * This is a high entropy method based on a new system service that is
482  * based on getentropy() from FreeBSD 12.  It's only used if available,
483  * and its availability is detected at run-time.
484  *
485  * We assume that this function provides full entropy random output.
486  */
487 #define PUBLIC_VECTORS "SYS$LIBRARY:SYS$PUBLIC_VECTORS.EXE"
488 #define GET_ENTROPY "SYS$GET_ENTROPY"
489 
490 static int get_entropy_address_flag = 0;
491 static int (*get_entropy_address)(void *buffer, size_t buffer_size) = NULL;
init_get_entropy_address(void)492 static int init_get_entropy_address(void)
493 {
494     if (get_entropy_address_flag == 0)
495         get_entropy_address = dlsym(dlopen(PUBLIC_VECTORS, 0), GET_ENTROPY);
496     get_entropy_address_flag = 1;
497     return get_entropy_address != NULL;
498 }
499 
get_entropy_method(RAND_POOL * pool)500 size_t get_entropy_method(RAND_POOL *pool)
501 {
502     /*
503      * The documentation says that SYS$GET_ENTROPY will give a maximum of
504      * 256 bytes of data.
505      */
506     unsigned char buffer[256];
507     size_t bytes_needed;
508     size_t bytes_to_get = 0;
509     uint32_t status;
510 
511     for (bytes_needed = ossl_rand_pool_bytes_needed(pool, 1);
512         bytes_needed > 0;
513         bytes_needed -= bytes_to_get) {
514         bytes_to_get = bytes_needed > sizeof(buffer) ? sizeof(buffer) : bytes_needed;
515 
516         status = get_entropy_address(buffer, bytes_to_get);
517         if (status == SS$_RETRY) {
518             /* Set to zero so the loop doesn't diminish |bytes_needed| */
519             bytes_to_get = 0;
520             /* Should sleep some amount of time */
521             continue;
522         }
523 
524         if (status != SS$_NORMAL) {
525             lib$signal(status);
526             return 0;
527         }
528 
529         ossl_rand_pool_add(pool, buffer, bytes_to_get, 8 * bytes_to_get);
530     }
531 
532     return ossl_rand_pool_entropy_available(pool);
533 }
534 
535 /*
536  * MAIN ENTROPY ACQUISITION FUNCTIONS
537  * ==================================
538  *
539  * These functions are called by the RAND / DRBG functions
540  */
541 
ossl_pool_acquire_entropy(RAND_POOL * pool)542 size_t ossl_pool_acquire_entropy(RAND_POOL *pool)
543 {
544     if (init_get_entropy_address())
545         return get_entropy_method(pool);
546     return data_collect_method(pool);
547 }
548 
ossl_pool_add_nonce_data(RAND_POOL * pool)549 int ossl_pool_add_nonce_data(RAND_POOL *pool)
550 {
551     /*
552      * Two variables to ensure that two nonces won't ever be the same
553      */
554     static unsigned __int64 last_time = 0;
555     static unsigned __int32 last_seq = 0;
556 
557     struct {
558         pid_t pid;
559         CRYPTO_THREAD_ID tid;
560         unsigned __int64 time;
561         unsigned __int32 seq;
562     } data;
563 
564     /* Erase the entire structure including any padding */
565     memset(&data, 0, sizeof(data));
566 
567     /*
568      * Add process id, thread id, a timestamp, and a sequence number in case
569      * the same time stamp is repeated, to ensure that the nonce is unique
570      * with high probability for different process instances.
571      *
572      * The normal OpenVMS time is specified to be high granularity (100ns),
573      * but the time update granularity given by sys$gettim() may be lower.
574      *
575      * OpenVMS version 8.4 (which is the latest for Alpha and Itanium) and
576      * on have sys$gettim_prec() as well, which is supposedly having a better
577      * time update granularity, but tests on Itanium (and even Alpha) have
578      * shown that compared with sys$gettim(), the difference is marginal,
579      * so of very little significance in terms of entropy.
580      * Given that, and that it's a high ask to expect everyone to have
581      * upgraded to OpenVMS version 8.4, only sys$gettim() is used, and a
582      * sequence number is added as well, in case sys$gettim() returns the
583      * same time value more than once.
584      *
585      * This function is assumed to be called under thread lock, and does
586      * therefore not take concurrency into account.
587      */
588     data.pid = getpid();
589     data.tid = CRYPTO_THREAD_get_current_id();
590     data.seq = 0;
591     sys$gettim((void *)&data.time);
592 
593     if (data.time == last_time) {
594         data.seq = ++last_seq;
595     } else {
596         last_time = data.time;
597         last_seq = 0;
598     }
599 
600     return ossl_rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0);
601 }
602 
ossl_rand_pool_init(void)603 int ossl_rand_pool_init(void)
604 {
605     return 1;
606 }
607 
ossl_rand_pool_cleanup(void)608 void ossl_rand_pool_cleanup(void)
609 {
610 }
611 
ossl_rand_pool_keep_random_devices_open(int keep)612 void ossl_rand_pool_keep_random_devices_open(int keep)
613 {
614 }
615