1193645Ssimon/* ==================================================================== 2193645Ssimon * Copyright (c) 2007 The OpenSSL Project. All rights reserved. 3193645Ssimon * 4193645Ssimon * Redistribution and use in source and binary forms, with or without 5193645Ssimon * modification, are permitted provided that the following conditions 6193645Ssimon * are met: 7193645Ssimon * 8193645Ssimon * 1. Redistributions of source code must retain the above copyright 9296465Sdelphij * notice, this list of conditions and the following disclaimer. 10193645Ssimon * 11193645Ssimon * 2. Redistributions in binary form must reproduce the above copyright 12193645Ssimon * notice, this list of conditions and the following disclaimer in 13193645Ssimon * the documentation and/or other materials provided with the 14193645Ssimon * distribution. 15193645Ssimon * 16193645Ssimon * 3. All advertising materials mentioning features or use of this 17193645Ssimon * software must display the following acknowledgment: 18193645Ssimon * "This product includes software developed by the OpenSSL Project 19193645Ssimon * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" 20193645Ssimon * 21193645Ssimon * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 22193645Ssimon * endorse or promote products derived from this software without 23193645Ssimon * prior written permission. For written permission, please contact 24193645Ssimon * openssl-core@openssl.org. 25193645Ssimon * 26193645Ssimon * 5. Products derived from this software may not be called "OpenSSL" 27193645Ssimon * nor may "OpenSSL" appear in their names without prior written 28193645Ssimon * permission of the OpenSSL Project. 29193645Ssimon * 30193645Ssimon * 6. Redistributions of any form whatsoever must retain the following 31193645Ssimon * acknowledgment: 32193645Ssimon * "This product includes software developed by the OpenSSL Project 33193645Ssimon * for use in the OpenSSL Toolkit (http://www.openssl.org/)" 34193645Ssimon * 35193645Ssimon * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 36193645Ssimon * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 37193645Ssimon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 38193645Ssimon * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 39193645Ssimon * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 40193645Ssimon * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 41193645Ssimon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 42193645Ssimon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 43193645Ssimon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 44193645Ssimon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 45193645Ssimon * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 46193645Ssimon * OF THE POSSIBILITY OF SUCH DAMAGE. 47193645Ssimon * 48193645Ssimon */ 49193645Ssimon 50193645Ssimon/* 51193645Ssimon * This is a FIPS approved AES PRNG based on ANSI X9.31 A.2.4. 52193645Ssimon */ 53193645Ssimon 54193645Ssimon#include "e_os.h" 55193645Ssimon 56296465Sdelphij/* 57296465Sdelphij * If we don't define _XOPEN_SOURCE_EXTENDED, struct timeval won't be defined 58296465Sdelphij * and gettimeofday() won't be declared with strict compilers like DEC C in 59296465Sdelphij * ANSI C mode. 60296465Sdelphij */ 61193645Ssimon#ifndef _XOPEN_SOURCE_EXTENDED 62296465Sdelphij# define _XOPEN_SOURCE_EXTENDED 1 63193645Ssimon#endif 64193645Ssimon 65193645Ssimon#include <openssl/rand.h> 66193645Ssimon#include <openssl/aes.h> 67193645Ssimon#include <openssl/err.h> 68193645Ssimon#include <openssl/fips_rand.h> 69193645Ssimon#ifndef OPENSSL_SYS_WIN32 70296465Sdelphij# include <sys/time.h> 71193645Ssimon#endif 72193645Ssimon#include <assert.h> 73193645Ssimon#ifndef OPENSSL_SYS_WIN32 74193645Ssimon# ifdef OPENSSL_UNISTD 75193645Ssimon# include OPENSSL_UNISTD 76193645Ssimon# else 77193645Ssimon# include <unistd.h> 78193645Ssimon# endif 79193645Ssimon#endif 80193645Ssimon#include <string.h> 81193645Ssimon#include <openssl/fips.h> 82193645Ssimon#include "fips_locl.h" 83193645Ssimon 84193645Ssimon#ifdef OPENSSL_FIPS 85193645Ssimon 86193645Ssimonvoid *OPENSSL_stderr(void); 87193645Ssimon 88296465Sdelphij# define AES_BLOCK_LENGTH 16 89193645Ssimon 90193645Ssimon/* AES FIPS PRNG implementation */ 91193645Ssimon 92296465Sdelphijtypedef struct { 93296465Sdelphij int seeded; 94296465Sdelphij int keyed; 95296465Sdelphij int test_mode; 96296465Sdelphij int second; 97296465Sdelphij int error; 98296465Sdelphij unsigned long counter; 99296465Sdelphij AES_KEY ks; 100296465Sdelphij int vpos; 101296465Sdelphij /* Temporary storage for key if it equals seed length */ 102296465Sdelphij unsigned char tmp_key[AES_BLOCK_LENGTH]; 103296465Sdelphij unsigned char V[AES_BLOCK_LENGTH]; 104296465Sdelphij unsigned char DT[AES_BLOCK_LENGTH]; 105296465Sdelphij unsigned char last[AES_BLOCK_LENGTH]; 106296465Sdelphij} FIPS_PRNG_CTX; 107193645Ssimon 108193645Ssimonstatic FIPS_PRNG_CTX sctx; 109193645Ssimon 110193645Ssimonstatic int fips_prng_fail = 0; 111193645Ssimon 112193645Ssimonvoid FIPS_rng_stick(void) 113296465Sdelphij{ 114296465Sdelphij fips_prng_fail = 1; 115296465Sdelphij} 116193645Ssimon 117296465Sdelphijstatic void fips_rand_prng_reset(FIPS_PRNG_CTX * ctx) 118296465Sdelphij{ 119296465Sdelphij ctx->seeded = 0; 120296465Sdelphij ctx->keyed = 0; 121296465Sdelphij ctx->test_mode = 0; 122296465Sdelphij ctx->counter = 0; 123296465Sdelphij ctx->second = 0; 124296465Sdelphij ctx->error = 0; 125296465Sdelphij ctx->vpos = 0; 126296465Sdelphij OPENSSL_cleanse(ctx->V, AES_BLOCK_LENGTH); 127296465Sdelphij OPENSSL_cleanse(&ctx->ks, sizeof(AES_KEY)); 128296465Sdelphij} 129193645Ssimon 130296465Sdelphijstatic int fips_set_prng_key(FIPS_PRNG_CTX * ctx, 131296465Sdelphij const unsigned char *key, 132296465Sdelphij FIPS_RAND_SIZE_T keylen) 133296465Sdelphij{ 134296465Sdelphij FIPS_selftest_check(); 135296465Sdelphij if (keylen != 16 && keylen != 24 && keylen != 32) { 136296465Sdelphij /* error: invalid key size */ 137296465Sdelphij return 0; 138296465Sdelphij } 139296465Sdelphij AES_set_encrypt_key(key, keylen << 3, &ctx->ks); 140296465Sdelphij if (keylen == 16) { 141296465Sdelphij memcpy(ctx->tmp_key, key, 16); 142296465Sdelphij ctx->keyed = 2; 143296465Sdelphij } else 144296465Sdelphij ctx->keyed = 1; 145296465Sdelphij ctx->seeded = 0; 146296465Sdelphij ctx->second = 0; 147296465Sdelphij return 1; 148296465Sdelphij} 149193645Ssimon 150296465Sdelphijstatic int fips_set_prng_seed(FIPS_PRNG_CTX * ctx, 151296465Sdelphij const unsigned char *seed, 152296465Sdelphij FIPS_RAND_SIZE_T seedlen) 153296465Sdelphij{ 154296465Sdelphij int i; 155296465Sdelphij if (!ctx->keyed) 156296465Sdelphij return 0; 157296465Sdelphij /* In test mode seed is just supplied data */ 158296465Sdelphij if (ctx->test_mode) { 159296465Sdelphij if (seedlen != AES_BLOCK_LENGTH) 160296465Sdelphij return 0; 161296465Sdelphij memcpy(ctx->V, seed, AES_BLOCK_LENGTH); 162296465Sdelphij ctx->seeded = 1; 163296465Sdelphij return 1; 164296465Sdelphij } 165296465Sdelphij /* Outside test mode XOR supplied data with existing seed */ 166296465Sdelphij for (i = 0; i < seedlen; i++) { 167296465Sdelphij ctx->V[ctx->vpos++] ^= seed[i]; 168296465Sdelphij if (ctx->vpos == AES_BLOCK_LENGTH) { 169296465Sdelphij ctx->vpos = 0; 170296465Sdelphij /* 171296465Sdelphij * Special case if first seed and key length equals block size 172296465Sdelphij * check key and seed do not match. 173296465Sdelphij */ 174296465Sdelphij if (ctx->keyed == 2) { 175296465Sdelphij if (!memcmp(ctx->tmp_key, ctx->V, 16)) { 176296465Sdelphij RANDerr(RAND_F_FIPS_SET_PRNG_SEED, 177296465Sdelphij RAND_R_PRNG_SEED_MUST_NOT_MATCH_KEY); 178296465Sdelphij return 0; 179296465Sdelphij } 180296465Sdelphij OPENSSL_cleanse(ctx->tmp_key, 16); 181296465Sdelphij ctx->keyed = 1; 182296465Sdelphij } 183296465Sdelphij ctx->seeded = 1; 184296465Sdelphij } 185296465Sdelphij } 186296465Sdelphij return 1; 187296465Sdelphij} 188193645Ssimon 189296465Sdelphijstatic int fips_set_test_mode(FIPS_PRNG_CTX * ctx) 190296465Sdelphij{ 191296465Sdelphij if (ctx->keyed) { 192296465Sdelphij RANDerr(RAND_F_FIPS_SET_TEST_MODE, RAND_R_PRNG_KEYED); 193296465Sdelphij return 0; 194296465Sdelphij } 195296465Sdelphij ctx->test_mode = 1; 196296465Sdelphij return 1; 197296465Sdelphij} 198193645Ssimon 199193645Ssimonint FIPS_rand_test_mode(void) 200296465Sdelphij{ 201296465Sdelphij return fips_set_test_mode(&sctx); 202296465Sdelphij} 203193645Ssimon 204193645Ssimonint FIPS_rand_set_dt(unsigned char *dt) 205296465Sdelphij{ 206296465Sdelphij if (!sctx.test_mode) { 207296465Sdelphij RANDerr(RAND_F_FIPS_RAND_SET_DT, RAND_R_NOT_IN_TEST_MODE); 208296465Sdelphij return 0; 209296465Sdelphij } 210296465Sdelphij memcpy(sctx.DT, dt, AES_BLOCK_LENGTH); 211296465Sdelphij return 1; 212296465Sdelphij} 213193645Ssimon 214296465Sdelphijstatic void fips_get_dt(FIPS_PRNG_CTX * ctx) 215296465Sdelphij{ 216296465Sdelphij# ifdef OPENSSL_SYS_WIN32 217296465Sdelphij FILETIME ft; 218296465Sdelphij# else 219296465Sdelphij struct timeval tv; 220296465Sdelphij# endif 221296465Sdelphij unsigned char *buf = ctx->DT; 222193645Ssimon 223296465Sdelphij# ifndef GETPID_IS_MEANINGLESS 224296465Sdelphij unsigned long pid; 225296465Sdelphij# endif 226193645Ssimon 227296465Sdelphij# ifdef OPENSSL_SYS_WIN32 228296465Sdelphij GetSystemTimeAsFileTime(&ft); 229296465Sdelphij buf[0] = (unsigned char)(ft.dwHighDateTime & 0xff); 230296465Sdelphij buf[1] = (unsigned char)((ft.dwHighDateTime >> 8) & 0xff); 231296465Sdelphij buf[2] = (unsigned char)((ft.dwHighDateTime >> 16) & 0xff); 232296465Sdelphij buf[3] = (unsigned char)((ft.dwHighDateTime >> 24) & 0xff); 233296465Sdelphij buf[4] = (unsigned char)(ft.dwLowDateTime & 0xff); 234296465Sdelphij buf[5] = (unsigned char)((ft.dwLowDateTime >> 8) & 0xff); 235296465Sdelphij buf[6] = (unsigned char)((ft.dwLowDateTime >> 16) & 0xff); 236296465Sdelphij buf[7] = (unsigned char)((ft.dwLowDateTime >> 24) & 0xff); 237296465Sdelphij# else 238296465Sdelphij gettimeofday(&tv, NULL); 239296465Sdelphij buf[0] = (unsigned char)(tv.tv_sec & 0xff); 240296465Sdelphij buf[1] = (unsigned char)((tv.tv_sec >> 8) & 0xff); 241296465Sdelphij buf[2] = (unsigned char)((tv.tv_sec >> 16) & 0xff); 242296465Sdelphij buf[3] = (unsigned char)((tv.tv_sec >> 24) & 0xff); 243296465Sdelphij buf[4] = (unsigned char)(tv.tv_usec & 0xff); 244296465Sdelphij buf[5] = (unsigned char)((tv.tv_usec >> 8) & 0xff); 245296465Sdelphij buf[6] = (unsigned char)((tv.tv_usec >> 16) & 0xff); 246296465Sdelphij buf[7] = (unsigned char)((tv.tv_usec >> 24) & 0xff); 247296465Sdelphij# endif 248296465Sdelphij buf[8] = (unsigned char)(ctx->counter & 0xff); 249296465Sdelphij buf[9] = (unsigned char)((ctx->counter >> 8) & 0xff); 250296465Sdelphij buf[10] = (unsigned char)((ctx->counter >> 16) & 0xff); 251296465Sdelphij buf[11] = (unsigned char)((ctx->counter >> 24) & 0xff); 252193645Ssimon 253296465Sdelphij ctx->counter++; 254193645Ssimon 255296465Sdelphij# ifndef GETPID_IS_MEANINGLESS 256296465Sdelphij pid = (unsigned long)getpid(); 257296465Sdelphij buf[12] = (unsigned char)(pid & 0xff); 258296465Sdelphij buf[13] = (unsigned char)((pid >> 8) & 0xff); 259296465Sdelphij buf[14] = (unsigned char)((pid >> 16) & 0xff); 260296465Sdelphij buf[15] = (unsigned char)((pid >> 24) & 0xff); 261296465Sdelphij# endif 262296465Sdelphij} 263193645Ssimon 264296465Sdelphijstatic int fips_rand(FIPS_PRNG_CTX * ctx, 265296465Sdelphij unsigned char *out, FIPS_RAND_SIZE_T outlen) 266296465Sdelphij{ 267296465Sdelphij unsigned char R[AES_BLOCK_LENGTH], I[AES_BLOCK_LENGTH]; 268296465Sdelphij unsigned char tmp[AES_BLOCK_LENGTH]; 269296465Sdelphij int i; 270296465Sdelphij if (ctx->error) { 271296465Sdelphij RANDerr(RAND_F_FIPS_RAND, RAND_R_PRNG_ERROR); 272296465Sdelphij return 0; 273193645Ssimon } 274296465Sdelphij if (!ctx->keyed) { 275296465Sdelphij RANDerr(RAND_F_FIPS_RAND, RAND_R_NO_KEY_SET); 276296465Sdelphij return 0; 277296465Sdelphij } 278296465Sdelphij if (!ctx->seeded) { 279296465Sdelphij RANDerr(RAND_F_FIPS_RAND, RAND_R_PRNG_NOT_SEEDED); 280296465Sdelphij return 0; 281296465Sdelphij } 282296465Sdelphij for (;;) { 283296465Sdelphij if (!ctx->test_mode) 284296465Sdelphij fips_get_dt(ctx); 285296465Sdelphij AES_encrypt(ctx->DT, I, &ctx->ks); 286296465Sdelphij for (i = 0; i < AES_BLOCK_LENGTH; i++) 287296465Sdelphij tmp[i] = I[i] ^ ctx->V[i]; 288296465Sdelphij AES_encrypt(tmp, R, &ctx->ks); 289296465Sdelphij for (i = 0; i < AES_BLOCK_LENGTH; i++) 290296465Sdelphij tmp[i] = R[i] ^ I[i]; 291296465Sdelphij AES_encrypt(tmp, ctx->V, &ctx->ks); 292296465Sdelphij /* Continuous PRNG test */ 293296465Sdelphij if (ctx->second) { 294296465Sdelphij if (fips_prng_fail) 295296465Sdelphij memcpy(ctx->last, R, AES_BLOCK_LENGTH); 296296465Sdelphij if (!memcmp(R, ctx->last, AES_BLOCK_LENGTH)) { 297296465Sdelphij RANDerr(RAND_F_FIPS_RAND, RAND_R_PRNG_STUCK); 298296465Sdelphij ctx->error = 1; 299296465Sdelphij fips_set_selftest_fail(); 300296465Sdelphij return 0; 301296465Sdelphij } 302296465Sdelphij } 303296465Sdelphij memcpy(ctx->last, R, AES_BLOCK_LENGTH); 304296465Sdelphij if (!ctx->second) { 305296465Sdelphij ctx->second = 1; 306296465Sdelphij if (!ctx->test_mode) 307296465Sdelphij continue; 308296465Sdelphij } 309193645Ssimon 310296465Sdelphij if (outlen <= AES_BLOCK_LENGTH) { 311296465Sdelphij memcpy(out, R, outlen); 312296465Sdelphij break; 313296465Sdelphij } 314193645Ssimon 315296465Sdelphij memcpy(out, R, AES_BLOCK_LENGTH); 316296465Sdelphij out += AES_BLOCK_LENGTH; 317296465Sdelphij outlen -= AES_BLOCK_LENGTH; 318296465Sdelphij } 319296465Sdelphij return 1; 320296465Sdelphij} 321193645Ssimon 322193645Ssimonint FIPS_rand_set_key(const unsigned char *key, FIPS_RAND_SIZE_T keylen) 323296465Sdelphij{ 324296465Sdelphij int ret; 325296465Sdelphij CRYPTO_w_lock(CRYPTO_LOCK_RAND); 326296465Sdelphij ret = fips_set_prng_key(&sctx, key, keylen); 327296465Sdelphij CRYPTO_w_unlock(CRYPTO_LOCK_RAND); 328296465Sdelphij return ret; 329296465Sdelphij} 330193645Ssimon 331193645Ssimonint FIPS_rand_seed(const void *seed, FIPS_RAND_SIZE_T seedlen) 332296465Sdelphij{ 333296465Sdelphij int ret; 334296465Sdelphij CRYPTO_w_lock(CRYPTO_LOCK_RAND); 335296465Sdelphij ret = fips_set_prng_seed(&sctx, seed, seedlen); 336296465Sdelphij CRYPTO_w_unlock(CRYPTO_LOCK_RAND); 337296465Sdelphij return ret; 338296465Sdelphij} 339193645Ssimon 340193645Ssimonint FIPS_rand_bytes(unsigned char *out, FIPS_RAND_SIZE_T count) 341296465Sdelphij{ 342296465Sdelphij int ret; 343296465Sdelphij CRYPTO_w_lock(CRYPTO_LOCK_RAND); 344296465Sdelphij ret = fips_rand(&sctx, out, count); 345296465Sdelphij CRYPTO_w_unlock(CRYPTO_LOCK_RAND); 346296465Sdelphij return ret; 347296465Sdelphij} 348193645Ssimon 349193645Ssimonint FIPS_rand_status(void) 350296465Sdelphij{ 351296465Sdelphij int ret; 352296465Sdelphij CRYPTO_r_lock(CRYPTO_LOCK_RAND); 353296465Sdelphij ret = sctx.seeded; 354296465Sdelphij CRYPTO_r_unlock(CRYPTO_LOCK_RAND); 355296465Sdelphij return ret; 356296465Sdelphij} 357193645Ssimon 358193645Ssimonvoid FIPS_rand_reset(void) 359296465Sdelphij{ 360296465Sdelphij CRYPTO_w_lock(CRYPTO_LOCK_RAND); 361296465Sdelphij fips_rand_prng_reset(&sctx); 362296465Sdelphij CRYPTO_w_unlock(CRYPTO_LOCK_RAND); 363296465Sdelphij} 364193645Ssimon 365193645Ssimonstatic void fips_do_rand_seed(const void *seed, FIPS_RAND_SIZE_T seedlen) 366296465Sdelphij{ 367296465Sdelphij FIPS_rand_seed(seed, seedlen); 368296465Sdelphij} 369193645Ssimon 370193645Ssimonstatic void fips_do_rand_add(const void *seed, FIPS_RAND_SIZE_T seedlen, 371296465Sdelphij double add_entropy) 372296465Sdelphij{ 373296465Sdelphij FIPS_rand_seed(seed, seedlen); 374296465Sdelphij} 375193645Ssimon 376296465Sdelphijstatic const RAND_METHOD rand_fips_meth = { 377193645Ssimon fips_do_rand_seed, 378193645Ssimon FIPS_rand_bytes, 379193645Ssimon FIPS_rand_reset, 380193645Ssimon fips_do_rand_add, 381193645Ssimon FIPS_rand_bytes, 382193645Ssimon FIPS_rand_status 383296465Sdelphij}; 384193645Ssimon 385193645Ssimonconst RAND_METHOD *FIPS_rand_method(void) 386193645Ssimon{ 387296465Sdelphij return &rand_fips_meth; 388193645Ssimon} 389193645Ssimon 390193645Ssimon#endif 391