Set FIPS mode for values other than 1. The only current effect
[openssl.git] / fips / fips.c
1 /* ====================================================================
2  * Copyright (c) 2011 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 #define OPENSSL_FIPSAPI
51
52 #include <openssl/crypto.h>
53 #include <openssl/rand.h>
54 #include <openssl/fips_rand.h>
55 #include <openssl/err.h>
56 #include <openssl/bio.h>
57 #include <openssl/hmac.h>
58 #include <openssl/rsa.h>
59 #include <openssl/dsa.h>
60 #include <openssl/ecdsa.h>
61 #include <string.h>
62 #include <limits.h>
63 #include "fips_locl.h"
64
65 #ifdef OPENSSL_FIPS
66
67 #include <openssl/fips.h>
68
69 #ifndef PATH_MAX
70 #define PATH_MAX 1024
71 #endif
72
73 static int fips_selftest_fail = 0;
74 static int fips_mode = 0;
75 static int fips_started = 0;
76
77 static int fips_is_owning_thread(void);
78 static int fips_set_owning_thread(void);
79 static int fips_clear_owning_thread(void);
80 static unsigned char *fips_signature_witness(void);
81
82 #define fips_w_lock()   CRYPTO_w_lock(CRYPTO_LOCK_FIPS)
83 #define fips_w_unlock() CRYPTO_w_unlock(CRYPTO_LOCK_FIPS)
84 #define fips_r_lock()   CRYPTO_r_lock(CRYPTO_LOCK_FIPS)
85 #define fips_r_unlock() CRYPTO_r_unlock(CRYPTO_LOCK_FIPS)
86
87 static void fips_set_mode(int onoff)
88         {
89         int owning_thread = fips_is_owning_thread();
90
91         if (fips_started)
92                 {
93                 if (!owning_thread) fips_w_lock();
94                 fips_mode = onoff;
95                 if (!owning_thread) fips_w_unlock();
96                 }
97         }
98
99 int FIPS_module_mode(void)
100         {
101         int ret = 0;
102         int owning_thread = fips_is_owning_thread();
103
104         if (fips_started)
105                 {
106                 if (!owning_thread) fips_r_lock();
107                 ret = fips_mode;
108                 if (!owning_thread) fips_r_unlock();
109                 }
110         return ret;
111         }
112
113 int FIPS_selftest_failed(void)
114     {
115     int ret = 0;
116     if (fips_started)
117         {
118         int owning_thread = fips_is_owning_thread();
119
120         if (!owning_thread) fips_r_lock();
121         ret = fips_selftest_fail;
122         if (!owning_thread) fips_r_unlock();
123         }
124     return ret;
125     }
126
127 /* Selftest failure fatal exit routine. This will be called
128  * during *any* cryptographic operation. It has the minimum
129  * overhead possible to avoid too big a performance hit.
130  */
131
132 void FIPS_selftest_check(void)
133     {
134     if (fips_selftest_fail)
135         {
136         OpenSSLDie(__FILE__,__LINE__, "FATAL FIPS SELFTEST FAILURE");
137         }
138     }
139
140 void fips_set_selftest_fail(void)
141     {
142     fips_selftest_fail = 1;
143     }
144
145 extern const void         *FIPS_text_start(),  *FIPS_text_end();
146 extern const unsigned char FIPS_rodata_start[], FIPS_rodata_end[];
147 unsigned char              FIPS_signature [20] = { 0 };
148 static const char          FIPS_hmac_key[]="etaonrishdlcupfm";
149
150 unsigned int FIPS_incore_fingerprint(unsigned char *sig,unsigned int len)
151     {
152     const unsigned char *p1 = FIPS_text_start();
153     const unsigned char *p2 = FIPS_text_end();
154     const unsigned char *p3 = FIPS_rodata_start;
155     const unsigned char *p4 = FIPS_rodata_end;
156     HMAC_CTX c;
157
158     HMAC_CTX_init(&c);
159     HMAC_Init(&c,FIPS_hmac_key,strlen(FIPS_hmac_key),EVP_sha1());
160
161     /* detect overlapping regions */
162     if (p1<=p3 && p2>=p3)
163         p3=p1, p4=p2>p4?p2:p4, p1=NULL, p2=NULL;
164     else if (p3<=p1 && p4>=p1)
165         p3=p3, p4=p2>p4?p2:p4, p1=NULL, p2=NULL;
166
167     if (p1)
168         HMAC_Update(&c,p1,(size_t)p2-(size_t)p1);
169
170     if (FIPS_signature>=p3 && FIPS_signature<p4)
171         {
172         /* "punch" hole */
173         HMAC_Update(&c,p3,(size_t)FIPS_signature-(size_t)p3);
174         p3 = FIPS_signature+sizeof(FIPS_signature);
175         if (p3<p4)
176             HMAC_Update(&c,p3,(size_t)p4-(size_t)p3);
177         }
178     else
179         HMAC_Update(&c,p3,(size_t)p4-(size_t)p3);
180
181     if (!fips_post_corrupt(FIPS_TEST_INTEGRITY, 0, NULL))
182         HMAC_Update(&c, (unsigned char *)FIPS_hmac_key, 1);
183
184     HMAC_Final(&c,sig,&len);
185     HMAC_CTX_cleanup(&c);
186
187     return len;
188     }
189
190 int FIPS_check_incore_fingerprint(void)
191     {
192     unsigned char sig[EVP_MAX_MD_SIZE];
193     unsigned int len;
194     int rv = 0;
195 #if defined(__sgi) && (defined(__mips) || defined(mips))
196     extern int __dso_displacement[];
197 #else
198     extern int OPENSSL_NONPIC_relocated;
199 #endif
200
201     if (!fips_post_started(FIPS_TEST_INTEGRITY, 0, NULL))
202         return 1;
203
204     if (FIPS_text_start()==NULL)
205         {
206         FIPSerr(FIPS_F_FIPS_CHECK_INCORE_FINGERPRINT,FIPS_R_UNSUPPORTED_PLATFORM);
207         goto err;
208         }
209
210     len=FIPS_incore_fingerprint(sig,sizeof(sig));
211
212     if (len!=sizeof(FIPS_signature) ||
213         memcmp(FIPS_signature,sig,sizeof(FIPS_signature)))
214         {
215         if (FIPS_signature>=FIPS_rodata_start && FIPS_signature<FIPS_rodata_end)
216             FIPSerr(FIPS_F_FIPS_CHECK_INCORE_FINGERPRINT,FIPS_R_FINGERPRINT_DOES_NOT_MATCH_SEGMENT_ALIASING);
217 #if defined(__sgi) && (defined(__mips) || defined(mips))
218         else if (__dso_displacement!=NULL)
219 #else
220         else if (OPENSSL_NONPIC_relocated)
221 #endif
222             FIPSerr(FIPS_F_FIPS_CHECK_INCORE_FINGERPRINT,FIPS_R_FINGERPRINT_DOES_NOT_MATCH_NONPIC_RELOCATED);
223         else
224             FIPSerr(FIPS_F_FIPS_CHECK_INCORE_FINGERPRINT,FIPS_R_FINGERPRINT_DOES_NOT_MATCH);
225 #ifdef OPENSSL_FIPS_DEBUGGER
226         rv = 1;
227 #endif
228         goto err;
229         }
230     rv = 1;
231     err:
232     if (rv == 0)
233         fips_post_failed(FIPS_TEST_INTEGRITY, 0, NULL);
234     else
235         if (!fips_post_success(FIPS_TEST_INTEGRITY, 0, NULL))
236                 return 0;
237     return rv;
238     }
239
240 int FIPS_module_mode_set(int onoff)
241     {
242     int fips_set_owning_thread();
243     int fips_clear_owning_thread();
244     int ret = 0;
245
246     fips_w_lock();
247     fips_started = 1;
248     fips_set_owning_thread();
249
250     if(onoff)
251         {
252
253         fips_selftest_fail = 0;
254
255         /* Don't go into FIPS mode twice, just so we can do automagic
256            seeding */
257         if(FIPS_module_mode())
258             {
259             FIPSerr(FIPS_F_FIPS_MODE_SET,FIPS_R_FIPS_MODE_ALREADY_SET);
260             fips_selftest_fail = 1;
261             ret = 0;
262             goto end;
263             }
264
265 #ifdef OPENSSL_IA32_SSE2
266         if ((OPENSSL_ia32cap & (1<<25|1<<26)) != (1<<25|1<<26))
267             {
268             FIPSerr(FIPS_F_FIPS_MODE_SET,FIPS_R_UNSUPPORTED_PLATFORM);
269             fips_selftest_fail = 1;
270             ret = 0;
271             goto end;
272             }
273 #endif
274
275         if(fips_signature_witness() != FIPS_signature)
276             {
277             FIPSerr(FIPS_F_FIPS_MODE_SET,FIPS_R_CONTRADICTING_EVIDENCE);
278             fips_selftest_fail = 1;
279             ret = 0;
280             goto end;
281             }
282
283         if(FIPS_selftest())
284             fips_set_mode(onoff);
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 static CRYPTO_THREADID fips_thread;
304 static int fips_thread_set = 0;
305
306 static int fips_is_owning_thread(void)
307         {
308         int ret = 0;
309
310         if (fips_started)
311                 {
312                 CRYPTO_r_lock(CRYPTO_LOCK_FIPS2);
313                 if (fips_thread_set)
314                         {
315                         CRYPTO_THREADID cur;
316                         CRYPTO_THREADID_current(&cur);
317                         if (!CRYPTO_THREADID_cmp(&cur, &fips_thread))
318                                 ret = 1;
319                         }
320                 CRYPTO_r_unlock(CRYPTO_LOCK_FIPS2);
321                 }
322         return ret;
323         }
324
325 int fips_set_owning_thread(void)
326         {
327         int ret = 0;
328
329         if (fips_started)
330                 {
331                 CRYPTO_w_lock(CRYPTO_LOCK_FIPS2);
332                 if (!fips_thread_set)
333                         {
334                         CRYPTO_THREADID_current(&fips_thread);
335                         ret = 1;
336                         fips_thread_set = 1;
337                         }
338                 CRYPTO_w_unlock(CRYPTO_LOCK_FIPS2);
339                 }
340         return ret;
341         }
342
343 int fips_clear_owning_thread(void)
344         {
345         int ret = 0;
346
347         if (fips_started)
348                 {
349                 CRYPTO_w_lock(CRYPTO_LOCK_FIPS2);
350                 if (fips_thread_set)
351                         {
352                         CRYPTO_THREADID cur;
353                         CRYPTO_THREADID_current(&cur);
354                         if (!CRYPTO_THREADID_cmp(&cur, &fips_thread))
355                                 fips_thread_set = 0;
356                         }
357                 CRYPTO_w_unlock(CRYPTO_LOCK_FIPS2);
358                 }
359         return ret;
360         }
361
362 unsigned char *fips_signature_witness(void)
363         {
364         extern unsigned char FIPS_signature[];
365         return FIPS_signature;
366         }
367
368 #if 0
369 /* The purpose of this is to ensure the error code exists and the function
370  * name is to keep the error checking script quiet
371  */
372 void hash_final(void)
373         {
374         FIPSerr(FIPS_F_HASH_FINAL,FIPS_R_NON_FIPS_METHOD);
375         }
376 #endif
377
378
379 #endif