And so it begins...
[oweals/openssl.git] / fips-1.0 / fips.c
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 #include <openssl/fips.h>
51 #include <openssl/rand.h>
52 #include <openssl/fips_rand.h>
53 #include <openssl/err.h>
54 #include <openssl/bio.h>
55 #include <openssl/hmac.h>
56 #include <string.h>
57 #include <limits.h>
58 #include "fips_locl.h"
59
60 #ifdef OPENSSL_FIPS
61
62 #ifndef PATH_MAX
63 #define PATH_MAX 1024
64 #endif
65
66 static int fips_selftest_fail;
67 static int fips_mode;
68 static const void *fips_rand_check;
69
70 static void fips_set_mode(int onoff)
71         {
72         int owning_thread = fips_is_owning_thread();
73
74         if (fips_is_started())
75                 {
76                 if (!owning_thread) fips_w_lock();
77                 fips_mode = onoff;
78                 if (!owning_thread) fips_w_unlock();
79                 }
80         }
81
82 static void fips_set_rand_check(const void *rand_check)
83         {
84         int owning_thread = fips_is_owning_thread();
85
86         if (fips_is_started())
87                 {
88                 if (!owning_thread) fips_w_lock();
89                 fips_rand_check = rand_check;
90                 if (!owning_thread) fips_w_unlock();
91                 }
92         }
93
94 int FIPS_mode(void)
95         {
96         int ret = 0;
97         int owning_thread = fips_is_owning_thread();
98
99         if (fips_is_started())
100                 {
101                 if (!owning_thread) fips_r_lock();
102                 ret = fips_mode;
103                 if (!owning_thread) fips_r_unlock();
104                 }
105         return ret;
106         }
107
108 const void *FIPS_rand_check(void)
109         {
110         const void *ret = 0;
111         int owning_thread = fips_is_owning_thread();
112
113         if (fips_is_started())
114                 {
115                 if (!owning_thread) fips_r_lock();
116                 ret = fips_rand_check;
117                 if (!owning_thread) fips_r_unlock();
118                 }
119         return ret;
120         }
121
122 int FIPS_selftest_failed(void)
123     {
124     int ret = 0;
125     if (fips_is_started())
126         {
127         int owning_thread = fips_is_owning_thread();
128
129         if (!owning_thread) fips_r_lock();
130         ret = fips_selftest_fail;
131         if (!owning_thread) fips_r_unlock();
132         }
133     return ret;
134     }
135
136 int FIPS_selftest()
137     {
138
139     return FIPS_selftest_sha1()
140         && FIPS_selftest_hmac()
141         && FIPS_selftest_aes()
142         && FIPS_selftest_des()
143         && FIPS_selftest_rsa()
144         && FIPS_selftest_dsa();
145     }
146
147 extern const void         *FIPS_text_start(),  *FIPS_text_end();
148 extern const unsigned char FIPS_rodata_start[], FIPS_rodata_end[];
149 unsigned char              FIPS_signature [20] = { 0 };
150 static const char          FIPS_hmac_key[]="etaonrishdlcupfm";
151
152 unsigned int FIPS_incore_fingerprint(unsigned char *sig,unsigned int len)
153     {
154     const unsigned char *p1 = FIPS_text_start();
155     const unsigned char *p2 = FIPS_text_end();
156     const unsigned char *p3 = FIPS_rodata_start;
157     const unsigned char *p4 = FIPS_rodata_end;
158     HMAC_CTX c;
159
160     HMAC_CTX_init(&c);
161     HMAC_Init(&c,FIPS_hmac_key,strlen(FIPS_hmac_key),EVP_sha1());
162
163     /* detect overlapping regions */
164     if (p1<=p3 && p2>=p3)
165         p3=p1, p4=p2>p4?p2:p4, p1=NULL, p2=NULL;
166     else if (p3<=p1 && p4>=p1)
167         p3=p3, p4=p2>p4?p2:p4, p1=NULL, p2=NULL;
168
169     if (p1)
170         HMAC_Update(&c,p1,(size_t)p2-(size_t)p1);
171
172     if (FIPS_signature>=p3 && FIPS_signature<p4)
173         {
174         /* "punch" hole */
175         HMAC_Update(&c,p3,(size_t)FIPS_signature-(size_t)p3);
176         p3 = FIPS_signature+sizeof(FIPS_signature);
177         if (p3<p4)
178             HMAC_Update(&c,p3,(size_t)p4-(size_t)p3);
179         }
180     else
181         HMAC_Update(&c,p3,(size_t)p4-(size_t)p3);
182
183     HMAC_Final(&c,sig,&len);
184     HMAC_CTX_cleanup(&c);
185
186     return len;
187     }
188
189 int FIPS_check_incore_fingerprint(void)
190     {
191     unsigned char sig[EVP_MAX_MD_SIZE];
192     unsigned int len;
193     extern int OPENSSL_NONPIC_relocated;
194
195     if (FIPS_text_start()==NULL)
196         {
197         FIPSerr(FIPS_F_FIPS_CHECK_FINGERPRINT,FIPS_R_UNSUPPORTED_PLATFORM);
198         return 0;
199         }
200
201     len=FIPS_incore_fingerprint (sig,sizeof(sig));
202
203     if (len!=sizeof(FIPS_signature) ||
204         memcmp(FIPS_signature,sig,sizeof(FIPS_signature)))
205         {
206         if (FIPS_signature>=FIPS_rodata_start && FIPS_signature<FIPS_rodata_end)
207             FIPSerr(FIPS_F_FIPS_CHECK_FINGERPRINT,FIPS_R_FINGERPRINT_DOES_NOT_MATCH_SEGMENT_ALIASING);
208         else if (OPENSSL_NONPIC_relocated)
209             FIPSerr(FIPS_F_FIPS_CHECK_FINGERPRINT,FIPS_R_FINGERPRINT_DOES_NOT_MATCH_NONPIC_RELOCATED);
210         else
211             FIPSerr(FIPS_F_FIPS_CHECK_FINGERPRINT,FIPS_R_FINGERPRINT_DOES_NOT_MATCH);
212         return 0;
213         }
214
215     return 1;
216     }
217
218 int FIPS_mode_set(int onoff)
219     {
220     int fips_set_owning_thread();
221     int fips_clear_owning_thread();
222     int ret = 0;
223
224     fips_w_lock();
225     fips_set_started();
226     fips_set_owning_thread();
227
228     if(onoff)
229         {
230         unsigned char buf[48];
231
232         fips_selftest_fail = 0;
233
234         /* Don't go into FIPS mode twice, just so we can do automagic
235            seeding */
236         if(FIPS_mode())
237             {
238             FIPSerr(FIPS_F_FIPS_MODE_SET,FIPS_R_FIPS_MODE_ALREADY_SET);
239             fips_selftest_fail = 1;
240             ret = 0;
241             goto end;
242             }
243
244         if(fips_signature_witness() != FIPS_signature)
245             {
246             FIPSerr(FIPS_F_FIPS_MODE_SET,FIPS_R_CONTRADICTING_EVIDENCE);
247             fips_selftest_fail = 1;
248             ret = 0;
249             goto end;
250             }
251
252         if(!FIPS_check_incore_fingerprint())
253             {
254             fips_selftest_fail = 1;
255             ret = 0;
256             goto end;
257             }
258
259         /* Perform RNG KAT before seeding */
260         if (!FIPS_selftest_rng())
261             {
262             fips_selftest_fail = 1;
263             ret = 0;
264             goto end;
265             }
266
267         /* automagically seed PRNG if not already seeded */
268         if(!FIPS_rand_status())
269             {
270             if(RAND_bytes(buf,sizeof buf) <= 0)
271                 {
272                 fips_selftest_fail = 1;
273                 ret = 0;
274                 goto end;
275                 }
276             FIPS_rand_set_key(buf,32);
277             FIPS_rand_seed(buf+32,16);
278             }
279
280         /* now switch into FIPS mode */
281         fips_set_rand_check(FIPS_rand_method());
282         RAND_set_rand_method(FIPS_rand_method());
283         if(FIPS_selftest())
284             fips_set_mode(1);
285         else
286             {
287             fips_selftest_fail = 1;
288             ret = 0;
289             goto end;
290             }
291         ret = 1;
292         goto end;
293         }
294     fips_set_mode(0);
295     fips_selftest_fail = 0;
296     ret = 1;
297 end:
298     fips_clear_owning_thread();
299     fips_w_unlock();
300     return ret;
301     }
302
303 #if 0
304 /* here just to cause error codes to exist */
305 static void dummy()
306     {
307     FIPSerr(FIPS_F_HASH_FINAL,FIPS_F_NON_FIPS_METHOD);
308     FIPSerr(FIPS_F_HASH_FINAL,FIPS_R_FIPS_SELFTEST_FAILED);
309     }
310 #endif
311
312 void fips_w_lock(void)          { CRYPTO_w_lock(CRYPTO_LOCK_FIPS); }
313 void fips_w_unlock(void)        { CRYPTO_w_unlock(CRYPTO_LOCK_FIPS); }
314 void fips_r_lock(void)          { CRYPTO_r_lock(CRYPTO_LOCK_FIPS); }
315 void fips_r_unlock(void)        { CRYPTO_r_unlock(CRYPTO_LOCK_FIPS); }
316
317 static int fips_started = 0;
318 static unsigned long fips_thread = 0;
319
320 void fips_set_started(void)
321         {
322         fips_started = 1;
323         }
324
325 int fips_is_started(void)
326         {
327         return fips_started;
328         }
329
330 int fips_is_owning_thread(void)
331         {
332         int ret = 0;
333
334         if (fips_is_started())
335                 {
336                 CRYPTO_r_lock(CRYPTO_LOCK_FIPS2);
337                 if (fips_thread != 0 && fips_thread == CRYPTO_thread_id())
338                         ret = 1;
339                 CRYPTO_r_unlock(CRYPTO_LOCK_FIPS2);
340                 }
341         return ret;
342         }
343
344 int fips_set_owning_thread(void)
345         {
346         int ret = 0;
347
348         if (fips_is_started())
349                 {
350                 CRYPTO_w_lock(CRYPTO_LOCK_FIPS2);
351                 if (fips_thread == 0)
352                         {
353                         fips_thread = CRYPTO_thread_id();
354                         ret = 1;
355                         }
356                 CRYPTO_w_unlock(CRYPTO_LOCK_FIPS2);
357                 }
358         return ret;
359         }
360
361 int fips_clear_owning_thread(void)
362         {
363         int ret = 0;
364
365         if (fips_is_started())
366                 {
367                 CRYPTO_w_lock(CRYPTO_LOCK_FIPS2);
368                 if (fips_thread == CRYPTO_thread_id())
369                         {
370                         fips_thread = 0;
371                         ret = 1;
372                         }
373                 CRYPTO_w_unlock(CRYPTO_LOCK_FIPS2);
374                 }
375         return ret;
376         }
377
378 unsigned char *fips_signature_witness(void)
379         {
380         extern unsigned char FIPS_signature[];
381         return FIPS_signature;
382         }
383
384 #endif