Updated FIPS140 initialization and added a self test for it.
[gnutls:gnutls.git] / lib / fips.c
1 /*
2  * Copyright (C) 2013 Red Hat
3  *
4  * Author: Nikos Mavrogiannopoulos
5  *
6  * This file is part of GnuTLS.
7  *
8  * The GnuTLS is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>
20  *
21  */
22
23 #include <gnutls_int.h>
24 #include <gnutls/gnutls.h>
25 #include <gnutls/crypto.h>
26 #include <unistd.h>
27 #include <gnutls_errors.h>
28 #include <fips.h>
29 #include <gnutls/fips140.h>
30 #include <dlfcn.h>
31
32 #define FIPS140_TEST
33
34 #ifdef ENABLE_FIPS140
35
36 unsigned int _gnutls_fips_mode = FIPS_STATE_POWERON;
37
38 unsigned _gnutls_fips_mode_enabled(void)
39 {
40         /* FIXME: There are some subtle differences here. Check it out later */
41         if (access("/proc/sys/crypto/fips_enabled", R_OK) == 0 &&
42             access("/etc/system-fips", R_OK) == 0)
43                 return 1;
44
45 #ifndef FIPS140_TEST
46         return 0;
47 #else
48         return 1;
49 #endif
50 }
51
52 static const char fips_key[] = "I'd rather be skiing.";
53
54 #define HMAC_SUFFIX ".hmac"
55 #define HMAC_SIZE 32
56 #define HMAC_ALGO GNUTLS_MAC_SHA256
57
58 /* Run an HMAC using the key above on the library binary data. 
59  * Returns true success and false on error.
60  */
61 static unsigned check_binary_integrity(void)
62 {
63         int ret;
64         Dl_info info;
65         unsigned prev;
66         char mac_file[GNUTLS_PATH_MAX];
67         uint8_t hmac[HMAC_SIZE];
68         uint8_t new_hmac[HMAC_SIZE];
69         size_t hmac_size;
70         gnutls_datum_t data;
71
72         ret = dladdr("gnutls_global_init", &info);
73         if (ret == 0)
74                 return gnutls_assert_val(0);
75
76         _gnutls_debug_log("Loading: %s\n", info.dli_fname);
77         ret = gnutls_load_file(info.dli_fname, &data);
78         if (ret < 0)
79                 return gnutls_assert_val(0);
80
81         prev = _gnutls_get_fips_state();
82         _gnutls_switch_fips_state(FIPS_STATE_OPERATIONAL);
83         ret = gnutls_hmac_fast(HMAC_ALGO, fips_key, sizeof(fips_key)-1,
84                 data.data, data.size, new_hmac);
85         _gnutls_switch_fips_state(prev);
86         
87         gnutls_free(data.data);
88
89         if (ret < 0)
90                 return gnutls_assert_val(0);
91
92         /* now open the .hmac file and compare */
93         snprintf(mac_file, sizeof(mac_file), "%s"HMAC_SUFFIX, info.dli_fname);
94         
95         ret = gnutls_load_file(mac_file, &data);
96         if (ret < 0)
97                 return gnutls_assert_val(0);
98
99         hmac_size = sizeof(hmac);
100         ret = _gnutls_hex2bin((void*)data.data, data.size, hmac, &hmac_size);
101         gnutls_free(data.data);
102
103         if (ret < 0)
104                 return gnutls_assert_val(0);
105
106         if (hmac_size != sizeof(hmac) ||
107                         memcmp(hmac, new_hmac, sizeof(hmac)) != 0) {
108                 _gnutls_debug_log("Calculated MAC does not match\n");
109                 return gnutls_assert_val(0);
110         }
111         
112         return 1;
113 }
114
115 int _gnutls_fips_perform_self_checks(void)
116 {
117         int ret;
118
119         _gnutls_switch_fips_state(FIPS_STATE_SELFTEST);
120
121         /* Tests the FIPS algorithms */
122
123         /* ciphers */
124         ret = gnutls_cipher_self_test(0, GNUTLS_CIPHER_AES_128_CBC);
125         if (ret < 0) {
126                 gnutls_assert();
127                 goto error;
128         }
129
130         ret = gnutls_cipher_self_test(0, GNUTLS_CIPHER_AES_192_CBC);
131         if (ret < 0) {
132                 gnutls_assert();
133                 goto error;
134         }
135
136         ret = gnutls_cipher_self_test(0, GNUTLS_CIPHER_AES_256_CBC);
137         if (ret < 0) {
138                 gnutls_assert();
139                 goto error;
140         }
141
142         ret = gnutls_cipher_self_test(0, GNUTLS_CIPHER_3DES_CBC);
143         if (ret < 0) {
144                 gnutls_assert();
145                 goto error;
146         }
147
148         ret = gnutls_cipher_self_test(0, GNUTLS_CIPHER_AES_128_GCM);
149         if (ret < 0) {
150                 gnutls_assert();
151                 goto error;
152         }
153
154         ret = gnutls_cipher_self_test(0, GNUTLS_CIPHER_AES_256_GCM);
155         if (ret < 0) {
156                 gnutls_assert();
157                 goto error;
158         }
159
160         /* MAC (includes message digest test) */
161         ret = gnutls_mac_self_test(0, GNUTLS_MAC_MD5);
162         if (ret < 0) {
163                 gnutls_assert();
164                 goto error;
165         }
166
167         ret = gnutls_mac_self_test(0, GNUTLS_MAC_SHA1);
168         if (ret < 0) {
169                 gnutls_assert();
170                 goto error;
171         }
172
173         ret = gnutls_mac_self_test(0, GNUTLS_MAC_SHA224);
174         if (ret < 0) {
175                 gnutls_assert();
176                 goto error;
177         }
178
179         ret = gnutls_mac_self_test(0, GNUTLS_MAC_SHA256);
180         if (ret < 0) {
181                 gnutls_assert();
182                 goto error;
183         }
184
185         ret = gnutls_mac_self_test(0, GNUTLS_MAC_SHA384);
186         if (ret < 0) {
187                 gnutls_assert();
188                 goto error;
189         }
190
191         ret = gnutls_mac_self_test(0, GNUTLS_MAC_SHA512);
192         if (ret < 0) {
193                 gnutls_assert();
194                 goto error;
195         }
196
197         /* PK */
198         ret = gnutls_pk_self_test(0, GNUTLS_PK_RSA);
199         if (ret < 0) {
200                 gnutls_assert();
201                 goto error;
202         }
203
204         ret = gnutls_pk_self_test(0, GNUTLS_PK_DSA);
205         if (ret < 0) {
206                 gnutls_assert();
207                 goto error;
208         }
209
210         ret = gnutls_pk_self_test(0, GNUTLS_PK_EC);
211         if (ret < 0) {
212                 gnutls_assert();
213                 goto error;
214         }
215         
216         ret = check_binary_integrity();
217         if (ret == 0) {
218                 gnutls_assert();
219 #ifndef FIPS140_TEST
220                 goto error;
221 #endif
222         }
223
224         return 0;
225 error:
226         _gnutls_switch_fips_state(FIPS_STATE_ERROR);
227
228         return GNUTLS_E_SELF_TEST_ERROR;
229 }
230 #endif
231
232 /**
233  * gnutls_fips140_mode_enabled:
234  *
235  * Checks whether this library is in FIPS140 mode.
236  *
237  * Returns: return non-zero if true or zero if false.
238  *
239  * Since: 3.3.0
240  **/
241 int gnutls_fips140_mode_enabled(void)
242 {
243 #ifdef ENABLE_FIPS140
244
245         return _gnutls_fips_mode_enabled();
246 #else
247         return 0;
248 #endif
249 }
250
251 void _gnutls_fips140_simulate_error(void)
252 {
253 #ifdef ENABLE_FIPS140
254         _gnutls_switch_fips_state(FIPS_STATE_ERROR);
255 #endif
256 }