1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * 4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 5e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 8e1051a39Sopenharmony_ci */ 9e1051a39Sopenharmony_ci 10e1051a39Sopenharmony_ci#if defined (__TANDEM) && defined (_SPT_MODEL_) 11e1051a39Sopenharmony_ci/* 12e1051a39Sopenharmony_ci * These definitions have to come first in SPT due to scoping of the 13e1051a39Sopenharmony_ci * declarations in c99 associated with SPT use of stat. 14e1051a39Sopenharmony_ci */ 15e1051a39Sopenharmony_ci# include <sys/types.h> 16e1051a39Sopenharmony_ci# include <sys/stat.h> 17e1051a39Sopenharmony_ci#endif 18e1051a39Sopenharmony_ci 19e1051a39Sopenharmony_ci#include "e_os.h" 20e1051a39Sopenharmony_ci#include "internal/cryptlib.h" 21e1051a39Sopenharmony_ci 22e1051a39Sopenharmony_ci#include <errno.h> 23e1051a39Sopenharmony_ci#include <stdio.h> 24e1051a39Sopenharmony_ci#include <stdlib.h> 25e1051a39Sopenharmony_ci#include <string.h> 26e1051a39Sopenharmony_ci 27e1051a39Sopenharmony_ci#include <openssl/crypto.h> 28e1051a39Sopenharmony_ci#include <openssl/rand.h> 29e1051a39Sopenharmony_ci#include <openssl/buffer.h> 30e1051a39Sopenharmony_ci 31e1051a39Sopenharmony_ci#ifdef OPENSSL_SYS_VMS 32e1051a39Sopenharmony_ci# include <unixio.h> 33e1051a39Sopenharmony_ci#endif 34e1051a39Sopenharmony_ci#include <sys/types.h> 35e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_POSIX_IO 36e1051a39Sopenharmony_ci# include <sys/stat.h> 37e1051a39Sopenharmony_ci# include <fcntl.h> 38e1051a39Sopenharmony_ci# if defined(_WIN32) && !defined(_WIN32_WCE) 39e1051a39Sopenharmony_ci# include <windows.h> 40e1051a39Sopenharmony_ci# include <io.h> 41e1051a39Sopenharmony_ci# define stat _stat 42e1051a39Sopenharmony_ci# define chmod _chmod 43e1051a39Sopenharmony_ci# define open _open 44e1051a39Sopenharmony_ci# define fdopen _fdopen 45e1051a39Sopenharmony_ci# define fstat _fstat 46e1051a39Sopenharmony_ci# define fileno _fileno 47e1051a39Sopenharmony_ci# endif 48e1051a39Sopenharmony_ci#endif 49e1051a39Sopenharmony_ci 50e1051a39Sopenharmony_ci/* 51e1051a39Sopenharmony_ci * Following should not be needed, and we could have been stricter 52e1051a39Sopenharmony_ci * and demand S_IS*. But some systems just don't comply... Formally 53e1051a39Sopenharmony_ci * below macros are "anatomically incorrect", because normally they 54e1051a39Sopenharmony_ci * would look like ((m) & MASK == TYPE), but since MASK availability 55e1051a39Sopenharmony_ci * is as questionable, we settle for this poor-man fallback... 56e1051a39Sopenharmony_ci */ 57e1051a39Sopenharmony_ci# if !defined(S_ISREG) 58e1051a39Sopenharmony_ci# define S_ISREG(m) ((m) & S_IFREG) 59e1051a39Sopenharmony_ci# endif 60e1051a39Sopenharmony_ci 61e1051a39Sopenharmony_ci#define RAND_BUF_SIZE 1024 62e1051a39Sopenharmony_ci#define RFILE ".rnd" 63e1051a39Sopenharmony_ci 64e1051a39Sopenharmony_ci#ifdef OPENSSL_SYS_VMS 65e1051a39Sopenharmony_ci/* 66e1051a39Sopenharmony_ci * __FILE_ptr32 is a type provided by DEC C headers (types.h specifically) 67e1051a39Sopenharmony_ci * to make sure the FILE* is a 32-bit pointer no matter what. We know that 68e1051a39Sopenharmony_ci * stdio functions return this type (a study of stdio.h proves it). 69e1051a39Sopenharmony_ci * 70e1051a39Sopenharmony_ci * This declaration is a nasty hack to get around vms' extension to fopen for 71e1051a39Sopenharmony_ci * passing in sharing options being disabled by /STANDARD=ANSI89 72e1051a39Sopenharmony_ci */ 73e1051a39Sopenharmony_cistatic __FILE_ptr32 (*const vms_fopen)(const char *, const char *, ...) = 74e1051a39Sopenharmony_ci (__FILE_ptr32 (*)(const char *, const char *, ...))fopen; 75e1051a39Sopenharmony_ci# define VMS_OPEN_ATTRS \ 76e1051a39Sopenharmony_ci "shr=get,put,upd,del","ctx=bin,stm","rfm=stm","rat=none","mrs=0" 77e1051a39Sopenharmony_ci# define openssl_fopen(fname, mode) vms_fopen((fname), (mode), VMS_OPEN_ATTRS) 78e1051a39Sopenharmony_ci#endif 79e1051a39Sopenharmony_ci 80e1051a39Sopenharmony_ci/* 81e1051a39Sopenharmony_ci * Note that these functions are intended for seed files only. Entropy 82e1051a39Sopenharmony_ci * devices and EGD sockets are handled in rand_unix.c If |bytes| is 83e1051a39Sopenharmony_ci * -1 read the complete file; otherwise read the specified amount. 84e1051a39Sopenharmony_ci */ 85e1051a39Sopenharmony_ciint RAND_load_file(const char *file, long bytes) 86e1051a39Sopenharmony_ci{ 87e1051a39Sopenharmony_ci /* 88e1051a39Sopenharmony_ci * The load buffer size exceeds the chunk size by the comfortable amount 89e1051a39Sopenharmony_ci * of 'RAND_DRBG_STRENGTH' bytes (not bits!). This is done on purpose 90e1051a39Sopenharmony_ci * to avoid calling RAND_add() with a small final chunk. Instead, such 91e1051a39Sopenharmony_ci * a small final chunk will be added together with the previous chunk 92e1051a39Sopenharmony_ci * (unless it's the only one). 93e1051a39Sopenharmony_ci */ 94e1051a39Sopenharmony_ci#define RAND_LOAD_BUF_SIZE (RAND_BUF_SIZE + RAND_DRBG_STRENGTH) 95e1051a39Sopenharmony_ci unsigned char buf[RAND_LOAD_BUF_SIZE]; 96e1051a39Sopenharmony_ci 97e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_POSIX_IO 98e1051a39Sopenharmony_ci struct stat sb; 99e1051a39Sopenharmony_ci#endif 100e1051a39Sopenharmony_ci int i, n, ret = 0; 101e1051a39Sopenharmony_ci FILE *in; 102e1051a39Sopenharmony_ci 103e1051a39Sopenharmony_ci if (bytes == 0) 104e1051a39Sopenharmony_ci return 0; 105e1051a39Sopenharmony_ci 106e1051a39Sopenharmony_ci if ((in = openssl_fopen(file, "rb")) == NULL) { 107e1051a39Sopenharmony_ci ERR_raise_data(ERR_LIB_RAND, RAND_R_CANNOT_OPEN_FILE, 108e1051a39Sopenharmony_ci "Filename=%s", file); 109e1051a39Sopenharmony_ci return -1; 110e1051a39Sopenharmony_ci } 111e1051a39Sopenharmony_ci 112e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_POSIX_IO 113e1051a39Sopenharmony_ci if (fstat(fileno(in), &sb) < 0) { 114e1051a39Sopenharmony_ci ERR_raise_data(ERR_LIB_RAND, RAND_R_INTERNAL_ERROR, 115e1051a39Sopenharmony_ci "Filename=%s", file); 116e1051a39Sopenharmony_ci fclose(in); 117e1051a39Sopenharmony_ci return -1; 118e1051a39Sopenharmony_ci } 119e1051a39Sopenharmony_ci 120e1051a39Sopenharmony_ci if (bytes < 0) { 121e1051a39Sopenharmony_ci if (S_ISREG(sb.st_mode)) 122e1051a39Sopenharmony_ci bytes = sb.st_size; 123e1051a39Sopenharmony_ci else 124e1051a39Sopenharmony_ci bytes = RAND_DRBG_STRENGTH; 125e1051a39Sopenharmony_ci } 126e1051a39Sopenharmony_ci#endif 127e1051a39Sopenharmony_ci /* 128e1051a39Sopenharmony_ci * On VMS, setbuf() will only take 32-bit pointers, and a compilation 129e1051a39Sopenharmony_ci * with /POINTER_SIZE=64 will give off a MAYLOSEDATA2 warning here. 130e1051a39Sopenharmony_ci * However, we trust that the C RTL will never give us a FILE pointer 131e1051a39Sopenharmony_ci * above the first 4 GB of memory, so we simply turn off the warning 132e1051a39Sopenharmony_ci * temporarily. 133e1051a39Sopenharmony_ci */ 134e1051a39Sopenharmony_ci#if defined(OPENSSL_SYS_VMS) && defined(__DECC) 135e1051a39Sopenharmony_ci# pragma environment save 136e1051a39Sopenharmony_ci# pragma message disable maylosedata2 137e1051a39Sopenharmony_ci#endif 138e1051a39Sopenharmony_ci /* 139e1051a39Sopenharmony_ci * Don't buffer, because even if |file| is regular file, we have 140e1051a39Sopenharmony_ci * no control over the buffer, so why would we want a copy of its 141e1051a39Sopenharmony_ci * contents lying around? 142e1051a39Sopenharmony_ci */ 143e1051a39Sopenharmony_ci setbuf(in, NULL); 144e1051a39Sopenharmony_ci#if defined(OPENSSL_SYS_VMS) && defined(__DECC) 145e1051a39Sopenharmony_ci# pragma environment restore 146e1051a39Sopenharmony_ci#endif 147e1051a39Sopenharmony_ci 148e1051a39Sopenharmony_ci for ( ; ; ) { 149e1051a39Sopenharmony_ci if (bytes > 0) 150e1051a39Sopenharmony_ci n = (bytes <= RAND_LOAD_BUF_SIZE) ? (int)bytes : RAND_BUF_SIZE; 151e1051a39Sopenharmony_ci else 152e1051a39Sopenharmony_ci n = RAND_LOAD_BUF_SIZE; 153e1051a39Sopenharmony_ci i = fread(buf, 1, n, in); 154e1051a39Sopenharmony_ci#ifdef EINTR 155e1051a39Sopenharmony_ci if (ferror(in) && errno == EINTR){ 156e1051a39Sopenharmony_ci clearerr(in); 157e1051a39Sopenharmony_ci if (i == 0) 158e1051a39Sopenharmony_ci continue; 159e1051a39Sopenharmony_ci } 160e1051a39Sopenharmony_ci#endif 161e1051a39Sopenharmony_ci if (i == 0) 162e1051a39Sopenharmony_ci break; 163e1051a39Sopenharmony_ci 164e1051a39Sopenharmony_ci RAND_add(buf, i, (double)i); 165e1051a39Sopenharmony_ci ret += i; 166e1051a39Sopenharmony_ci 167e1051a39Sopenharmony_ci /* If given a bytecount, and we did it, break. */ 168e1051a39Sopenharmony_ci if (bytes > 0 && (bytes -= i) <= 0) 169e1051a39Sopenharmony_ci break; 170e1051a39Sopenharmony_ci } 171e1051a39Sopenharmony_ci 172e1051a39Sopenharmony_ci OPENSSL_cleanse(buf, sizeof(buf)); 173e1051a39Sopenharmony_ci fclose(in); 174e1051a39Sopenharmony_ci if (!RAND_status()) { 175e1051a39Sopenharmony_ci ERR_raise_data(ERR_LIB_RAND, RAND_R_RESEED_ERROR, "Filename=%s", file); 176e1051a39Sopenharmony_ci return -1; 177e1051a39Sopenharmony_ci } 178e1051a39Sopenharmony_ci 179e1051a39Sopenharmony_ci return ret; 180e1051a39Sopenharmony_ci} 181e1051a39Sopenharmony_ci 182e1051a39Sopenharmony_ciint RAND_write_file(const char *file) 183e1051a39Sopenharmony_ci{ 184e1051a39Sopenharmony_ci unsigned char buf[RAND_BUF_SIZE]; 185e1051a39Sopenharmony_ci int ret = -1; 186e1051a39Sopenharmony_ci FILE *out = NULL; 187e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_POSIX_IO 188e1051a39Sopenharmony_ci struct stat sb; 189e1051a39Sopenharmony_ci 190e1051a39Sopenharmony_ci if (stat(file, &sb) >= 0 && !S_ISREG(sb.st_mode)) { 191e1051a39Sopenharmony_ci ERR_raise_data(ERR_LIB_RAND, RAND_R_NOT_A_REGULAR_FILE, 192e1051a39Sopenharmony_ci "Filename=%s", file); 193e1051a39Sopenharmony_ci return -1; 194e1051a39Sopenharmony_ci } 195e1051a39Sopenharmony_ci#endif 196e1051a39Sopenharmony_ci 197e1051a39Sopenharmony_ci /* Collect enough random data. */ 198e1051a39Sopenharmony_ci if (RAND_priv_bytes(buf, (int)sizeof(buf)) != 1) 199e1051a39Sopenharmony_ci return -1; 200e1051a39Sopenharmony_ci 201e1051a39Sopenharmony_ci#if defined(O_CREAT) && !defined(OPENSSL_NO_POSIX_IO) && \ 202e1051a39Sopenharmony_ci !defined(OPENSSL_SYS_VMS) && !defined(OPENSSL_SYS_WINDOWS) 203e1051a39Sopenharmony_ci { 204e1051a39Sopenharmony_ci# ifndef O_BINARY 205e1051a39Sopenharmony_ci# define O_BINARY 0 206e1051a39Sopenharmony_ci# endif 207e1051a39Sopenharmony_ci /* 208e1051a39Sopenharmony_ci * chmod(..., 0600) is too late to protect the file, permissions 209e1051a39Sopenharmony_ci * should be restrictive from the start 210e1051a39Sopenharmony_ci */ 211e1051a39Sopenharmony_ci int fd = open(file, O_WRONLY | O_CREAT | O_BINARY, 0600); 212e1051a39Sopenharmony_ci 213e1051a39Sopenharmony_ci if (fd != -1) { 214e1051a39Sopenharmony_ci out = fdopen(fd, "wb"); 215e1051a39Sopenharmony_ci if (out == NULL) { 216e1051a39Sopenharmony_ci close(fd); 217e1051a39Sopenharmony_ci ERR_raise_data(ERR_LIB_RAND, RAND_R_CANNOT_OPEN_FILE, 218e1051a39Sopenharmony_ci "Filename=%s", file); 219e1051a39Sopenharmony_ci return -1; 220e1051a39Sopenharmony_ci } 221e1051a39Sopenharmony_ci } 222e1051a39Sopenharmony_ci } 223e1051a39Sopenharmony_ci#endif 224e1051a39Sopenharmony_ci 225e1051a39Sopenharmony_ci#ifdef OPENSSL_SYS_VMS 226e1051a39Sopenharmony_ci /* 227e1051a39Sopenharmony_ci * VMS NOTE: Prior versions of this routine created a _new_ version of 228e1051a39Sopenharmony_ci * the rand file for each call into this routine, then deleted all 229e1051a39Sopenharmony_ci * existing versions named ;-1, and finally renamed the current version 230e1051a39Sopenharmony_ci * as ';1'. Under concurrent usage, this resulted in an RMS race 231e1051a39Sopenharmony_ci * condition in rename() which could orphan files (see vms message help 232e1051a39Sopenharmony_ci * for RMS$_REENT). With the fopen() calls below, openssl/VMS now shares 233e1051a39Sopenharmony_ci * the top-level version of the rand file. Note that there may still be 234e1051a39Sopenharmony_ci * conditions where the top-level rand file is locked. If so, this code 235e1051a39Sopenharmony_ci * will then create a new version of the rand file. Without the delete 236e1051a39Sopenharmony_ci * and rename code, this can result in ascending file versions that stop 237e1051a39Sopenharmony_ci * at version 32767, and this routine will then return an error. The 238e1051a39Sopenharmony_ci * remedy for this is to recode the calling application to avoid 239e1051a39Sopenharmony_ci * concurrent use of the rand file, or synchronize usage at the 240e1051a39Sopenharmony_ci * application level. Also consider whether or not you NEED a persistent 241e1051a39Sopenharmony_ci * rand file in a concurrent use situation. 242e1051a39Sopenharmony_ci */ 243e1051a39Sopenharmony_ci out = openssl_fopen(file, "rb+"); 244e1051a39Sopenharmony_ci#endif 245e1051a39Sopenharmony_ci 246e1051a39Sopenharmony_ci if (out == NULL) 247e1051a39Sopenharmony_ci out = openssl_fopen(file, "wb"); 248e1051a39Sopenharmony_ci if (out == NULL) { 249e1051a39Sopenharmony_ci ERR_raise_data(ERR_LIB_RAND, RAND_R_CANNOT_OPEN_FILE, 250e1051a39Sopenharmony_ci "Filename=%s", file); 251e1051a39Sopenharmony_ci return -1; 252e1051a39Sopenharmony_ci } 253e1051a39Sopenharmony_ci 254e1051a39Sopenharmony_ci#if !defined(NO_CHMOD) && !defined(OPENSSL_NO_POSIX_IO) 255e1051a39Sopenharmony_ci /* 256e1051a39Sopenharmony_ci * Yes it's late to do this (see above comment), but better than nothing. 257e1051a39Sopenharmony_ci */ 258e1051a39Sopenharmony_ci chmod(file, 0600); 259e1051a39Sopenharmony_ci#endif 260e1051a39Sopenharmony_ci 261e1051a39Sopenharmony_ci ret = fwrite(buf, 1, RAND_BUF_SIZE, out); 262e1051a39Sopenharmony_ci fclose(out); 263e1051a39Sopenharmony_ci OPENSSL_cleanse(buf, RAND_BUF_SIZE); 264e1051a39Sopenharmony_ci return ret; 265e1051a39Sopenharmony_ci} 266e1051a39Sopenharmony_ci 267e1051a39Sopenharmony_ciconst char *RAND_file_name(char *buf, size_t size) 268e1051a39Sopenharmony_ci{ 269e1051a39Sopenharmony_ci char *s = NULL; 270e1051a39Sopenharmony_ci size_t len; 271e1051a39Sopenharmony_ci int use_randfile = 1; 272e1051a39Sopenharmony_ci 273e1051a39Sopenharmony_ci#if defined(_WIN32) && defined(CP_UTF8) && !defined(_WIN32_WCE) 274e1051a39Sopenharmony_ci DWORD envlen; 275e1051a39Sopenharmony_ci WCHAR *var; 276e1051a39Sopenharmony_ci 277e1051a39Sopenharmony_ci /* Look up various environment variables. */ 278e1051a39Sopenharmony_ci if ((envlen = GetEnvironmentVariableW(var = L"RANDFILE", NULL, 0)) == 0) { 279e1051a39Sopenharmony_ci use_randfile = 0; 280e1051a39Sopenharmony_ci if ((envlen = GetEnvironmentVariableW(var = L"HOME", NULL, 0)) == 0 281e1051a39Sopenharmony_ci && (envlen = GetEnvironmentVariableW(var = L"USERPROFILE", 282e1051a39Sopenharmony_ci NULL, 0)) == 0) 283e1051a39Sopenharmony_ci envlen = GetEnvironmentVariableW(var = L"SYSTEMROOT", NULL, 0); 284e1051a39Sopenharmony_ci } 285e1051a39Sopenharmony_ci 286e1051a39Sopenharmony_ci /* If we got a value, allocate space to hold it and then get it. */ 287e1051a39Sopenharmony_ci if (envlen != 0) { 288e1051a39Sopenharmony_ci int sz; 289e1051a39Sopenharmony_ci WCHAR *val = _alloca(envlen * sizeof(WCHAR)); 290e1051a39Sopenharmony_ci 291e1051a39Sopenharmony_ci if (GetEnvironmentVariableW(var, val, envlen) < envlen 292e1051a39Sopenharmony_ci && (sz = WideCharToMultiByte(CP_UTF8, 0, val, -1, NULL, 0, 293e1051a39Sopenharmony_ci NULL, NULL)) != 0) { 294e1051a39Sopenharmony_ci s = _alloca(sz); 295e1051a39Sopenharmony_ci if (WideCharToMultiByte(CP_UTF8, 0, val, -1, s, sz, 296e1051a39Sopenharmony_ci NULL, NULL) == 0) 297e1051a39Sopenharmony_ci s = NULL; 298e1051a39Sopenharmony_ci } 299e1051a39Sopenharmony_ci } 300e1051a39Sopenharmony_ci#else 301e1051a39Sopenharmony_ci if ((s = ossl_safe_getenv("RANDFILE")) == NULL || *s == '\0') { 302e1051a39Sopenharmony_ci use_randfile = 0; 303e1051a39Sopenharmony_ci s = ossl_safe_getenv("HOME"); 304e1051a39Sopenharmony_ci } 305e1051a39Sopenharmony_ci#endif 306e1051a39Sopenharmony_ci 307e1051a39Sopenharmony_ci#ifdef DEFAULT_HOME 308e1051a39Sopenharmony_ci if (!use_randfile && s == NULL) 309e1051a39Sopenharmony_ci s = DEFAULT_HOME; 310e1051a39Sopenharmony_ci#endif 311e1051a39Sopenharmony_ci if (s == NULL || *s == '\0') 312e1051a39Sopenharmony_ci return NULL; 313e1051a39Sopenharmony_ci 314e1051a39Sopenharmony_ci len = strlen(s); 315e1051a39Sopenharmony_ci if (use_randfile) { 316e1051a39Sopenharmony_ci if (len + 1 >= size) 317e1051a39Sopenharmony_ci return NULL; 318e1051a39Sopenharmony_ci strcpy(buf, s); 319e1051a39Sopenharmony_ci } else { 320e1051a39Sopenharmony_ci if (len + 1 + strlen(RFILE) + 1 >= size) 321e1051a39Sopenharmony_ci return NULL; 322e1051a39Sopenharmony_ci strcpy(buf, s); 323e1051a39Sopenharmony_ci#ifndef OPENSSL_SYS_VMS 324e1051a39Sopenharmony_ci strcat(buf, "/"); 325e1051a39Sopenharmony_ci#endif 326e1051a39Sopenharmony_ci strcat(buf, RFILE); 327e1051a39Sopenharmony_ci } 328e1051a39Sopenharmony_ci 329e1051a39Sopenharmony_ci return buf; 330e1051a39Sopenharmony_ci} 331