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