e879e0c3db993e28d81d0face8c11549242432af
[oweals/openssl.git] / fips / 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_md5_allowed = 0;
67 static int fips_selftest_fail = 0;
68 static int fips_mode = 0;
69 static const void *fips_rand_check = 0;
70
71 static void fips_set_mode(int onoff)
72         {
73         int owning_thread = fips_is_owning_thread();
74
75         if (fips_is_started())
76                 {
77                 if (!owning_thread) fips_w_lock();
78                 fips_mode = onoff;
79                 if (!owning_thread) fips_w_unlock();
80                 }
81         }
82
83 static void fips_set_rand_check(const void *rand_check)
84         {
85         int owning_thread = fips_is_owning_thread();
86
87         if (fips_is_started())
88                 {
89                 if (!owning_thread) fips_w_lock();
90                 fips_rand_check = rand_check;
91                 if (!owning_thread) fips_w_unlock();
92                 }
93         }
94
95 int FIPS_mode(void)
96         {
97         int ret = 0;
98         int owning_thread = fips_is_owning_thread();
99
100         if (fips_is_started())
101                 {
102                 if (!owning_thread) fips_r_lock();
103                 ret = fips_mode;
104                 if (!owning_thread) fips_r_unlock();
105                 }
106         return ret;
107         }
108
109 const void *FIPS_rand_check(void)
110         {
111         const void *ret = 0;
112         int owning_thread = fips_is_owning_thread();
113
114         if (fips_is_started())
115                 {
116                 if (!owning_thread) fips_r_lock();
117                 ret = fips_rand_check;
118                 if (!owning_thread) fips_r_unlock();
119                 }
120         return ret;
121         }
122
123 void FIPS_allow_md5(int onoff)
124     {
125     if (fips_is_started())
126         {
127         int owning_thread = fips_is_owning_thread();
128
129         if (!owning_thread) fips_w_lock();
130         fips_md5_allowed = onoff;
131         if (!owning_thread) fips_w_unlock();
132         }
133     }
134
135 int FIPS_md5_allowed(void)
136     {
137     int ret = 1;
138     if (fips_is_started())
139         {
140         int owning_thread = fips_is_owning_thread();
141
142         if (!owning_thread) fips_r_lock();
143         ret = fips_md5_allowed;
144         if (!owning_thread) fips_r_unlock();
145         }
146     return ret;
147     }
148
149 int FIPS_selftest_failed(void)
150     {
151     int ret = 0;
152     if (fips_is_started())
153         {
154         int owning_thread = fips_is_owning_thread();
155
156         if (!owning_thread) fips_r_lock();
157         ret = fips_selftest_fail;
158         if (!owning_thread) fips_r_unlock();
159         }
160     return ret;
161     }
162
163 int FIPS_selftest()
164     {
165     ERR_load_crypto_strings();
166
167     return FIPS_selftest_sha1()
168         && FIPS_selftest_aes()
169         && FIPS_selftest_des()
170         && FIPS_selftest_rsa()
171         && FIPS_selftest_dsa();
172     }
173
174 static int FIPS_check_exe(const char *path)
175     {
176     unsigned char buf[1024];
177     char p2[PATH_MAX];
178     unsigned int n;
179     unsigned char mdbuf[EVP_MAX_MD_SIZE];
180     FILE *f;
181     static char key[]="etaonrishdlcupfm";
182     HMAC_CTX hmac;
183     const char *sha1_fmt="%s.sha1";
184
185     f=fopen(path,"rb");
186 #ifdef __CYGWIN32__
187     /* cygwin scrupulously strips .exe extentions:-( as of now it's
188        actually no point to attempt above fopen, but we keep the call
189        just in case the behavior changes in the future... */
190     if (!f)
191         {
192         sha1_fmt="%s.exe.sha1";
193         BIO_snprintf(p2,sizeof p2,"%s.exe",path);
194         f=fopen(p2,"rb");
195         }
196 #endif
197     if(!f)
198         {
199         FIPSerr(FIPS_F_FIPS_CHECK_EXE,FIPS_R_CANNOT_READ_EXE);
200         return 0;
201         }
202     HMAC_Init(&hmac,key,strlen(key),EVP_sha1());
203     while(!feof(f))
204         {
205         n=fread(buf,1,sizeof buf,f);
206         if(ferror(f))
207             {
208             clearerr(f);
209             fclose(f);
210             FIPSerr(FIPS_F_FIPS_CHECK_EXE,FIPS_R_CANNOT_READ_EXE);
211             return 0;
212             }
213         if (n) HMAC_Update(&hmac,buf,n);
214         }
215     fclose(f);
216     HMAC_Final(&hmac,mdbuf,&n);
217     HMAC_CTX_cleanup(&hmac);
218     BIO_snprintf(p2,sizeof p2,sha1_fmt,path);
219     f=fopen(p2,"rb");
220     if(!f || fread(buf,1,20,f) != 20)
221         {
222         if (f) fclose(f);
223         FIPSerr(FIPS_F_FIPS_CHECK_EXE,FIPS_R_CANNOT_READ_EXE_DIGEST);
224         return 0;
225         }
226     fclose(f);
227     if(memcmp(buf,mdbuf,20))
228         {
229         FIPSerr(FIPS_F_FIPS_CHECK_EXE,FIPS_R_EXE_DIGEST_DOES_NOT_MATCH);
230         return 0;
231         }
232     return 1;
233     }
234
235 int FIPS_mode_set(int onoff,const char *path)
236     {
237     void fips_set_mode(int _onoff);
238     int fips_set_owning_thread();
239     int fips_clear_owning_thread();
240     int ret = 0;
241
242     fips_w_lock();
243     fips_set_started();
244     fips_set_owning_thread();
245
246     if(onoff)
247         {
248         unsigned char buf[24];
249
250         fips_selftest_fail = 0;
251
252         /* Don't go into FIPS mode twice, just so we can do automagic
253            seeding */
254         if(FIPS_mode())
255             {
256             FIPSerr(FIPS_F_FIPS_MODE_SET,FIPS_R_FIPS_MODE_ALREADY_SET);
257             fips_selftest_fail = 1;
258             ret = 0;
259             goto end;
260             }
261
262         if(!FIPS_check_exe(path))
263             {
264             fips_selftest_fail = 1;
265             ret = 0;
266             goto end;
267             }
268
269         /* automagically seed PRNG if not already seeded */
270         if(!FIPS_rand_seeded())
271             {
272             if(RAND_bytes(buf,sizeof buf) <= 0)
273                 {
274                 fips_selftest_fail = 1;
275                 ret = 0;
276                 goto end;
277                 }
278             FIPS_set_prng_key(buf,buf+8);
279             FIPS_rand_seed(buf+16,8);
280             }
281
282         /* now switch into FIPS mode */
283         fips_set_rand_check(FIPS_rand_method());
284         RAND_set_rand_method(FIPS_rand_method());
285         if(FIPS_selftest())
286             fips_set_mode(1);
287         else
288             {
289             fips_selftest_fail = 1;
290             ret = 0;
291             goto end;
292             }
293         ret = 1;
294         goto end;
295         }
296     fips_set_mode(0);
297     fips_selftest_fail = 0;
298     ret = 1;
299 end:
300     fips_clear_owning_thread();
301     fips_w_unlock();
302     return ret;
303     }
304
305 #if 0
306 /* here just to cause error codes to exist */
307 static void dummy()
308     {
309     FIPSerr(FIPS_F_HASH_FINAL,FIPS_F_NON_FIPS_METHOD);
310     FIPSerr(FIPS_F_HASH_FINAL,FIPS_R_FIPS_SELFTEST_FAILED);
311     }
312 #endif
313
314 #endif