fips_rand.c revision 194206
1/* ==================================================================== 2 * Copyright (c) 2007 The OpenSSL Project. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in 13 * the documentation and/or other materials provided with the 14 * distribution. 15 * 16 * 3. All advertising materials mentioning features or use of this 17 * software must display the following acknowledgment: 18 * "This product includes software developed by the OpenSSL Project 19 * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" 20 * 21 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 22 * endorse or promote products derived from this software without 23 * prior written permission. For written permission, please contact 24 * openssl-core@openssl.org. 25 * 26 * 5. Products derived from this software may not be called "OpenSSL" 27 * nor may "OpenSSL" appear in their names without prior written 28 * permission of the OpenSSL Project. 29 * 30 * 6. Redistributions of any form whatsoever must retain the following 31 * acknowledgment: 32 * "This product includes software developed by the OpenSSL Project 33 * for use in the OpenSSL Toolkit (http://www.openssl.org/)" 34 * 35 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 36 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 37 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 38 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 41 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 42 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 43 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 44 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 45 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 46 * OF THE POSSIBILITY OF SUCH DAMAGE. 47 * 48 */ 49 50/* 51 * This is a FIPS approved AES PRNG based on ANSI X9.31 A.2.4. 52 */ 53 54#include "e_os.h" 55 56/* If we don't define _XOPEN_SOURCE_EXTENDED, struct timeval won't 57 be defined and gettimeofday() won't be declared with strict compilers 58 like DEC C in ANSI C mode. */ 59#ifndef _XOPEN_SOURCE_EXTENDED 60#define _XOPEN_SOURCE_EXTENDED 1 61#endif 62 63#include <openssl/rand.h> 64#include <openssl/aes.h> 65#include <openssl/err.h> 66#include <openssl/fips_rand.h> 67#ifndef OPENSSL_SYS_WIN32 68#include <sys/time.h> 69#endif 70#include <assert.h> 71#ifndef OPENSSL_SYS_WIN32 72# ifdef OPENSSL_UNISTD 73# include OPENSSL_UNISTD 74# else 75# include <unistd.h> 76# endif 77#endif 78#include <string.h> 79#include <openssl/fips.h> 80#include "fips_locl.h" 81 82#ifdef OPENSSL_FIPS 83 84void *OPENSSL_stderr(void); 85 86#define AES_BLOCK_LENGTH 16 87 88 89/* AES FIPS PRNG implementation */ 90 91typedef struct 92 { 93 int seeded; 94 int keyed; 95 int test_mode; 96 int second; 97 int error; 98 unsigned long counter; 99 AES_KEY ks; 100 int vpos; 101 /* Temporary storage for key if it equals seed length */ 102 unsigned char tmp_key[AES_BLOCK_LENGTH]; 103 unsigned char V[AES_BLOCK_LENGTH]; 104 unsigned char DT[AES_BLOCK_LENGTH]; 105 unsigned char last[AES_BLOCK_LENGTH]; 106 } FIPS_PRNG_CTX; 107 108static FIPS_PRNG_CTX sctx; 109 110static int fips_prng_fail = 0; 111 112void FIPS_rng_stick(void) 113 { 114 fips_prng_fail = 1; 115 } 116 117void fips_rand_prng_reset(FIPS_PRNG_CTX *ctx) 118 { 119 ctx->seeded = 0; 120 ctx->keyed = 0; 121 ctx->test_mode = 0; 122 ctx->counter = 0; 123 ctx->second = 0; 124 ctx->error = 0; 125 ctx->vpos = 0; 126 OPENSSL_cleanse(ctx->V, AES_BLOCK_LENGTH); 127 OPENSSL_cleanse(&ctx->ks, sizeof(AES_KEY)); 128 } 129 130 131static int fips_set_prng_key(FIPS_PRNG_CTX *ctx, 132 const unsigned char *key, FIPS_RAND_SIZE_T keylen) 133 { 134 FIPS_selftest_check(); 135 if (keylen != 16 && keylen != 24 && keylen != 32) 136 { 137 /* error: invalid key size */ 138 return 0; 139 } 140 AES_set_encrypt_key(key, keylen << 3, &ctx->ks); 141 if (keylen == 16) 142 { 143 memcpy(ctx->tmp_key, key, 16); 144 ctx->keyed = 2; 145 } 146 else 147 ctx->keyed = 1; 148 ctx->seeded = 0; 149 ctx->second = 0; 150 return 1; 151 } 152 153static int fips_set_prng_seed(FIPS_PRNG_CTX *ctx, 154 const unsigned char *seed, FIPS_RAND_SIZE_T seedlen) 155 { 156 int i; 157 if (!ctx->keyed) 158 return 0; 159 /* In test mode seed is just supplied data */ 160 if (ctx->test_mode) 161 { 162 if (seedlen != AES_BLOCK_LENGTH) 163 return 0; 164 memcpy(ctx->V, seed, AES_BLOCK_LENGTH); 165 ctx->seeded = 1; 166 return 1; 167 } 168 /* Outside test mode XOR supplied data with existing seed */ 169 for (i = 0; i < seedlen; i++) 170 { 171 ctx->V[ctx->vpos++] ^= seed[i]; 172 if (ctx->vpos == AES_BLOCK_LENGTH) 173 { 174 ctx->vpos = 0; 175 /* Special case if first seed and key length equals 176 * block size check key and seed do not match. 177 */ 178 if (ctx->keyed == 2) 179 { 180 if (!memcmp(ctx->tmp_key, ctx->V, 16)) 181 { 182 RANDerr(RAND_F_FIPS_SET_PRNG_SEED, 183 RAND_R_PRNG_SEED_MUST_NOT_MATCH_KEY); 184 return 0; 185 } 186 OPENSSL_cleanse(ctx->tmp_key, 16); 187 ctx->keyed = 1; 188 } 189 ctx->seeded = 1; 190 } 191 } 192 return 1; 193 } 194 195int fips_set_test_mode(FIPS_PRNG_CTX *ctx) 196 { 197 if (ctx->keyed) 198 { 199 RANDerr(RAND_F_FIPS_SET_TEST_MODE,RAND_R_PRNG_KEYED); 200 return 0; 201 } 202 ctx->test_mode = 1; 203 return 1; 204 } 205 206int FIPS_rand_test_mode(void) 207 { 208 return fips_set_test_mode(&sctx); 209 } 210 211int FIPS_rand_set_dt(unsigned char *dt) 212 { 213 if (!sctx.test_mode) 214 { 215 RANDerr(RAND_F_FIPS_RAND_SET_DT,RAND_R_NOT_IN_TEST_MODE); 216 return 0; 217 } 218 memcpy(sctx.DT, dt, AES_BLOCK_LENGTH); 219 return 1; 220 } 221 222static void fips_get_dt(FIPS_PRNG_CTX *ctx) 223 { 224#ifdef OPENSSL_SYS_WIN32 225 FILETIME ft; 226#else 227 struct timeval tv; 228#endif 229 unsigned char *buf = ctx->DT; 230 231#ifndef GETPID_IS_MEANINGLESS 232 unsigned long pid; 233#endif 234 235#ifdef OPENSSL_SYS_WIN32 236 GetSystemTimeAsFileTime(&ft); 237 buf[0] = (unsigned char) (ft.dwHighDateTime & 0xff); 238 buf[1] = (unsigned char) ((ft.dwHighDateTime >> 8) & 0xff); 239 buf[2] = (unsigned char) ((ft.dwHighDateTime >> 16) & 0xff); 240 buf[3] = (unsigned char) ((ft.dwHighDateTime >> 24) & 0xff); 241 buf[4] = (unsigned char) (ft.dwLowDateTime & 0xff); 242 buf[5] = (unsigned char) ((ft.dwLowDateTime >> 8) & 0xff); 243 buf[6] = (unsigned char) ((ft.dwLowDateTime >> 16) & 0xff); 244 buf[7] = (unsigned char) ((ft.dwLowDateTime >> 24) & 0xff); 245#else 246 gettimeofday(&tv,NULL); 247 buf[0] = (unsigned char) (tv.tv_sec & 0xff); 248 buf[1] = (unsigned char) ((tv.tv_sec >> 8) & 0xff); 249 buf[2] = (unsigned char) ((tv.tv_sec >> 16) & 0xff); 250 buf[3] = (unsigned char) ((tv.tv_sec >> 24) & 0xff); 251 buf[4] = (unsigned char) (tv.tv_usec & 0xff); 252 buf[5] = (unsigned char) ((tv.tv_usec >> 8) & 0xff); 253 buf[6] = (unsigned char) ((tv.tv_usec >> 16) & 0xff); 254 buf[7] = (unsigned char) ((tv.tv_usec >> 24) & 0xff); 255#endif 256 buf[8] = (unsigned char) (ctx->counter & 0xff); 257 buf[9] = (unsigned char) ((ctx->counter >> 8) & 0xff); 258 buf[10] = (unsigned char) ((ctx->counter >> 16) & 0xff); 259 buf[11] = (unsigned char) ((ctx->counter >> 24) & 0xff); 260 261 ctx->counter++; 262 263 264#ifndef GETPID_IS_MEANINGLESS 265 pid=(unsigned long)getpid(); 266 buf[12] = (unsigned char) (pid & 0xff); 267 buf[13] = (unsigned char) ((pid >> 8) & 0xff); 268 buf[14] = (unsigned char) ((pid >> 16) & 0xff); 269 buf[15] = (unsigned char) ((pid >> 24) & 0xff); 270#endif 271 } 272 273static int fips_rand(FIPS_PRNG_CTX *ctx, 274 unsigned char *out, FIPS_RAND_SIZE_T outlen) 275 { 276 unsigned char R[AES_BLOCK_LENGTH], I[AES_BLOCK_LENGTH]; 277 unsigned char tmp[AES_BLOCK_LENGTH]; 278 int i; 279 if (ctx->error) 280 { 281 RANDerr(RAND_F_FIPS_RAND,RAND_R_PRNG_ERROR); 282 return 0; 283 } 284 if (!ctx->keyed) 285 { 286 RANDerr(RAND_F_FIPS_RAND,RAND_R_NO_KEY_SET); 287 return 0; 288 } 289 if (!ctx->seeded) 290 { 291 RANDerr(RAND_F_FIPS_RAND,RAND_R_PRNG_NOT_SEEDED); 292 return 0; 293 } 294 for (;;) 295 { 296 if (!ctx->test_mode) 297 fips_get_dt(ctx); 298 AES_encrypt(ctx->DT, I, &ctx->ks); 299 for (i = 0; i < AES_BLOCK_LENGTH; i++) 300 tmp[i] = I[i] ^ ctx->V[i]; 301 AES_encrypt(tmp, R, &ctx->ks); 302 for (i = 0; i < AES_BLOCK_LENGTH; i++) 303 tmp[i] = R[i] ^ I[i]; 304 AES_encrypt(tmp, ctx->V, &ctx->ks); 305 /* Continuous PRNG test */ 306 if (ctx->second) 307 { 308 if (fips_prng_fail) 309 memcpy(ctx->last, R, AES_BLOCK_LENGTH); 310 if (!memcmp(R, ctx->last, AES_BLOCK_LENGTH)) 311 { 312 RANDerr(RAND_F_FIPS_RAND,RAND_R_PRNG_STUCK); 313 ctx->error = 1; 314 fips_set_selftest_fail(); 315 return 0; 316 } 317 } 318 memcpy(ctx->last, R, AES_BLOCK_LENGTH); 319 if (!ctx->second) 320 { 321 ctx->second = 1; 322 if (!ctx->test_mode) 323 continue; 324 } 325 326 if (outlen <= AES_BLOCK_LENGTH) 327 { 328 memcpy(out, R, outlen); 329 break; 330 } 331 332 memcpy(out, R, AES_BLOCK_LENGTH); 333 out += AES_BLOCK_LENGTH; 334 outlen -= AES_BLOCK_LENGTH; 335 } 336 return 1; 337 } 338 339 340int FIPS_rand_set_key(const unsigned char *key, FIPS_RAND_SIZE_T keylen) 341 { 342 int ret; 343 CRYPTO_w_lock(CRYPTO_LOCK_RAND); 344 ret = fips_set_prng_key(&sctx, key, keylen); 345 CRYPTO_w_unlock(CRYPTO_LOCK_RAND); 346 return ret; 347 } 348 349int FIPS_rand_seed(const void *seed, FIPS_RAND_SIZE_T seedlen) 350 { 351 int ret; 352 CRYPTO_w_lock(CRYPTO_LOCK_RAND); 353 ret = fips_set_prng_seed(&sctx, seed, seedlen); 354 CRYPTO_w_unlock(CRYPTO_LOCK_RAND); 355 return ret; 356 } 357 358 359int FIPS_rand_bytes(unsigned char *out, FIPS_RAND_SIZE_T count) 360 { 361 int ret; 362 CRYPTO_w_lock(CRYPTO_LOCK_RAND); 363 ret = fips_rand(&sctx, out, count); 364 CRYPTO_w_unlock(CRYPTO_LOCK_RAND); 365 return ret; 366 } 367 368int FIPS_rand_status(void) 369 { 370 int ret; 371 CRYPTO_r_lock(CRYPTO_LOCK_RAND); 372 ret = sctx.seeded; 373 CRYPTO_r_unlock(CRYPTO_LOCK_RAND); 374 return ret; 375 } 376 377void FIPS_rand_reset(void) 378 { 379 CRYPTO_w_lock(CRYPTO_LOCK_RAND); 380 fips_rand_prng_reset(&sctx); 381 CRYPTO_w_unlock(CRYPTO_LOCK_RAND); 382 } 383 384static void fips_do_rand_seed(const void *seed, FIPS_RAND_SIZE_T seedlen) 385 { 386 FIPS_rand_seed(seed, seedlen); 387 } 388 389static void fips_do_rand_add(const void *seed, FIPS_RAND_SIZE_T seedlen, 390 double add_entropy) 391 { 392 FIPS_rand_seed(seed, seedlen); 393 } 394 395static const RAND_METHOD rand_fips_meth= 396 { 397 fips_do_rand_seed, 398 FIPS_rand_bytes, 399 FIPS_rand_reset, 400 fips_do_rand_add, 401 FIPS_rand_bytes, 402 FIPS_rand_status 403 }; 404 405const RAND_METHOD *FIPS_rand_method(void) 406{ 407 return &rand_fips_meth; 408} 409 410#endif 411