1/* ====================================================================
2 * Copyright (c) 2003 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 PRNG, 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/des.h>
64#include <openssl/rand.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
80#ifdef OPENSSL_FIPS
81
82#define SEED_SIZE	8
83
84static unsigned char seed[SEED_SIZE];
85static FIPS_RAND_SIZE_T n_seed;
86static FIPS_RAND_SIZE_T o_seed;
87static DES_cblock key1;
88static DES_cblock key2;
89static DES_key_schedule ks1,ks2;
90static int key_set;
91static int test_mode;
92static unsigned char test_faketime[8];
93
94#ifndef GETPID_IS_MEANINGLESS
95static int seed_pid;
96static int key_pid;
97#endif
98
99static void fips_rand_cleanup(void);
100static void fips_rand_add(const void *buf, FIPS_RAND_SIZE_T num, double add_entropy);
101static int fips_rand_bytes(unsigned char *buf, FIPS_RAND_SIZE_T num);
102static int fips_rand_status(void);
103
104static RAND_METHOD rand_fips_meth=
105    {
106    FIPS_rand_seed,
107    fips_rand_bytes,
108    fips_rand_cleanup,
109    fips_rand_add,
110    fips_rand_bytes,
111    fips_rand_status
112    };
113
114static int second;
115
116RAND_METHOD *FIPS_rand_method(void)
117{
118  return &rand_fips_meth;
119}
120
121void FIPS_set_prng_key(const unsigned char k1[8],const unsigned char k2[8])
122    {
123    memcpy(&key1,k1,sizeof key1);
124    memcpy(&key2,k2,sizeof key2);
125    key_set=1;
126#ifndef GETPID_IS_MEANINGLESS
127    key_pid=getpid();
128#endif
129    second=0;
130    }
131
132void FIPS_test_mode(int test,const unsigned char faketime[8])
133    {
134    test_mode=test;
135    if(!test_mode)
136	return;
137    memcpy(test_faketime,faketime,sizeof test_faketime);
138    }
139
140/* NB: this returns true if _partially_ seeded */
141int FIPS_rand_seeded()
142    { return key_set || n_seed; }
143
144static void fips_gettime(unsigned char buf[8])
145    {
146#ifdef OPENSSL_SYS_WIN32
147    FILETIME ft;
148#else
149    struct timeval tv;
150#endif
151
152    if(test_mode)
153	{
154	fprintf(stderr,"WARNING!!! PRNG IN TEST MODE!!!\n");
155	memcpy(buf,test_faketime,sizeof test_faketime);
156	return;
157	}
158#ifdef OPENSSL_SYS_WIN32
159    GetSystemTimeAsFileTime(&ft);
160    buf[0] = (unsigned char) (ft.dwHighDateTime & 0xff);
161    buf[1] = (unsigned char) ((ft.dwHighDateTime >> 8) & 0xff);
162    buf[2] = (unsigned char) ((ft.dwHighDateTime >> 16) & 0xff);
163    buf[3] = (unsigned char) ((ft.dwHighDateTime >> 24) & 0xff);
164    buf[4] = (unsigned char) (ft.dwLowDateTime & 0xff);
165    buf[5] = (unsigned char) ((ft.dwLowDateTime >> 8) & 0xff);
166    buf[6] = (unsigned char) ((ft.dwLowDateTime >> 16) & 0xff);
167    buf[7] = (unsigned char) ((ft.dwLowDateTime >> 24) & 0xff);
168#else
169    gettimeofday(&tv,NULL);
170    buf[0] = (unsigned char) (tv.tv_sec & 0xff);
171    buf[1] = (unsigned char) ((tv.tv_sec >> 8) & 0xff);
172    buf[2] = (unsigned char) ((tv.tv_sec >> 16) & 0xff);
173    buf[3] = (unsigned char) ((tv.tv_sec >> 24) & 0xff);
174    buf[4] = (unsigned char) (tv.tv_usec & 0xff);
175    buf[5] = (unsigned char) ((tv.tv_usec >> 8) & 0xff);
176    buf[6] = (unsigned char) ((tv.tv_usec >> 16) & 0xff);
177    buf[7] = (unsigned char) ((tv.tv_usec >> 24) & 0xff);
178#endif
179
180#if 0  /* This eminently sensible strategy is not acceptable to NIST. Sigh. */
181#ifndef GETPID_IS_MEANINGLESS
182    /* we mix in the PID to ensure that after a fork the children don't give
183     * the same results as each other
184     */
185    pid=getpid();
186    /* make sure we shift the pid to the MSB */
187    if((pid&0xffff0000) == 0)
188	pid<<=16;
189    *(long *)&buf[0]^=pid;
190#endif
191#endif
192    }
193
194static void fips_rand_encrypt(unsigned char *out,const unsigned char *in)
195    {
196    DES_ecb2_encrypt(in,out,&ks1,&ks2,1);
197    }
198
199static void fips_rand_cleanup(void)
200    {
201    OPENSSL_cleanse(seed,sizeof seed);
202    n_seed=0;
203    }
204
205void FIPS_rand_seed(const void *buf_, FIPS_RAND_SIZE_T num)
206    {
207    const char *buf=buf_;
208    FIPS_RAND_SIZE_T n;
209    static int init;
210
211    /* If the key hasn't been set, we can't seed! */
212    if(!key_set)
213	return;
214
215    CRYPTO_w_lock(CRYPTO_LOCK_RAND);
216    if(!init)
217	{
218	init=1;
219	DES_set_key(&key1,&ks1);
220	DES_set_key(&key2,&ks2);
221	}
222
223    /*
224     * This algorithm only uses 64 bits of seed, so ensure that we use
225     * the most recent 64 bits.
226     */
227    for(n=0 ; n < num ; )
228	{
229	FIPS_RAND_SIZE_T t=num-n;
230
231	if(o_seed+t > sizeof seed)
232	    t=sizeof seed-o_seed;
233	memcpy(seed+o_seed,buf+n,t);
234	n+=t;
235	o_seed+=t;
236	if(o_seed == sizeof seed)
237	    o_seed=0;
238	if(n_seed < sizeof seed)
239	    n_seed+=t;
240	}
241
242#ifndef GETPID_IS_MEANINGLESS
243    seed_pid=getpid();
244#endif
245
246    CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
247    }
248
249static void fips_rand_add(const void *buf, FIPS_RAND_SIZE_T num, double add_entropy)
250    {
251    FIPS_rand_seed(buf,num);
252    }
253
254static int fips_rand_bytes(unsigned char *buf,FIPS_RAND_SIZE_T num)
255    {
256    FIPS_RAND_SIZE_T n;
257    unsigned char timeseed[8];
258    unsigned char intermediate[SEED_SIZE];
259    unsigned char output[SEED_SIZE];
260    static unsigned char previous[SEED_SIZE];
261#ifndef GETPID_IS_MEANINGLESS
262    int pid;
263#endif
264
265    if(n_seed < sizeof seed)
266	{
267	RANDerr(RAND_F_FIPS_RAND_BYTES,RAND_R_PRNG_NOT_SEEDED);
268	return 0;
269	}
270
271#ifdef FIPS_RAND_MAX_SIZE_T
272    if (num > FIPS_RAND_MAX_SIZE_T)
273	{
274#ifdef RAND_R_PRNG_ASKING_FOR_TOO_MUCH
275	RANDerr(RAND_F_FIPS_RAND_BYTES,RAND_R_PRNG_ASKING_FOR_TOO_MUCH);
276	return 0;
277#else
278	return -1; /* signal "not supported" condition */
279#endif
280	}
281#endif
282
283#ifndef GETPID_IS_MEANINGLESS
284    pid=getpid();
285    if(pid != seed_pid)
286	{
287	RANDerr(RAND_F_FIPS_RAND_BYTES,RAND_R_PRNG_NOT_RESEEDED);
288	return 0;
289	}
290    if(pid != key_pid)
291	{
292	RANDerr(RAND_F_FIPS_RAND_BYTES,RAND_R_PRNG_NOT_REKEYED);
293	return 0;
294	}
295#endif
296
297    CRYPTO_w_lock(CRYPTO_LOCK_RAND);
298
299    for(n=0 ; n < num ; )
300	{
301	unsigned char t[SEED_SIZE];
302	FIPS_RAND_SIZE_T l;
303
304	/* ANS X9.31 A.2.4:	I = ede*K(DT)
305	       timeseed == DT
306	       intermediate == I
307	*/
308	fips_gettime(timeseed);
309	fips_rand_encrypt(intermediate,timeseed);
310
311	/* ANS X9.31 A.2.4:     R = ede*K(I^V)
312	       intermediate == I
313	       seed == V
314	       output == R
315	*/
316	for(l=0 ; l < sizeof t ; ++l)
317	    t[l]=intermediate[l]^seed[l];
318	fips_rand_encrypt(output,t);
319
320	/* ANS X9.31 A.2.4:     V = ede*K(R^I)
321	       output == R
322	       intermediate == I
323	       seed == V
324	*/
325	for(l=0 ; l < sizeof t ; ++l)
326	    t[l]=output[l]^intermediate[l];
327	fips_rand_encrypt(seed,t);
328
329	if(second && !memcmp(output,previous,sizeof previous))
330	    {
331	    RANDerr(RAND_F_FIPS_RAND_BYTES,RAND_R_PRNG_STUCK);
332	    CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
333	    return 0;
334	    }
335	memcpy(previous,output,sizeof previous);
336	second=1;
337
338	/* Successive values of R may be concatenated to produce a
339	   pseudo random number of the desired length */
340	l=SEED_SIZE < num-n ? SEED_SIZE : num-n;
341	memcpy(buf+n,output,l);
342	n+=l;
343	}
344
345    CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
346
347    return 1;
348    }
349
350static int fips_rand_status(void)
351    {
352    return n_seed == sizeof seed;
353    }
354
355#endif /* OPENSSL_FIPS */
356