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 "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 "crypto/rand_pool.h"
18#include "prov/seeding.h"
19#include <descrip.h>
20#include <dvidef.h>
21#include <jpidef.h>
22#include <rmidef.h>
23#include <syidef.h>
24#include <ssdef.h>
25#include <starlet.h>
26#include <efndef.h>
27#include <gen64def.h>
28#include <iosbdef.h>
29#include <iledef.h>
30#include <lib$routines.h>
31#ifdef __DECC
32# pragma message disable DOLLARID
33#endif
34
35#include <dlfcn.h>              /* SYS$GET_ENTROPY presence */
36
37#ifndef OPENSSL_RAND_SEED_OS
38# error "Unsupported seeding method configured; must be os"
39#endif
40
41/*
42 * DATA COLLECTION METHOD
43 * ======================
44 *
45 * This is a method to get low quality entropy.
46 * It works by collecting all kinds of statistical data that
47 * VMS offers and using them as random seed.
48 */
49
50/* We need to make sure we have the right size pointer in some cases */
51#if __INITIAL_POINTER_SIZE == 64
52# pragma pointer_size save
53# pragma pointer_size 32
54#endif
55typedef uint32_t *uint32_t__ptr32;
56#if __INITIAL_POINTER_SIZE == 64
57# pragma pointer_size restore
58#endif
59
60struct item_st {
61    short length, code;         /* length is number of bytes */
62};
63
64static const struct item_st DVI_item_data[] = {
65    {4,   DVI$_ERRCNT},
66    {4,   DVI$_REFCNT},
67};
68
69static const struct item_st JPI_item_data[] = {
70    {4,   JPI$_BUFIO},
71    {4,   JPI$_CPUTIM},
72    {4,   JPI$_DIRIO},
73    {4,   JPI$_IMAGECOUNT},
74    {4,   JPI$_PAGEFLTS},
75    {4,   JPI$_PID},
76    {4,   JPI$_PPGCNT},
77    {4,   JPI$_WSPEAK},
78    /*
79     * Note: the direct result is just a 32-bit address.  However, it points
80     * to a list of 4 32-bit words, so we make extra space for them so we can
81     * do in-place replacement of values
82     */
83    {16,  JPI$_FINALEXC},
84};
85
86static const struct item_st JPI_item_data_64bit[] = {
87    {8,   JPI$_LAST_LOGIN_I},
88    {8,   JPI$_LOGINTIM},
89};
90
91static const struct item_st RMI_item_data[] = {
92    {4,   RMI$_COLPG},
93    {4,   RMI$_MWAIT},
94    {4,   RMI$_CEF},
95    {4,   RMI$_PFW},
96    {4,   RMI$_LEF},
97    {4,   RMI$_LEFO},
98    {4,   RMI$_HIB},
99    {4,   RMI$_HIBO},
100    {4,   RMI$_SUSP},
101    {4,   RMI$_SUSPO},
102    {4,   RMI$_FPG},
103    {4,   RMI$_COM},
104    {4,   RMI$_COMO},
105    {4,   RMI$_CUR},
106#if defined __alpha
107    {4,   RMI$_FRLIST},
108    {4,   RMI$_MODLIST},
109#endif
110    {4,   RMI$_FAULTS},
111    {4,   RMI$_PREADS},
112    {4,   RMI$_PWRITES},
113    {4,   RMI$_PWRITIO},
114    {4,   RMI$_PREADIO},
115    {4,   RMI$_GVALFLTS},
116    {4,   RMI$_WRTINPROG},
117    {4,   RMI$_FREFLTS},
118    {4,   RMI$_DZROFLTS},
119    {4,   RMI$_SYSFAULTS},
120    {4,   RMI$_ISWPCNT},
121    {4,   RMI$_DIRIO},
122    {4,   RMI$_BUFIO},
123    {4,   RMI$_MBREADS},
124    {4,   RMI$_MBWRITES},
125    {4,   RMI$_LOGNAM},
126    {4,   RMI$_FCPCALLS},
127    {4,   RMI$_FCPREAD},
128    {4,   RMI$_FCPWRITE},
129    {4,   RMI$_FCPCACHE},
130    {4,   RMI$_FCPCPU},
131    {4,   RMI$_FCPHIT},
132    {4,   RMI$_FCPSPLIT},
133    {4,   RMI$_FCPFAULT},
134    {4,   RMI$_ENQNEW},
135    {4,   RMI$_ENQCVT},
136    {4,   RMI$_DEQ},
137    {4,   RMI$_BLKAST},
138    {4,   RMI$_ENQWAIT},
139    {4,   RMI$_ENQNOTQD},
140    {4,   RMI$_DLCKSRCH},
141    {4,   RMI$_DLCKFND},
142    {4,   RMI$_NUMLOCKS},
143    {4,   RMI$_NUMRES},
144    {4,   RMI$_ARRLOCPK},
145    {4,   RMI$_DEPLOCPK},
146    {4,   RMI$_ARRTRAPK},
147    {4,   RMI$_TRCNGLOS},
148    {4,   RMI$_RCVBUFFL},
149    {4,   RMI$_ENQNEWLOC},
150    {4,   RMI$_ENQNEWIN},
151    {4,   RMI$_ENQNEWOUT},
152    {4,   RMI$_ENQCVTLOC},
153    {4,   RMI$_ENQCVTIN},
154    {4,   RMI$_ENQCVTOUT},
155    {4,   RMI$_DEQLOC},
156    {4,   RMI$_DEQIN},
157    {4,   RMI$_DEQOUT},
158    {4,   RMI$_BLKLOC},
159    {4,   RMI$_BLKIN},
160    {4,   RMI$_BLKOUT},
161    {4,   RMI$_DIRIN},
162    {4,   RMI$_DIROUT},
163    /* We currently get a fault when trying these */
164#if 0
165    {140, RMI$_MSCP_EVERYTHING},   /* 35 32-bit words */
166    {152, RMI$_DDTM_ALL},          /* 38 32-bit words */
167    {80,  RMI$_TMSCP_EVERYTHING}   /* 20 32-bit words */
168#endif
169    {4,   RMI$_LPZ_PAGCNT},
170    {4,   RMI$_LPZ_HITS},
171    {4,   RMI$_LPZ_MISSES},
172    {4,   RMI$_LPZ_EXPCNT},
173    {4,   RMI$_LPZ_ALLOCF},
174    {4,   RMI$_LPZ_ALLOC2},
175    {4,   RMI$_ACCESS},
176    {4,   RMI$_ALLOC},
177    {4,   RMI$_FCPCREATE},
178    {4,   RMI$_VOLWAIT},
179    {4,   RMI$_FCPTURN},
180    {4,   RMI$_FCPERASE},
181    {4,   RMI$_OPENS},
182    {4,   RMI$_FIDHIT},
183    {4,   RMI$_FIDMISS},
184    {4,   RMI$_FILHDR_HIT},
185    {4,   RMI$_DIRFCB_HIT},
186    {4,   RMI$_DIRFCB_MISS},
187    {4,   RMI$_DIRDATA_HIT},
188    {4,   RMI$_EXTHIT},
189    {4,   RMI$_EXTMISS},
190    {4,   RMI$_QUOHIT},
191    {4,   RMI$_QUOMISS},
192    {4,   RMI$_STORAGMAP_HIT},
193    {4,   RMI$_VOLLCK},
194    {4,   RMI$_SYNCHLCK},
195    {4,   RMI$_SYNCHWAIT},
196    {4,   RMI$_ACCLCK},
197    {4,   RMI$_XQPCACHEWAIT},
198    {4,   RMI$_DIRDATA_MISS},
199    {4,   RMI$_FILHDR_MISS},
200    {4,   RMI$_STORAGMAP_MISS},
201    {4,   RMI$_PROCCNTMAX},
202    {4,   RMI$_PROCBATCNT},
203    {4,   RMI$_PROCINTCNT},
204    {4,   RMI$_PROCNETCNT},
205    {4,   RMI$_PROCSWITCHCNT},
206    {4,   RMI$_PROCBALSETCNT},
207    {4,   RMI$_PROCLOADCNT},
208    {4,   RMI$_BADFLTS},
209    {4,   RMI$_EXEFAULTS},
210    {4,   RMI$_HDRINSWAPS},
211    {4,   RMI$_HDROUTSWAPS},
212    {4,   RMI$_IOPAGCNT},
213    {4,   RMI$_ISWPCNTPG},
214    {4,   RMI$_OSWPCNT},
215    {4,   RMI$_OSWPCNTPG},
216    {4,   RMI$_RDFAULTS},
217    {4,   RMI$_TRANSFLTS},
218    {4,   RMI$_WRTFAULTS},
219#if defined __alpha
220    {4,   RMI$_USERPAGES},
221#endif
222    {4,   RMI$_VMSPAGES},
223    {4,   RMI$_TTWRITES},
224    {4,   RMI$_BUFOBJPAG},
225    {4,   RMI$_BUFOBJPAGPEAK},
226    {4,   RMI$_BUFOBJPAGS01},
227    {4,   RMI$_BUFOBJPAGS2},
228    {4,   RMI$_BUFOBJPAGMAXS01},
229    {4,   RMI$_BUFOBJPAGMAXS2},
230    {4,   RMI$_BUFOBJPAGPEAKS01},
231    {4,   RMI$_BUFOBJPAGPEAKS2},
232    {4,   RMI$_BUFOBJPGLTMAXS01},
233    {4,   RMI$_BUFOBJPGLTMAXS2},
234    {4,   RMI$_DLCK_INCMPLT},
235    {4,   RMI$_DLCKMSGS_IN},
236    {4,   RMI$_DLCKMSGS_OUT},
237    {4,   RMI$_MCHKERRS},
238    {4,   RMI$_MEMERRS},
239};
240
241static const struct item_st RMI_item_data_64bit[] = {
242#if defined __ia64
243    {8,   RMI$_FRLIST},
244    {8,   RMI$_MODLIST},
245#endif
246    {8,   RMI$_LCKMGR_REQCNT},
247    {8,   RMI$_LCKMGR_REQTIME},
248    {8,   RMI$_LCKMGR_SPINCNT},
249    {8,   RMI$_LCKMGR_SPINTIME},
250    {8,   RMI$_CPUINTSTK},
251    {8,   RMI$_CPUMPSYNCH},
252    {8,   RMI$_CPUKERNEL},
253    {8,   RMI$_CPUEXEC},
254    {8,   RMI$_CPUSUPER},
255    {8,   RMI$_CPUUSER},
256#if defined __ia64
257    {8,   RMI$_USERPAGES},
258#endif
259    {8,   RMI$_TQETOTAL},
260    {8,   RMI$_TQESYSUB},
261    {8,   RMI$_TQEUSRTIMR},
262    {8,   RMI$_TQEUSRWAKE},
263};
264
265static const struct item_st SYI_item_data[] = {
266    {4,   SYI$_PAGEFILE_FREE},
267};
268
269/*
270 * Input:
271 * items_data           - an array of lengths and codes
272 * items_data_num       - number of elements in that array
273 *
274 * Output:
275 * items                - pre-allocated ILE3 array to be filled.
276 *                        It's assumed to have items_data_num elements plus
277 *                        one extra for the terminating NULL element
278 * databuffer           - pre-allocated 32-bit word array.
279 *
280 * Returns the number of elements used in databuffer
281 */
282static size_t prepare_item_list(const struct item_st *items_input,
283                                size_t items_input_num,
284                                ILE3 *items,
285                                uint32_t__ptr32 databuffer)
286{
287    size_t data_sz = 0;
288
289    for (; items_input_num-- > 0; items_input++, items++) {
290
291        items->ile3$w_code = items_input->code;
292        /* Special treatment of JPI$_FINALEXC */
293        if (items->ile3$w_code == JPI$_FINALEXC)
294            items->ile3$w_length = 4;
295        else
296            items->ile3$w_length = items_input->length;
297
298        items->ile3$ps_bufaddr = databuffer;
299        items->ile3$ps_retlen_addr = 0;
300
301        databuffer += items_input->length / sizeof(databuffer[0]);
302        data_sz += items_input->length;
303    }
304    /* Terminating NULL entry */
305    items->ile3$w_length = items->ile3$w_code = 0;
306    items->ile3$ps_bufaddr = items->ile3$ps_retlen_addr = NULL;
307
308    return data_sz / sizeof(databuffer[0]);
309}
310
311static void massage_JPI(ILE3 *items)
312{
313    /*
314     * Special treatment of JPI$_FINALEXC
315     * The result of that item's data buffer is a 32-bit address to a list of
316     * 4 32-bit words.
317     */
318    for (; items->ile3$w_length != 0; items++) {
319        if (items->ile3$w_code == JPI$_FINALEXC) {
320            uint32_t *data = items->ile3$ps_bufaddr;
321            uint32_t *ptr = (uint32_t *)*data;
322            size_t j;
323
324            /*
325             * We know we made space for 4 32-bit words, so we can do in-place
326             * replacement.
327             */
328            for (j = 0; j < 4; j++)
329                data[j] = ptr[j];
330
331            break;
332        }
333    }
334}
335
336/*
337 * This number expresses how many bits of data contain 1 bit of entropy.
338 *
339 * For the moment, we assume about 0.05 entropy bits per data bit, or 1
340 * bit of entropy per 20 data bits.
341 */
342#define ENTROPY_FACTOR  20
343
344size_t data_collect_method(RAND_POOL *pool)
345{
346    ILE3 JPI_items_64bit[OSSL_NELEM(JPI_item_data_64bit) + 1];
347    ILE3 RMI_items_64bit[OSSL_NELEM(RMI_item_data_64bit) + 1];
348    ILE3 DVI_items[OSSL_NELEM(DVI_item_data) + 1];
349    ILE3 JPI_items[OSSL_NELEM(JPI_item_data) + 1];
350    ILE3 RMI_items[OSSL_NELEM(RMI_item_data) + 1];
351    ILE3 SYI_items[OSSL_NELEM(SYI_item_data) + 1];
352    union {
353        /* This ensures buffer starts at 64 bit boundary */
354        uint64_t dummy;
355        uint32_t buffer[OSSL_NELEM(JPI_item_data_64bit) * 2
356                        + OSSL_NELEM(RMI_item_data_64bit) * 2
357                        + OSSL_NELEM(DVI_item_data)
358                        + OSSL_NELEM(JPI_item_data)
359                        + OSSL_NELEM(RMI_item_data)
360                        + OSSL_NELEM(SYI_item_data)
361                        + 4 /* For JPI$_FINALEXC */];
362    } data;
363    size_t total_elems = 0;
364    size_t total_length = 0;
365    size_t bytes_needed = ossl_rand_pool_bytes_needed(pool, ENTROPY_FACTOR);
366    size_t bytes_remaining = ossl_rand_pool_bytes_remaining(pool);
367
368    /* Take all the 64-bit items first, to ensure proper alignment of data */
369    total_elems +=
370        prepare_item_list(JPI_item_data_64bit, OSSL_NELEM(JPI_item_data_64bit),
371                          JPI_items_64bit, &data.buffer[total_elems]);
372    total_elems +=
373        prepare_item_list(RMI_item_data_64bit, OSSL_NELEM(RMI_item_data_64bit),
374                          RMI_items_64bit, &data.buffer[total_elems]);
375    /* Now the 32-bit items */
376    total_elems += prepare_item_list(DVI_item_data, OSSL_NELEM(DVI_item_data),
377                                     DVI_items, &data.buffer[total_elems]);
378    total_elems += prepare_item_list(JPI_item_data, OSSL_NELEM(JPI_item_data),
379                                     JPI_items, &data.buffer[total_elems]);
380    total_elems += prepare_item_list(RMI_item_data, OSSL_NELEM(RMI_item_data),
381                                     RMI_items, &data.buffer[total_elems]);
382    total_elems += prepare_item_list(SYI_item_data, OSSL_NELEM(SYI_item_data),
383                                     SYI_items, &data.buffer[total_elems]);
384    total_length = total_elems * sizeof(data.buffer[0]);
385
386    /* Fill data.buffer with various info bits from this process */
387    {
388        uint32_t status;
389        uint32_t efn;
390        IOSB iosb;
391        $DESCRIPTOR(SYSDEVICE,"SYS$SYSDEVICE:");
392
393        if ((status = sys$getdviw(EFN$C_ENF, 0, &SYSDEVICE, DVI_items,
394                                  0, 0, 0, 0, 0)) != 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
490static int get_entropy_address_flag = 0;
491static int (*get_entropy_address)(void *buffer, size_t buffer_size) = NULL;
492static 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
500size_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 =
515            bytes_needed > sizeof(buffer) ? sizeof(buffer) : bytes_needed;
516
517        status = get_entropy_address(buffer, bytes_to_get);
518        if (status == SS$_RETRY) {
519            /* Set to zero so the loop doesn't diminish |bytes_needed| */
520            bytes_to_get = 0;
521            /* Should sleep some amount of time */
522            continue;
523        }
524
525        if (status != SS$_NORMAL) {
526            lib$signal(status);
527            return 0;
528        }
529
530        ossl_rand_pool_add(pool, buffer, bytes_to_get, 8 * bytes_to_get);
531    }
532
533    return ossl_rand_pool_entropy_available(pool);
534}
535
536/*
537 * MAIN ENTROPY ACQUISITION FUNCTIONS
538 * ==================================
539 *
540 * These functions are called by the RAND / DRBG functions
541 */
542
543size_t ossl_pool_acquire_entropy(RAND_POOL *pool)
544{
545    if (init_get_entropy_address())
546        return get_entropy_method(pool);
547    return data_collect_method(pool);
548}
549
550int ossl_pool_add_nonce_data(RAND_POOL *pool)
551{
552    /*
553     * Two variables to ensure that two nonces won't ever be the same
554     */
555    static unsigned __int64 last_time = 0;
556    static unsigned __int32 last_seq = 0;
557
558    struct {
559        pid_t pid;
560        CRYPTO_THREAD_ID tid;
561        unsigned __int64 time;
562        unsigned __int32 seq;
563    } data;
564
565    /* Erase the entire structure including any padding */
566    memset(&data, 0, sizeof(data));
567
568    /*
569     * Add process id, thread id, a timestamp, and a sequence number in case
570     * the same time stamp is repeated, to ensure that the nonce is unique
571     * with high probability for different process instances.
572     *
573     * The normal OpenVMS time is specified to be high granularity (100ns),
574     * but the time update granularity given by sys$gettim() may be lower.
575     *
576     * OpenVMS version 8.4 (which is the latest for Alpha and Itanium) and
577     * on have sys$gettim_prec() as well, which is supposedly having a better
578     * time update granularity, but tests on Itanium (and even Alpha) have
579     * shown that compared with sys$gettim(), the difference is marginal,
580     * so of very little significance in terms of entropy.
581     * Given that, and that it's a high ask to expect everyone to have
582     * upgraded to OpenVMS version 8.4, only sys$gettim() is used, and a
583     * sequence number is added as well, in case sys$gettim() returns the
584     * same time value more than once.
585     *
586     * This function is assumed to be called under thread lock, and does
587     * therefore not take concurrency into account.
588     */
589    data.pid = getpid();
590    data.tid = CRYPTO_THREAD_get_current_id();
591    data.seq = 0;
592    sys$gettim((void*)&data.time);
593
594    if (data.time == last_time) {
595        data.seq = ++last_seq;
596    } else {
597        last_time = data.time;
598        last_seq = 0;
599    }
600
601    return ossl_rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0);
602}
603
604int ossl_rand_pool_init(void)
605{
606    return 1;
607}
608
609void ossl_rand_pool_cleanup(void)
610{
611}
612
613void ossl_rand_pool_keep_random_devices_open(int keep)
614{
615}
616