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