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 55 typedef uint32_t *uint32_t__ptr32; 56 #if __INITIAL_POINTER_SIZE == 64 57 # pragma pointer_size restore 58 #endif 59 60 struct item_st { 61 short length, code; /* length is number of bytes */ 62 }; 63 64 static const struct item_st DVI_item_data[] = { 65 {4, DVI$_ERRCNT}, 66 {4, DVI$_REFCNT}, 67 }; 68 69 static 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 86 static const struct item_st JPI_item_data_64bit[] = { 87 {8, JPI$_LAST_LOGIN_I}, 88 {8, JPI$_LOGINTIM}, 89 }; 90 91 static 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 241 static 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 265 static 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 */ 282 static 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 311 static 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 344 size_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 490 static int get_entropy_address_flag = 0; 491 static int (*get_entropy_address)(void *buffer, size_t buffer_size) = NULL; 492 static 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 500 size_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 543 size_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 550 int 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 604 int ossl_rand_pool_init(void) 605 { 606 return 1; 607 } 608 609 void ossl_rand_pool_cleanup(void) 610 { 611 } 612 613 void ossl_rand_pool_keep_random_devices_open(int keep) 614 { 615 } 616