fips_rand.c revision 193645
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 9193645Ssimon * 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 56193645Ssimon/* If we don't define _XOPEN_SOURCE_EXTENDED, struct timeval won't 57193645Ssimon be defined and gettimeofday() won't be declared with strict compilers 58193645Ssimon like DEC C in ANSI C mode. */ 59193645Ssimon#ifndef _XOPEN_SOURCE_EXTENDED 60193645Ssimon#define _XOPEN_SOURCE_EXTENDED 1 61193645Ssimon#endif 62193645Ssimon 63193645Ssimon#include <openssl/rand.h> 64193645Ssimon#include <openssl/aes.h> 65193645Ssimon#include <openssl/err.h> 66193645Ssimon#include <openssl/fips_rand.h> 67193645Ssimon#ifndef OPENSSL_SYS_WIN32 68193645Ssimon#include <sys/time.h> 69193645Ssimon#endif 70193645Ssimon#include <assert.h> 71193645Ssimon#ifndef OPENSSL_SYS_WIN32 72193645Ssimon# ifdef OPENSSL_UNISTD 73193645Ssimon# include OPENSSL_UNISTD 74193645Ssimon# else 75193645Ssimon# include <unistd.h> 76193645Ssimon# endif 77193645Ssimon#endif 78193645Ssimon#include <string.h> 79193645Ssimon#include <openssl/fips.h> 80193645Ssimon#include "fips_locl.h" 81193645Ssimon 82193645Ssimon#ifdef OPENSSL_FIPS 83193645Ssimon 84193645Ssimonvoid *OPENSSL_stderr(void); 85193645Ssimon 86193645Ssimon#define AES_BLOCK_LENGTH 16 87193645Ssimon 88193645Ssimon 89193645Ssimon/* AES FIPS PRNG implementation */ 90193645Ssimon 91193645Ssimontypedef struct 92193645Ssimon { 93193645Ssimon int seeded; 94193645Ssimon int keyed; 95193645Ssimon int test_mode; 96193645Ssimon int second; 97193645Ssimon int error; 98193645Ssimon unsigned long counter; 99193645Ssimon AES_KEY ks; 100193645Ssimon int vpos; 101193645Ssimon /* Temporary storage for key if it equals seed length */ 102193645Ssimon unsigned char tmp_key[AES_BLOCK_LENGTH]; 103193645Ssimon unsigned char V[AES_BLOCK_LENGTH]; 104193645Ssimon unsigned char DT[AES_BLOCK_LENGTH]; 105193645Ssimon unsigned char last[AES_BLOCK_LENGTH]; 106193645Ssimon } FIPS_PRNG_CTX; 107193645Ssimon 108193645Ssimonstatic FIPS_PRNG_CTX sctx; 109193645Ssimon 110193645Ssimonstatic int fips_prng_fail = 0; 111193645Ssimon 112193645Ssimonvoid FIPS_rng_stick(void) 113193645Ssimon { 114193645Ssimon fips_prng_fail = 1; 115193645Ssimon } 116193645Ssimon 117193645Ssimonvoid fips_rand_prng_reset(FIPS_PRNG_CTX *ctx) 118193645Ssimon { 119193645Ssimon ctx->seeded = 0; 120193645Ssimon ctx->keyed = 0; 121193645Ssimon ctx->test_mode = 0; 122193645Ssimon ctx->counter = 0; 123193645Ssimon ctx->second = 0; 124193645Ssimon ctx->error = 0; 125193645Ssimon ctx->vpos = 0; 126193645Ssimon OPENSSL_cleanse(ctx->V, AES_BLOCK_LENGTH); 127193645Ssimon OPENSSL_cleanse(&ctx->ks, sizeof(AES_KEY)); 128193645Ssimon } 129193645Ssimon 130193645Ssimon 131193645Ssimonstatic int fips_set_prng_key(FIPS_PRNG_CTX *ctx, 132193645Ssimon const unsigned char *key, FIPS_RAND_SIZE_T keylen) 133193645Ssimon { 134193645Ssimon FIPS_selftest_check(); 135193645Ssimon if (keylen != 16 && keylen != 24 && keylen != 32) 136193645Ssimon { 137193645Ssimon /* error: invalid key size */ 138193645Ssimon return 0; 139193645Ssimon } 140193645Ssimon AES_set_encrypt_key(key, keylen << 3, &ctx->ks); 141193645Ssimon if (keylen == 16) 142193645Ssimon { 143193645Ssimon memcpy(ctx->tmp_key, key, 16); 144193645Ssimon ctx->keyed = 2; 145193645Ssimon } 146193645Ssimon else 147193645Ssimon ctx->keyed = 1; 148193645Ssimon ctx->seeded = 0; 149193645Ssimon ctx->second = 0; 150193645Ssimon return 1; 151193645Ssimon } 152193645Ssimon 153193645Ssimonstatic int fips_set_prng_seed(FIPS_PRNG_CTX *ctx, 154193645Ssimon const unsigned char *seed, FIPS_RAND_SIZE_T seedlen) 155193645Ssimon { 156193645Ssimon int i; 157193645Ssimon if (!ctx->keyed) 158193645Ssimon return 0; 159193645Ssimon /* In test mode seed is just supplied data */ 160193645Ssimon if (ctx->test_mode) 161193645Ssimon { 162193645Ssimon if (seedlen != AES_BLOCK_LENGTH) 163193645Ssimon return 0; 164193645Ssimon memcpy(ctx->V, seed, AES_BLOCK_LENGTH); 165193645Ssimon ctx->seeded = 1; 166193645Ssimon return 1; 167193645Ssimon } 168193645Ssimon /* Outside test mode XOR supplied data with existing seed */ 169193645Ssimon for (i = 0; i < seedlen; i++) 170193645Ssimon { 171193645Ssimon ctx->V[ctx->vpos++] ^= seed[i]; 172193645Ssimon if (ctx->vpos == AES_BLOCK_LENGTH) 173193645Ssimon { 174193645Ssimon ctx->vpos = 0; 175193645Ssimon /* Special case if first seed and key length equals 176193645Ssimon * block size check key and seed do not match. 177193645Ssimon */ 178193645Ssimon if (ctx->keyed == 2) 179193645Ssimon { 180193645Ssimon if (!memcmp(ctx->tmp_key, ctx->V, 16)) 181193645Ssimon { 182193645Ssimon RANDerr(RAND_F_FIPS_SET_PRNG_SEED, 183193645Ssimon RAND_R_PRNG_SEED_MUST_NOT_MATCH_KEY); 184193645Ssimon return 0; 185193645Ssimon } 186193645Ssimon OPENSSL_cleanse(ctx->tmp_key, 16); 187193645Ssimon ctx->keyed = 1; 188193645Ssimon } 189193645Ssimon ctx->seeded = 1; 190193645Ssimon } 191193645Ssimon } 192193645Ssimon return 1; 193193645Ssimon } 194193645Ssimon 195193645Ssimonint fips_set_test_mode(FIPS_PRNG_CTX *ctx) 196193645Ssimon { 197193645Ssimon if (ctx->keyed) 198193645Ssimon { 199193645Ssimon RANDerr(RAND_F_FIPS_SET_TEST_MODE,RAND_R_PRNG_KEYED); 200193645Ssimon return 0; 201193645Ssimon } 202193645Ssimon ctx->test_mode = 1; 203193645Ssimon return 1; 204193645Ssimon } 205193645Ssimon 206193645Ssimonint FIPS_rand_test_mode(void) 207193645Ssimon { 208193645Ssimon return fips_set_test_mode(&sctx); 209193645Ssimon } 210193645Ssimon 211193645Ssimonint FIPS_rand_set_dt(unsigned char *dt) 212193645Ssimon { 213193645Ssimon if (!sctx.test_mode) 214193645Ssimon { 215193645Ssimon RANDerr(RAND_F_FIPS_RAND_SET_DT,RAND_R_NOT_IN_TEST_MODE); 216193645Ssimon return 0; 217193645Ssimon } 218193645Ssimon memcpy(sctx.DT, dt, AES_BLOCK_LENGTH); 219193645Ssimon return 1; 220193645Ssimon } 221193645Ssimon 222193645Ssimonstatic void fips_get_dt(FIPS_PRNG_CTX *ctx) 223193645Ssimon { 224193645Ssimon#ifdef OPENSSL_SYS_WIN32 225193645Ssimon FILETIME ft; 226193645Ssimon#else 227193645Ssimon struct timeval tv; 228193645Ssimon#endif 229193645Ssimon unsigned char *buf = ctx->DT; 230193645Ssimon 231193645Ssimon#ifndef GETPID_IS_MEANINGLESS 232193645Ssimon unsigned long pid; 233193645Ssimon#endif 234193645Ssimon 235193645Ssimon#ifdef OPENSSL_SYS_WIN32 236193645Ssimon GetSystemTimeAsFileTime(&ft); 237193645Ssimon buf[0] = (unsigned char) (ft.dwHighDateTime & 0xff); 238193645Ssimon buf[1] = (unsigned char) ((ft.dwHighDateTime >> 8) & 0xff); 239193645Ssimon buf[2] = (unsigned char) ((ft.dwHighDateTime >> 16) & 0xff); 240193645Ssimon buf[3] = (unsigned char) ((ft.dwHighDateTime >> 24) & 0xff); 241193645Ssimon buf[4] = (unsigned char) (ft.dwLowDateTime & 0xff); 242193645Ssimon buf[5] = (unsigned char) ((ft.dwLowDateTime >> 8) & 0xff); 243193645Ssimon buf[6] = (unsigned char) ((ft.dwLowDateTime >> 16) & 0xff); 244193645Ssimon buf[7] = (unsigned char) ((ft.dwLowDateTime >> 24) & 0xff); 245193645Ssimon#else 246193645Ssimon gettimeofday(&tv,NULL); 247193645Ssimon buf[0] = (unsigned char) (tv.tv_sec & 0xff); 248193645Ssimon buf[1] = (unsigned char) ((tv.tv_sec >> 8) & 0xff); 249193645Ssimon buf[2] = (unsigned char) ((tv.tv_sec >> 16) & 0xff); 250193645Ssimon buf[3] = (unsigned char) ((tv.tv_sec >> 24) & 0xff); 251193645Ssimon buf[4] = (unsigned char) (tv.tv_usec & 0xff); 252193645Ssimon buf[5] = (unsigned char) ((tv.tv_usec >> 8) & 0xff); 253193645Ssimon buf[6] = (unsigned char) ((tv.tv_usec >> 16) & 0xff); 254193645Ssimon buf[7] = (unsigned char) ((tv.tv_usec >> 24) & 0xff); 255193645Ssimon#endif 256193645Ssimon buf[8] = (unsigned char) (ctx->counter & 0xff); 257193645Ssimon buf[9] = (unsigned char) ((ctx->counter >> 8) & 0xff); 258193645Ssimon buf[10] = (unsigned char) ((ctx->counter >> 16) & 0xff); 259193645Ssimon buf[11] = (unsigned char) ((ctx->counter >> 24) & 0xff); 260193645Ssimon 261193645Ssimon ctx->counter++; 262193645Ssimon 263193645Ssimon 264193645Ssimon#ifndef GETPID_IS_MEANINGLESS 265193645Ssimon pid=(unsigned long)getpid(); 266193645Ssimon buf[12] = (unsigned char) (pid & 0xff); 267193645Ssimon buf[13] = (unsigned char) ((pid >> 8) & 0xff); 268193645Ssimon buf[14] = (unsigned char) ((pid >> 16) & 0xff); 269193645Ssimon buf[15] = (unsigned char) ((pid >> 24) & 0xff); 270193645Ssimon#endif 271193645Ssimon } 272193645Ssimon 273193645Ssimonstatic int fips_rand(FIPS_PRNG_CTX *ctx, 274193645Ssimon unsigned char *out, FIPS_RAND_SIZE_T outlen) 275193645Ssimon { 276193645Ssimon unsigned char R[AES_BLOCK_LENGTH], I[AES_BLOCK_LENGTH]; 277193645Ssimon unsigned char tmp[AES_BLOCK_LENGTH]; 278193645Ssimon int i; 279193645Ssimon if (ctx->error) 280193645Ssimon { 281193645Ssimon RANDerr(RAND_F_FIPS_RAND,RAND_R_PRNG_ERROR); 282193645Ssimon return 0; 283193645Ssimon } 284193645Ssimon if (!ctx->keyed) 285193645Ssimon { 286193645Ssimon RANDerr(RAND_F_FIPS_RAND,RAND_R_NO_KEY_SET); 287193645Ssimon return 0; 288193645Ssimon } 289193645Ssimon if (!ctx->seeded) 290193645Ssimon { 291193645Ssimon RANDerr(RAND_F_FIPS_RAND,RAND_R_PRNG_NOT_SEEDED); 292193645Ssimon return 0; 293193645Ssimon } 294193645Ssimon for (;;) 295193645Ssimon { 296193645Ssimon if (!ctx->test_mode) 297193645Ssimon fips_get_dt(ctx); 298193645Ssimon AES_encrypt(ctx->DT, I, &ctx->ks); 299193645Ssimon for (i = 0; i < AES_BLOCK_LENGTH; i++) 300193645Ssimon tmp[i] = I[i] ^ ctx->V[i]; 301193645Ssimon AES_encrypt(tmp, R, &ctx->ks); 302193645Ssimon for (i = 0; i < AES_BLOCK_LENGTH; i++) 303193645Ssimon tmp[i] = R[i] ^ I[i]; 304193645Ssimon AES_encrypt(tmp, ctx->V, &ctx->ks); 305193645Ssimon /* Continuous PRNG test */ 306193645Ssimon if (ctx->second) 307193645Ssimon { 308193645Ssimon if (fips_prng_fail) 309193645Ssimon memcpy(ctx->last, R, AES_BLOCK_LENGTH); 310193645Ssimon if (!memcmp(R, ctx->last, AES_BLOCK_LENGTH)) 311193645Ssimon { 312193645Ssimon RANDerr(RAND_F_FIPS_RAND,RAND_R_PRNG_STUCK); 313193645Ssimon ctx->error = 1; 314193645Ssimon fips_set_selftest_fail(); 315193645Ssimon return 0; 316193645Ssimon } 317193645Ssimon } 318193645Ssimon memcpy(ctx->last, R, AES_BLOCK_LENGTH); 319193645Ssimon if (!ctx->second) 320193645Ssimon { 321193645Ssimon ctx->second = 1; 322193645Ssimon if (!ctx->test_mode) 323193645Ssimon continue; 324193645Ssimon } 325193645Ssimon 326193645Ssimon if (outlen <= AES_BLOCK_LENGTH) 327193645Ssimon { 328193645Ssimon memcpy(out, R, outlen); 329193645Ssimon break; 330193645Ssimon } 331193645Ssimon 332193645Ssimon memcpy(out, R, AES_BLOCK_LENGTH); 333193645Ssimon out += AES_BLOCK_LENGTH; 334193645Ssimon outlen -= AES_BLOCK_LENGTH; 335193645Ssimon } 336193645Ssimon return 1; 337193645Ssimon } 338193645Ssimon 339193645Ssimon 340193645Ssimonint FIPS_rand_set_key(const unsigned char *key, FIPS_RAND_SIZE_T keylen) 341193645Ssimon { 342193645Ssimon int ret; 343193645Ssimon CRYPTO_w_lock(CRYPTO_LOCK_RAND); 344193645Ssimon ret = fips_set_prng_key(&sctx, key, keylen); 345193645Ssimon CRYPTO_w_unlock(CRYPTO_LOCK_RAND); 346193645Ssimon return ret; 347193645Ssimon } 348193645Ssimon 349193645Ssimonint FIPS_rand_seed(const void *seed, FIPS_RAND_SIZE_T seedlen) 350193645Ssimon { 351193645Ssimon int ret; 352193645Ssimon CRYPTO_w_lock(CRYPTO_LOCK_RAND); 353193645Ssimon ret = fips_set_prng_seed(&sctx, seed, seedlen); 354193645Ssimon CRYPTO_w_unlock(CRYPTO_LOCK_RAND); 355193645Ssimon return ret; 356193645Ssimon } 357193645Ssimon 358193645Ssimon 359193645Ssimonint FIPS_rand_bytes(unsigned char *out, FIPS_RAND_SIZE_T count) 360193645Ssimon { 361193645Ssimon int ret; 362193645Ssimon CRYPTO_w_lock(CRYPTO_LOCK_RAND); 363193645Ssimon ret = fips_rand(&sctx, out, count); 364193645Ssimon CRYPTO_w_unlock(CRYPTO_LOCK_RAND); 365193645Ssimon return ret; 366193645Ssimon } 367193645Ssimon 368193645Ssimonint FIPS_rand_status(void) 369193645Ssimon { 370193645Ssimon int ret; 371193645Ssimon CRYPTO_r_lock(CRYPTO_LOCK_RAND); 372193645Ssimon ret = sctx.seeded; 373193645Ssimon CRYPTO_r_unlock(CRYPTO_LOCK_RAND); 374193645Ssimon return ret; 375193645Ssimon } 376193645Ssimon 377193645Ssimonvoid FIPS_rand_reset(void) 378193645Ssimon { 379193645Ssimon CRYPTO_w_lock(CRYPTO_LOCK_RAND); 380193645Ssimon fips_rand_prng_reset(&sctx); 381193645Ssimon CRYPTO_w_unlock(CRYPTO_LOCK_RAND); 382193645Ssimon } 383193645Ssimon 384193645Ssimonstatic void fips_do_rand_seed(const void *seed, FIPS_RAND_SIZE_T seedlen) 385193645Ssimon { 386193645Ssimon FIPS_rand_seed(seed, seedlen); 387193645Ssimon } 388193645Ssimon 389193645Ssimonstatic void fips_do_rand_add(const void *seed, FIPS_RAND_SIZE_T seedlen, 390193645Ssimon double add_entropy) 391193645Ssimon { 392193645Ssimon FIPS_rand_seed(seed, seedlen); 393193645Ssimon } 394193645Ssimon 395193645Ssimonstatic const RAND_METHOD rand_fips_meth= 396193645Ssimon { 397193645Ssimon fips_do_rand_seed, 398193645Ssimon FIPS_rand_bytes, 399193645Ssimon FIPS_rand_reset, 400193645Ssimon fips_do_rand_add, 401193645Ssimon FIPS_rand_bytes, 402193645Ssimon FIPS_rand_status 403193645Ssimon }; 404193645Ssimon 405193645Ssimonconst RAND_METHOD *FIPS_rand_method(void) 406193645Ssimon{ 407193645Ssimon return &rand_fips_meth; 408193645Ssimon} 409193645Ssimon 410193645Ssimon#endif 411