VirtualBox

source: vbox/trunk/src/libs/openssl-1.1.1k/crypto/rand/rand_vms.c@ 90293

Last change on this file since 90293 was 90293, checked in by vboxsync, 4 years ago

openssl-1.1.1k: Applied and adjusted our OpenSSL changes to 1.1.1k. bugref:10072

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