2 * Copyright 2001-2018 The OpenSSL Project Authors. All Rights Reserved.
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
12 #if defined(OPENSSL_SYS_VMS)
13 # define __NEW_STARLET 1 /* New starlet definitions since VMS 7.0 */
15 # include "internal/cryptlib.h"
16 # include <openssl/rand.h>
17 # include "internal/rand_int.h"
18 # include "rand_lcl.h"
27 # include <gen64def.h>
30 # include <lib$routines.h>
32 # pragma message disable DOLLARID
35 # ifndef OPENSSL_RAND_SEED_OS
36 # error "Unsupported seeding method configured; must be os"
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
44 typedef uint32_t *uint32_t__ptr32
;
45 # if __INITIAL_POINTER_SIZE == 64
46 # pragma pointer_size restore
50 short length
, code
; /* length is number of bytes */
53 static const struct item_st DVI_item_data
[] = {
58 static const struct item_st JPI_item_data
[] = {
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
75 static const struct item_st JPI_item_data_64bit
[] = {
76 {8, JPI$_LAST_LOGIN_I
},
80 static const struct item_st RMI_item_data
[] = {
152 /* We currently get a fault when trying these. TODO: To be figured out. */
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 */
158 {4, RMI$_LPZ_PAGCNT
},
160 {4, RMI$_LPZ_MISSES
},
161 {4, RMI$_LPZ_EXPCNT
},
162 {4, RMI$_LPZ_ALLOCF
},
163 {4, RMI$_LPZ_ALLOC2
},
173 {4, RMI$_FILHDR_HIT
},
174 {4, RMI$_DIRFCB_HIT
},
175 {4, RMI$_DIRFCB_MISS
},
176 {4, RMI$_DIRDATA_HIT
},
181 {4, RMI$_STORAGMAP_HIT
},
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
},
199 {4, RMI$_HDRINSWAPS
},
200 {4, RMI$_HDROUTSWAPS
},
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
},
230 static const struct item_st RMI_item_data_64bit
[] = {
235 {8, RMI$_LCKMGR_REQCNT
},
236 {8, RMI$_LCKMGR_REQTIME
},
237 {8, RMI$_LCKMGR_SPINCNT
},
238 {8, RMI$_LCKMGR_SPINTIME
},
240 {8, RMI$_CPUMPSYNCH
},
250 {8, RMI$_TQEUSRTIMR
},
251 {8, RMI$_TQEUSRWAKE
},
254 static const struct item_st SYI_item_data
[] = {
255 {4, SYI$_PAGEFILE_FREE
},
260 * items_data - an array of lengths and codes
261 * items_data_num - number of elements in that array
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.
269 * Returns the number of elements used in databuffer
271 static size_t prepare_item_list(const struct item_st
*items_input
,
272 size_t items_input_num
,
274 uint32_t__ptr32 databuffer
)
278 for (; items_input_num
-- > 0; items_input
++, items
++) {
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;
285 items
->ile3$w_length
= items_input
->length
;
287 items
->ile3$ps_bufaddr
= databuffer
;
288 items
->ile3$ps_retlen_addr
= 0;
290 databuffer
+= items_input
->length
/ sizeof(databuffer
[0]);
291 data_sz
+= items_input
->length
;
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
;
297 return data_sz
/ sizeof(databuffer
[0]);
300 static void massage_JPI(ILE3
*items
)
303 * Special treatment of JPI$_FINALEXC
304 * The result of that item's data buffer is a 32-bit address to a list of
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
;
314 * We know we made space for 4 32-bit words, so we can do in-place
317 for (j
= 0; j
< 4; j
++)
326 * This number expresses how many bits of data contain 1 bit of entropy.
328 * For the moment, we assume about 0.05 entropy bits per data bit, or 1
329 * bit of entropy per 20 data bits.
331 #define ENTROPY_FACTOR 20
333 size_t rand_pool_acquire_entropy(RAND_POOL
*pool
)
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];
342 /* This ensures buffer starts at 64 bit boundary */
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 */];
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
);
357 /* Take all the 64-bit items first, to ensure proper alignment of data */
359 prepare_item_list(JPI_item_data_64bit
, OSSL_NELEM(JPI_item_data_64bit
),
360 JPI_items_64bit
, &data
.buffer
[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]);
375 /* Fill data.buffer with various info bits from this process */
380 $
DESCRIPTOR(SYSDEVICE
,"SYS$SYSDEVICE:");
382 if ((status
= sys$
getdviw(EFN$C_ENF
, 0, &SYSDEVICE
, DVI_items
,
383 0, 0, 0, 0, 0)) != SS$_NORMAL
) {
387 if ((status
= sys$
getjpiw(EFN$C_ENF
, 0, 0, JPI_items_64bit
, 0, 0, 0))
392 if ((status
= sys$
getjpiw(EFN$C_ENF
, 0, 0, JPI_items
, 0, 0, 0))
397 if ((status
= sys$
getsyiw(EFN$C_ENF
, 0, 0, SYI_items
, 0, 0, 0))
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.
406 if ((status
= lib$
get_ef(&efn
)) != SS$_NORMAL
) {
410 if ((status
= sys$
getrmi(efn
, 0, 0, RMI_items_64bit
, &iosb
, 0, 0))
415 if ((status
= sys$
synch(efn
, &iosb
)) != SS$_NORMAL
) {
419 if (iosb
.iosb$l_getxxi_status
!= SS$_NORMAL
) {
420 lib$
signal(iosb
.iosb$l_getxxi_status
);
423 if ((status
= sys$
getrmi(efn
, 0, 0, RMI_items
, &iosb
, 0, 0))
428 if ((status
= sys$
synch(efn
, &iosb
)) != SS$_NORMAL
) {
432 if (iosb
.iosb$l_getxxi_status
!= SS$_NORMAL
) {
433 lib$
signal(iosb
.iosb$l_getxxi_status
);
436 if ((status
= lib$
free_ef(&efn
)) != SS$_NORMAL
) {
442 massage_JPI(JPI_items
);
445 * If we can't feed the requirements from the caller, we're in deep trouble.
447 if (!ossl_assert(total_length
>= bytes_needed
)) {
449 char availablestr
[20];
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: ",
461 * Try not to overfeed the pool
463 if (total_length
> bytes_remaining
)
464 total_length
= bytes_remaining
;
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
);
472 int rand_pool_add_nonce_data(RAND_POOL
*pool
)
476 CRYPTO_THREAD_ID tid
;
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
487 data
.tid
= CRYPTO_THREAD_get_current_id();
488 #if __CRTL_VER >= 80400000
489 sys$
gettim_prec(&data
.time
);
491 sys$
gettim((void*)&data
.time
);
494 return rand_pool_add(pool
, (unsigned char *)&data
, sizeof(data
), 0);
497 int rand_pool_add_additional_data(RAND_POOL
*pool
)
500 CRYPTO_THREAD_ID tid
;
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).
509 data
.tid
= CRYPTO_THREAD_get_current_id();
510 #if __CRTL_VER >= 80400000
511 sys$
gettim_prec(&data
.time
);
513 sys$
gettim((void*)&data
.time
);
516 return rand_pool_add(pool
, (unsigned char *)&data
, sizeof(data
), 0);
519 int rand_pool_init(void)
524 void rand_pool_cleanup(void)
528 void rand_pool_keep_random_devices_open(int keep
)