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