VirtualBox

source: vbox/trunk/src/libs/openssl-3.1.0/providers/implementations/rands/seeding/rand_vms.c@ 100947

Last change on this file since 100947 was 99366, checked in by vboxsync, 22 months ago

openssl-3.1.0: Applied and adjusted our OpenSSL changes to 3.0.7. bugref:10418

File size: 18.1 KB
Line 
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
56typedef uint32_t *uint32_t__ptr32;
57#if __INITIAL_POINTER_SIZE == 64
58# pragma pointer_size restore
59#endif
60
61struct item_st {
62 short length, code; /* length is number of bytes */
63};
64
65static const struct item_st DVI_item_data[] = {
66 {4, DVI$_ERRCNT},
67 {4, DVI$_REFCNT},
68};
69
70static 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
87static const struct item_st JPI_item_data_64bit[] = {
88 {8, JPI$_LAST_LOGIN_I},
89 {8, JPI$_LOGINTIM},
90};
91
92static 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
242static 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
266static 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 */
283static 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
312static 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
345size_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 +=
371 prepare_item_list(JPI_item_data_64bit, OSSL_NELEM(JPI_item_data_64bit),
372 JPI_items_64bit, &data.buffer[total_elems]);
373 total_elems +=
374 prepare_item_list(RMI_item_data_64bit, OSSL_NELEM(RMI_item_data_64bit),
375 RMI_items_64bit, &data.buffer[total_elems]);
376 /* Now the 32-bit items */
377 total_elems += prepare_item_list(DVI_item_data, OSSL_NELEM(DVI_item_data),
378 DVI_items, &data.buffer[total_elems]);
379 total_elems += prepare_item_list(JPI_item_data, OSSL_NELEM(JPI_item_data),
380 JPI_items, &data.buffer[total_elems]);
381 total_elems += prepare_item_list(RMI_item_data, OSSL_NELEM(RMI_item_data),
382 RMI_items, &data.buffer[total_elems]);
383 total_elems += prepare_item_list(SYI_item_data, OSSL_NELEM(SYI_item_data),
384 SYI_items, &data.buffer[total_elems]);
385 total_length = total_elems * sizeof(data.buffer[0]);
386
387 /* Fill data.buffer with various info bits from this process */
388 {
389 uint32_t status;
390 uint32_t efn;
391 IOSB iosb;
392 $DESCRIPTOR(SYSDEVICE,"SYS$SYSDEVICE:");
393
394 if ((status = sys$getdviw(EFN$C_ENF, 0, &SYSDEVICE, DVI_items,
395 0, 0, 0, 0, 0)) != SS$_NORMAL) {
396 lib$signal(status);
397 return 0;
398 }
399 if ((status = sys$getjpiw(EFN$C_ENF, 0, 0, JPI_items_64bit, 0, 0, 0))
400 != SS$_NORMAL) {
401 lib$signal(status);
402 return 0;
403 }
404 if ((status = sys$getjpiw(EFN$C_ENF, 0, 0, JPI_items, 0, 0, 0))
405 != SS$_NORMAL) {
406 lib$signal(status);
407 return 0;
408 }
409 if ((status = sys$getsyiw(EFN$C_ENF, 0, 0, SYI_items, 0, 0, 0))
410 != SS$_NORMAL) {
411 lib$signal(status);
412 return 0;
413 }
414 /*
415 * The RMI service is a bit special, as there is no synchronous
416 * variant, so we MUST create an event flag to synchronise on.
417 */
418 if ((status = lib$get_ef(&efn)) != SS$_NORMAL) {
419 lib$signal(status);
420 return 0;
421 }
422 if ((status = sys$getrmi(efn, 0, 0, RMI_items_64bit, &iosb, 0, 0))
423 != SS$_NORMAL) {
424 lib$signal(status);
425 return 0;
426 }
427 if ((status = sys$synch(efn, &iosb)) != SS$_NORMAL) {
428 lib$signal(status);
429 return 0;
430 }
431 if (iosb.iosb$l_getxxi_status != SS$_NORMAL) {
432 lib$signal(iosb.iosb$l_getxxi_status);
433 return 0;
434 }
435 if ((status = sys$getrmi(efn, 0, 0, RMI_items, &iosb, 0, 0))
436 != SS$_NORMAL) {
437 lib$signal(status);
438 return 0;
439 }
440 if ((status = sys$synch(efn, &iosb)) != SS$_NORMAL) {
441 lib$signal(status);
442 return 0;
443 }
444 if (iosb.iosb$l_getxxi_status != SS$_NORMAL) {
445 lib$signal(iosb.iosb$l_getxxi_status);
446 return 0;
447 }
448 if ((status = lib$free_ef(&efn)) != SS$_NORMAL) {
449 lib$signal(status);
450 return 0;
451 }
452 }
453
454 massage_JPI(JPI_items);
455
456 /*
457 * If we can't feed the requirements from the caller, we're in deep trouble.
458 */
459 if (!ossl_assert(total_length >= bytes_needed)) {
460 ERR_raise_data(ERR_LIB_RAND, RAND_R_RANDOM_POOL_UNDERFLOW,
461 "Needed: %zu, Available: %zu",
462 bytes_needed, total_length);
463 return 0;
464 }
465
466 /*
467 * Try not to overfeed the pool
468 */
469 if (total_length > bytes_remaining)
470 total_length = bytes_remaining;
471
472 /* We give the pessimistic value for the amount of entropy */
473 ossl_rand_pool_add(pool, (unsigned char *)data.buffer, total_length,
474 8 * total_length / ENTROPY_FACTOR);
475 return ossl_rand_pool_entropy_available(pool);
476}
477
478/*
479 * SYS$GET_ENTROPY METHOD
480 * ======================
481 *
482 * This is a high entropy method based on a new system service that is
483 * based on getentropy() from FreeBSD 12. It's only used if available,
484 * and its availability is detected at run-time.
485 *
486 * We assume that this function provides full entropy random output.
487 */
488#define PUBLIC_VECTORS "SYS$LIBRARY:SYS$PUBLIC_VECTORS.EXE"
489#define GET_ENTROPY "SYS$GET_ENTROPY"
490
491static int get_entropy_address_flag = 0;
492static int (*get_entropy_address)(void *buffer, size_t buffer_size) = NULL;
493static int init_get_entropy_address(void)
494{
495 if (get_entropy_address_flag == 0)
496 get_entropy_address = dlsym(dlopen(PUBLIC_VECTORS, 0), GET_ENTROPY);
497 get_entropy_address_flag = 1;
498 return get_entropy_address != NULL;
499}
500
501size_t get_entropy_method(RAND_POOL *pool)
502{
503 /*
504 * The documentation says that SYS$GET_ENTROPY will give a maximum of
505 * 256 bytes of data.
506 */
507 unsigned char buffer[256];
508 size_t bytes_needed;
509 size_t bytes_to_get = 0;
510 uint32_t status;
511
512 for (bytes_needed = ossl_rand_pool_bytes_needed(pool, 1);
513 bytes_needed > 0;
514 bytes_needed -= bytes_to_get) {
515 bytes_to_get =
516 bytes_needed > sizeof(buffer) ? sizeof(buffer) : bytes_needed;
517
518 status = get_entropy_address(buffer, bytes_to_get);
519 if (status == SS$_RETRY) {
520 /* Set to zero so the loop doesn't diminish |bytes_needed| */
521 bytes_to_get = 0;
522 /* Should sleep some amount of time */
523 continue;
524 }
525
526 if (status != SS$_NORMAL) {
527 lib$signal(status);
528 return 0;
529 }
530
531 ossl_rand_pool_add(pool, buffer, bytes_to_get, 8 * bytes_to_get);
532 }
533
534 return ossl_rand_pool_entropy_available(pool);
535}
536
537/*
538 * MAIN ENTROPY ACQUISITION FUNCTIONS
539 * ==================================
540 *
541 * These functions are called by the RAND / DRBG functions
542 */
543
544size_t ossl_pool_acquire_entropy(RAND_POOL *pool)
545{
546 if (init_get_entropy_address())
547 return get_entropy_method(pool);
548 return data_collect_method(pool);
549}
550
551int ossl_pool_add_nonce_data(RAND_POOL *pool)
552{
553 /*
554 * Two variables to ensure that two nonces won't ever be the same
555 */
556 static unsigned __int64 last_time = 0;
557 static unsigned __int32 last_seq = 0;
558
559 struct {
560 pid_t pid;
561 CRYPTO_THREAD_ID tid;
562 unsigned __int64 time;
563 unsigned __int32 seq;
564 } data;
565
566 /* Erase the entire structure including any padding */
567 memset(&data, 0, sizeof(data));
568
569 /*
570 * Add process id, thread id, a timestamp, and a sequence number in case
571 * the same time stamp is repeated, to ensure that the nonce is unique
572 * with high probability for different process instances.
573 *
574 * The normal OpenVMS time is specified to be high granularity (100ns),
575 * but the time update granularity given by sys$gettim() may be lower.
576 *
577 * OpenVMS version 8.4 (which is the latest for Alpha and Itanium) and
578 * on have sys$gettim_prec() as well, which is supposedly having a better
579 * time update granularity, but tests on Itanium (and even Alpha) have
580 * shown that compared with sys$gettim(), the difference is marginal,
581 * so of very little significance in terms of entropy.
582 * Given that, and that it's a high ask to expect everyone to have
583 * upgraded to OpenVMS version 8.4, only sys$gettim() is used, and a
584 * sequence number is added as well, in case sys$gettim() returns the
585 * same time value more than once.
586 *
587 * This function is assumed to be called under thread lock, and does
588 * therefore not take concurrency into account.
589 */
590 data.pid = getpid();
591 data.tid = CRYPTO_THREAD_get_current_id();
592 data.seq = 0;
593 sys$gettim((void*)&data.time);
594
595 if (data.time == last_time) {
596 data.seq = ++last_seq;
597 } else {
598 last_time = data.time;
599 last_seq = 0;
600 }
601
602 return ossl_rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0);
603}
604
605int ossl_rand_pool_init(void)
606{
607 return 1;
608}
609
610void ossl_rand_pool_cleanup(void)
611{
612}
613
614void ossl_rand_pool_keep_random_devices_open(int keep)
615{
616}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette