]>
Commit | Line | Data |
---|---|---|
2b4b28dc | 1 | /* ==================================================================== |
63c82f8a | 2 | * Copyright (c) 2011 The OpenSSL Project. All rights reserved. |
2b4b28dc DSH |
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 | ||
7c8ced94 | 50 | #define OPENSSL_FIPSAPI |
2b4b28dc | 51 | |
017bc57b | 52 | #include <openssl/crypto.h> |
2b4b28dc DSH |
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> | |
0fbf8f44 | 60 | #include <openssl/ecdsa.h> |
2b4b28dc DSH |
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 | ||
63c82f8a DSH |
73 | static int fips_selftest_fail = 0; |
74 | static int fips_mode = 0; | |
7e951160 | 75 | static int fips_started = 0; |
2b4b28dc | 76 | |
7e951160 DSH |
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 | ||
8776ef63 DSH |
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) | |
7e951160 | 86 | |
2b4b28dc DSH |
87 | static void fips_set_mode(int onoff) |
88 | { | |
89 | int owning_thread = fips_is_owning_thread(); | |
90 | ||
7e951160 | 91 | if (fips_started) |
2b4b28dc DSH |
92 | { |
93 | if (!owning_thread) fips_w_lock(); | |
94 | fips_mode = onoff; | |
95 | if (!owning_thread) fips_w_unlock(); | |
96 | } | |
97 | } | |
98 | ||
c2fd5989 | 99 | int FIPS_module_mode(void) |
2b4b28dc DSH |
100 | { |
101 | int ret = 0; | |
102 | int owning_thread = fips_is_owning_thread(); | |
103 | ||
7e951160 | 104 | if (fips_started) |
2b4b28dc DSH |
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 | ||
2b4b28dc DSH |
113 | int FIPS_selftest_failed(void) |
114 | { | |
115 | int ret = 0; | |
7e951160 | 116 | if (fips_started) |
2b4b28dc DSH |
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 | ||
2b4b28dc DSH |
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 }; | |
03e389cf | 148 | __fips_constseg |
2b4b28dc DSH |
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 | ||
ac892b7a DSH |
182 | if (!fips_post_corrupt(FIPS_TEST_INTEGRITY, 0, NULL)) |
183 | HMAC_Update(&c, (unsigned char *)FIPS_hmac_key, 1); | |
184 | ||
2b4b28dc DSH |
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; | |
ac892b7a | 195 | int rv = 0; |
2b4b28dc DSH |
196 | #if defined(__sgi) && (defined(__mips) || defined(mips)) |
197 | extern int __dso_displacement[]; | |
198 | #else | |
199 | extern int OPENSSL_NONPIC_relocated; | |
200 | #endif | |
201 | ||
ac892b7a DSH |
202 | if (!fips_post_started(FIPS_TEST_INTEGRITY, 0, NULL)) |
203 | return 1; | |
204 | ||
2b4b28dc DSH |
205 | if (FIPS_text_start()==NULL) |
206 | { | |
207 | FIPSerr(FIPS_F_FIPS_CHECK_INCORE_FINGERPRINT,FIPS_R_UNSUPPORTED_PLATFORM); | |
ac892b7a | 208 | goto err; |
2b4b28dc DSH |
209 | } |
210 | ||
ac892b7a | 211 | len=FIPS_incore_fingerprint(sig,sizeof(sig)); |
2b4b28dc DSH |
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 | |
ac892b7a | 227 | rv = 1; |
2b4b28dc | 228 | #endif |
ac892b7a | 229 | goto err; |
2b4b28dc | 230 | } |
ac892b7a DSH |
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; | |
2b4b28dc DSH |
239 | } |
240 | ||
c2fd5989 | 241 | int FIPS_module_mode_set(int onoff) |
2b4b28dc | 242 | { |
2b4b28dc DSH |
243 | int ret = 0; |
244 | ||
245 | fips_w_lock(); | |
7e951160 | 246 | fips_started = 1; |
2b4b28dc DSH |
247 | fips_set_owning_thread(); |
248 | ||
249 | if(onoff) | |
250 | { | |
2b4b28dc DSH |
251 | |
252 | fips_selftest_fail = 0; | |
253 | ||
254 | /* Don't go into FIPS mode twice, just so we can do automagic | |
255 | seeding */ | |
c2fd5989 | 256 | if(FIPS_module_mode()) |
2b4b28dc | 257 | { |
f76b1baf | 258 | FIPSerr(FIPS_F_FIPS_MODULE_MODE_SET,FIPS_R_FIPS_MODE_ALREADY_SET); |
2b4b28dc DSH |
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 | { | |
f76b1baf | 267 | FIPSerr(FIPS_F_FIPS_MODULE_MODE_SET,FIPS_R_UNSUPPORTED_PLATFORM); |
2b4b28dc DSH |
268 | fips_selftest_fail = 1; |
269 | ret = 0; | |
270 | goto end; | |
271 | } | |
272 | #endif | |
273 | ||
274 | if(fips_signature_witness() != FIPS_signature) | |
275 | { | |
f76b1baf | 276 | FIPSerr(FIPS_F_FIPS_MODULE_MODE_SET,FIPS_R_CONTRADICTING_EVIDENCE); |
2b4b28dc DSH |
277 | fips_selftest_fail = 1; |
278 | ret = 0; | |
279 | goto end; | |
280 | } | |
281 | ||
2b4b28dc | 282 | if(FIPS_selftest()) |
2f38b389 | 283 | fips_set_mode(onoff); |
2b4b28dc DSH |
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 | ||
2b4b28dc DSH |
302 | static CRYPTO_THREADID fips_thread; |
303 | static int fips_thread_set = 0; | |
304 | ||
7e951160 | 305 | static int fips_is_owning_thread(void) |
2b4b28dc DSH |
306 | { |
307 | int ret = 0; | |
308 | ||
7e951160 | 309 | if (fips_started) |
2b4b28dc DSH |
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 | ||
7e951160 | 328 | if (fips_started) |
2b4b28dc DSH |
329 | { |
330 | CRYPTO_w_lock(CRYPTO_LOCK_FIPS2); | |
331 | if (!fips_thread_set) | |
332 | { | |
333 | CRYPTO_THREADID_current(&fips_thread); | |
334 | ret = 1; | |
8776ef63 | 335 | fips_thread_set = 1; |
2b4b28dc DSH |
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 | ||
7e951160 | 346 | if (fips_started) |
2b4b28dc DSH |
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 | ||
01a9a759 DSH |
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 | ||
2b4b28dc DSH |
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 |