a00f83bcc4911402a95a965c0bae62442941d8b2
[openssl.git] / crypto / rand / rand_vms.c
1 /*
2  * Copyright 2001-2021 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
57 typedef uint32_t *uint32_t__ptr32;
58 # if __INITIAL_POINTER_SIZE == 64
59 #  pragma pointer_size restore
60 # endif
61
62 struct item_st {
63     short length, code;         /* length is number of bytes */
64 };
65
66 static const struct item_st DVI_item_data[] = {
67     {4,   DVI$_ERRCNT},
68     {4,   DVI$_REFCNT},
69 };
70
71 static 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
88 static const struct item_st JPI_item_data_64bit[] = {
89     {8,   JPI$_LAST_LOGIN_I},
90     {8,   JPI$_LOGINTIM},
91 };
92
93 static 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
243 static 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
267 static 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  */
284 static 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
313 static 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
346 size_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
482 int rand_pool_add_nonce_data(RAND_POOL *pool)
483 {
484     struct {
485         pid_t pid;
486         CRYPTO_THREAD_ID tid;
487         unsigned __int64 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
520 static int get_entropy_address_flag = 0;
521 static int (*get_entropy_address)(void *buffer, size_t buffer_size) = NULL;
522 static 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
530 size_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
573 size_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
581 int rand_pool_add_additional_data(RAND_POOL *pool)
582 {
583     struct {
584         CRYPTO_THREAD_ID tid;
585         unsigned __int64 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
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 }
615
616 #endif