Added binary integrity test
[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
30 #ifdef ENABLE_FIPS140
31
32 unsigned int _gnutls_fips_mode = FIPS_STATE_POWERON;
33
34 unsigned _gnutls_fips_mode_enabled(void)
35 {
36         /* FIXME: There are some subtle differences here. Check it out later */
37         if (access("/proc/sys/crypto/fips_enabled", R_OK) == 0 &&
38             access("/etc/system-fips", R_OK) == 0)
39                 return 1;
40
41         return 0;
42 }
43
44 #ifdef HAVE_DLADDR
45 static const char fips_key[] = "I'd rather be skiing.";
46
47 #define HMAC_SUFFIX ".hmac"
48
49
50 /* Run an HMAC using the key above on the library binary data. 
51  * Returns true success and false on error.
52  */
53 static unsigned check_binary_integrity(void)
54 {
55         int ret;
56         Dl_info info;
57         unsigned prev;
58         char mac_file[GNUTLS_PATH_MAX];
59         uint8_t sha256_hmac[32];
60         uint8_t new_sha256_hmac[32];
61         size_t sha256_hmac_size;
62         gnutls_datum_t data;
63
64         ret = dladdr("gnutls_global_init", &info);
65         if (ret == 0)
66                 return gnutls_assert_val(0);
67
68         ret = gnutls_load_file(info.dli_fname, &data);
69         if (ret < 0)
70                 return gnutls_assert_val(0);
71
72         prev = _gnutls_get_fips_state();
73         _gnutls_switch_fips_state(FIPS_STATE_OPERATIONAL);
74         ret = gnutls_hmac_fast(GNUTLS_MAC_SHA256, fips_key, sizeof(fips_key)-1,
75                 data.data, data.size, new_sha256_hmac);
76         _gnutls_switch_fips_state(prev);
77         
78         gnutls_free(data.data);
79
80         if (ret < 0)
81                 return gnutls_assert_val(0);
82
83         /* now open the .hmac file and compare */
84         snprintf(mac_file, sizeof(mac_file), "%s"HMAC_SUFFIX, info.dli_fname);
85         
86         ret = gnutls_load_file(info.dli_fname, &data);
87         if (ret < 0)
88                 return gnutls_assert_val(0);
89
90         sha256_hmac_size = sizeof(sha256_hmac);
91         ret = _gnutls_hex2bin(data.data, data.size, sha256_hmac, &sha256_hmac_size);
92         gnutls_free(data.data);
93
94         if (ret < 0)
95                 return gnutls_assert_val(0);
96
97         if (sha256_hmac_size != sizeof(sha256_hmac) ||
98                         memcmp(sha256_hmac, new_sha256_hmac, sizeof(sha256_hmac)) != 0)
99                 return gnutls_assert_val(0);
100         
101         return 1;
102 }
103
104 #else
105 static int check_binary_integrity(void)
106 {
107         return 1;
108 }
109 #endif
110
111 int _gnutls_fips_perform_self_checks(void)
112 {
113         int ret;
114
115         _gnutls_switch_fips_state(FIPS_STATE_SELFTEST);
116
117         /* Tests the FIPS algorithms */
118
119         /* ciphers */
120         ret = gnutls_cipher_self_test(0, GNUTLS_CIPHER_AES_128_CBC);
121         if (ret < 0) {
122                 gnutls_assert();
123                 goto error;
124         }
125
126         ret = gnutls_cipher_self_test(0, GNUTLS_CIPHER_AES_192_CBC);
127         if (ret < 0) {
128                 gnutls_assert();
129                 goto error;
130         }
131
132         ret = gnutls_cipher_self_test(0, GNUTLS_CIPHER_AES_256_CBC);
133         if (ret < 0) {
134                 gnutls_assert();
135                 goto error;
136         }
137
138         ret = gnutls_cipher_self_test(0, GNUTLS_CIPHER_3DES_CBC);
139         if (ret < 0) {
140                 gnutls_assert();
141                 goto error;
142         }
143
144         ret = gnutls_cipher_self_test(0, GNUTLS_CIPHER_AES_128_GCM);
145         if (ret < 0) {
146                 gnutls_assert();
147                 goto error;
148         }
149
150         ret = gnutls_cipher_self_test(0, GNUTLS_CIPHER_AES_256_GCM);
151         if (ret < 0) {
152                 gnutls_assert();
153                 goto error;
154         }
155
156         /* MAC (includes message digest test) */
157         ret = gnutls_mac_self_test(0, GNUTLS_MAC_MD5);
158         if (ret < 0) {
159                 gnutls_assert();
160                 goto error;
161         }
162
163         ret = gnutls_mac_self_test(0, GNUTLS_MAC_SHA1);
164         if (ret < 0) {
165                 gnutls_assert();
166                 goto error;
167         }
168
169         ret = gnutls_mac_self_test(0, GNUTLS_MAC_SHA224);
170         if (ret < 0) {
171                 gnutls_assert();
172                 goto error;
173         }
174
175         ret = gnutls_mac_self_test(0, GNUTLS_MAC_SHA256);
176         if (ret < 0) {
177                 gnutls_assert();
178                 goto error;
179         }
180
181         ret = gnutls_mac_self_test(0, GNUTLS_MAC_SHA384);
182         if (ret < 0) {
183                 gnutls_assert();
184                 goto error;
185         }
186
187         ret = gnutls_mac_self_test(0, GNUTLS_MAC_SHA512);
188         if (ret < 0) {
189                 gnutls_assert();
190                 goto error;
191         }
192
193         /* PK */
194         ret = gnutls_pk_self_test(0, GNUTLS_PK_RSA);
195         if (ret < 0) {
196                 gnutls_assert();
197                 goto error;
198         }
199
200         ret = gnutls_pk_self_test(0, GNUTLS_PK_DSA);
201         if (ret < 0) {
202                 gnutls_assert();
203                 goto error;
204         }
205
206         ret = gnutls_pk_self_test(0, GNUTLS_PK_EC);
207         if (ret < 0) {
208                 gnutls_assert();
209                 goto error;
210         }
211         
212         ret = check_binary_integrity();
213         if (ret < 0) {
214                 gnutls_assert();
215                 goto error;
216         }
217
218         return 0;
219 error:
220         _gnutls_switch_fips_state(FIPS_STATE_ERROR);
221
222         return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
223 }
224
225 #endif