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