clarify comment
[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 __fips_constseg
149 static const char          FIPS_hmac_key[]="etaonrishdlcupfm";
150
151 unsigned int FIPS_incore_fingerprint(unsigned char *sig,unsigned int len)
152     {
153     const unsigned char *p1 = FIPS_text_start();
154     const unsigned char *p2 = FIPS_text_end();
155     const unsigned char *p3 = FIPS_rodata_start;
156     const unsigned char *p4 = FIPS_rodata_end;
157     HMAC_CTX c;
158
159     HMAC_CTX_init(&c);
160     HMAC_Init(&c,FIPS_hmac_key,strlen(FIPS_hmac_key),EVP_sha1());
161
162     /* detect overlapping regions */
163     if (p1<=p3 && p2>=p3)
164         p3=p1, p4=p2>p4?p2:p4, p1=NULL, p2=NULL;
165     else if (p3<=p1 && p4>=p1)
166         p3=p3, p4=p2>p4?p2:p4, p1=NULL, p2=NULL;
167
168     if (p1)
169         HMAC_Update(&c,p1,(size_t)p2-(size_t)p1);
170
171     if (FIPS_signature>=p3 && FIPS_signature<p4)
172         {
173         /* "punch" hole */
174         HMAC_Update(&c,p3,(size_t)FIPS_signature-(size_t)p3);
175         p3 = FIPS_signature+sizeof(FIPS_signature);
176         if (p3<p4)
177             HMAC_Update(&c,p3,(size_t)p4-(size_t)p3);
178         }
179     else
180         HMAC_Update(&c,p3,(size_t)p4-(size_t)p3);
181
182     if (!fips_post_corrupt(FIPS_TEST_INTEGRITY, 0, NULL))
183         HMAC_Update(&c, (unsigned char *)FIPS_hmac_key, 1);
184
185     HMAC_Final(&c,sig,&len);
186     HMAC_CTX_cleanup(&c);
187
188     return len;
189     }
190
191 int FIPS_check_incore_fingerprint(void)
192     {
193     unsigned char sig[EVP_MAX_MD_SIZE];
194     unsigned int len;
195     int rv = 0;
196 #if defined(__sgi) && (defined(__mips) || defined(mips))
197     extern int __dso_displacement[];
198 #else
199     extern int OPENSSL_NONPIC_relocated;
200 #endif
201
202     if (!fips_post_started(FIPS_TEST_INTEGRITY, 0, NULL))
203         return 1;
204
205     if (FIPS_text_start()==NULL)
206         {
207         FIPSerr(FIPS_F_FIPS_CHECK_INCORE_FINGERPRINT,FIPS_R_UNSUPPORTED_PLATFORM);
208         goto err;
209         }
210
211     len=FIPS_incore_fingerprint(sig,sizeof(sig));
212
213     if (len!=sizeof(FIPS_signature) ||
214         memcmp(FIPS_signature,sig,sizeof(FIPS_signature)))
215         {
216         if (FIPS_signature>=FIPS_rodata_start && FIPS_signature<FIPS_rodata_end)
217             FIPSerr(FIPS_F_FIPS_CHECK_INCORE_FINGERPRINT,FIPS_R_FINGERPRINT_DOES_NOT_MATCH_SEGMENT_ALIASING);
218 #if defined(__sgi) && (defined(__mips) || defined(mips))
219         else if (__dso_displacement!=NULL)
220 #else
221         else if (OPENSSL_NONPIC_relocated)
222 #endif
223             FIPSerr(FIPS_F_FIPS_CHECK_INCORE_FINGERPRINT,FIPS_R_FINGERPRINT_DOES_NOT_MATCH_NONPIC_RELOCATED);
224         else
225             FIPSerr(FIPS_F_FIPS_CHECK_INCORE_FINGERPRINT,FIPS_R_FINGERPRINT_DOES_NOT_MATCH);
226 #ifdef OPENSSL_FIPS_DEBUGGER
227         rv = 1;
228 #endif
229         goto err;
230         }
231     rv = 1;
232     err:
233     if (rv == 0)
234         fips_post_failed(FIPS_TEST_INTEGRITY, 0, NULL);
235     else
236         if (!fips_post_success(FIPS_TEST_INTEGRITY, 0, NULL))
237                 return 0;
238     return rv;
239     }
240
241 int FIPS_module_mode_set(int onoff)
242     {
243     int ret = 0;
244
245     fips_w_lock();
246     fips_started = 1;
247     fips_set_owning_thread();
248
249     if(onoff)
250         {
251
252         fips_selftest_fail = 0;
253
254         /* Don't go into FIPS mode twice, just so we can do automagic
255            seeding */
256         if(FIPS_module_mode())
257             {
258             FIPSerr(FIPS_F_FIPS_MODULE_MODE_SET,FIPS_R_FIPS_MODE_ALREADY_SET);
259             fips_selftest_fail = 1;
260             ret = 0;
261             goto end;
262             }
263
264 #ifdef OPENSSL_IA32_SSE2
265         if ((OPENSSL_ia32cap & (1<<25|1<<26)) != (1<<25|1<<26))
266             {
267             FIPSerr(FIPS_F_FIPS_MODULE_MODE_SET,FIPS_R_UNSUPPORTED_PLATFORM);
268             fips_selftest_fail = 1;
269             ret = 0;
270             goto end;
271             }
272 #endif
273
274         if(fips_signature_witness() != FIPS_signature)
275             {
276             FIPSerr(FIPS_F_FIPS_MODULE_MODE_SET,FIPS_R_CONTRADICTING_EVIDENCE);
277             fips_selftest_fail = 1;
278             ret = 0;
279             goto end;
280             }
281
282         if(FIPS_selftest())
283             fips_set_mode(onoff);
284         else
285             {
286             fips_selftest_fail = 1;
287             ret = 0;
288             goto end;
289             }
290         ret = 1;
291         goto end;
292         }
293     fips_set_mode(0);
294     fips_selftest_fail = 0;
295     ret = 1;
296 end:
297     fips_clear_owning_thread();
298     fips_w_unlock();
299     return ret;
300     }
301
302 static CRYPTO_THREADID fips_thread;
303 static int fips_thread_set = 0;
304
305 static int fips_is_owning_thread(void)
306         {
307         int ret = 0;
308
309         if (fips_started)
310                 {
311                 CRYPTO_r_lock(CRYPTO_LOCK_FIPS2);
312                 if (fips_thread_set)
313                         {
314                         CRYPTO_THREADID cur;
315                         CRYPTO_THREADID_current(&cur);
316                         if (!CRYPTO_THREADID_cmp(&cur, &fips_thread))
317                                 ret = 1;
318                         }
319                 CRYPTO_r_unlock(CRYPTO_LOCK_FIPS2);
320                 }
321         return ret;
322         }
323
324 int fips_set_owning_thread(void)
325         {
326         int ret = 0;
327
328         if (fips_started)
329                 {
330                 CRYPTO_w_lock(CRYPTO_LOCK_FIPS2);
331                 if (!fips_thread_set)
332                         {
333                         CRYPTO_THREADID_current(&fips_thread);
334                         ret = 1;
335                         fips_thread_set = 1;
336                         }
337                 CRYPTO_w_unlock(CRYPTO_LOCK_FIPS2);
338                 }
339         return ret;
340         }
341
342 int fips_clear_owning_thread(void)
343         {
344         int ret = 0;
345
346         if (fips_started)
347                 {
348                 CRYPTO_w_lock(CRYPTO_LOCK_FIPS2);
349                 if (fips_thread_set)
350                         {
351                         CRYPTO_THREADID cur;
352                         CRYPTO_THREADID_current(&cur);
353                         if (!CRYPTO_THREADID_cmp(&cur, &fips_thread))
354                                 fips_thread_set = 0;
355                         }
356                 CRYPTO_w_unlock(CRYPTO_LOCK_FIPS2);
357                 }
358         return ret;
359         }
360
361 unsigned char *fips_signature_witness(void)
362         {
363         extern unsigned char FIPS_signature[];
364         return FIPS_signature;
365         }
366
367 unsigned long FIPS_module_version(void)
368         {
369         return FIPS_MODULE_VERSION_NUMBER;
370         }
371
372 const char *FIPS_module_version_text(void)
373         {
374         return FIPS_MODULE_VERSION_TEXT;
375         }
376
377 #if 0
378 /* The purpose of this is to ensure the error code exists and the function
379  * name is to keep the error checking script quiet
380  */
381 void hash_final(void)
382         {
383         FIPSerr(FIPS_F_HASH_FINAL,FIPS_R_NON_FIPS_METHOD);
384         }
385 #endif
386
387
388 #endif