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