Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/openssl/providers/implementations/rands/seeding/rand_vms.c
108728 views
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
*/
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
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
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;
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
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
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
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
603
int ossl_rand_pool_init(void)
604
{
605
return 1;
606
}
607
608
void ossl_rand_pool_cleanup(void)
609
{
610
}
611
612
void ossl_rand_pool_keep_random_devices_open(int keep)
613
{
614
}
615
616