]> git.ipfire.org Git - thirdparty/openssl.git/blob - apps/fipsinstall.c
739df23d448aa8651d45fd4b4cdea165fb01ee78
[thirdparty/openssl.git] / apps / fipsinstall.c
1 /*
2 * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10 #include <string.h>
11 #include <openssl/evp.h>
12 #include <openssl/err.h>
13 #include <openssl/provider.h>
14 #include <openssl/params.h>
15 #include <openssl/fips_names.h>
16 #include "apps.h"
17 #include "progs.h"
18
19 #define BUFSIZE 4096
20 #define DEFAULT_MAC_NAME "HMAC"
21 #define DEFAULT_FIPS_SECTION "fips_check_section"
22
23 /* Configuration file values */
24 #define VERSION_KEY "version"
25 #define VERSION_VAL "1"
26 #define INSTALL_STATUS_VAL "INSTALL_SELF_TEST_KATS_RUN"
27
28 typedef enum OPTION_choice {
29 OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
30 OPT_IN, OPT_OUT, OPT_MODULE,
31 OPT_PROV_NAME, OPT_SECTION_NAME, OPT_MAC_NAME, OPT_MACOPT, OPT_VERIFY
32 } OPTION_CHOICE;
33
34 const OPTIONS fipsinstall_options[] = {
35 OPT_SECTION("General"),
36 {"help", OPT_HELP, '-', "Display this summary"},
37 {"verify", OPT_VERIFY, '-',
38 "Verify a config file instead of generating one"},
39 {"module", OPT_MODULE, '<', "File name of the provider module"},
40 {"provider_name", OPT_PROV_NAME, 's', "FIPS provider name"},
41 {"section_name", OPT_SECTION_NAME, 's',
42 "FIPS Provider config section name (optional)"},
43
44 OPT_SECTION("Input"),
45 {"in", OPT_IN, '<', "Input config file, used when verifying"},
46
47 OPT_SECTION("Output"),
48 {"out", OPT_OUT, '>', "Output config file, used when generating"},
49 {"mac_name", OPT_MAC_NAME, 's', "MAC name"},
50 {"macopt", OPT_MACOPT, 's', "MAC algorithm parameters in n:v form. "
51 "See 'PARAMETER NAMES' in the EVP_MAC_ docs"},
52 {NULL}
53 };
54
55 static int do_mac(EVP_MAC_CTX *ctx, unsigned char *tmp, BIO *in,
56 unsigned char *out, size_t *out_len)
57 {
58 int ret = 0;
59 int i;
60 size_t outsz = *out_len;
61
62 if (!EVP_MAC_init(ctx))
63 goto err;
64 if (EVP_MAC_size(ctx) > outsz)
65 goto end;
66 while ((i = BIO_read(in, (char *)tmp, BUFSIZE)) != 0) {
67 if (i < 0 || !EVP_MAC_update(ctx, tmp, i))
68 goto err;
69 }
70 end:
71 if (!EVP_MAC_final(ctx, out, out_len, outsz))
72 goto err;
73 ret = 1;
74 err:
75 return ret;
76 }
77
78 static int load_fips_prov_and_run_self_test(const char *prov_name)
79 {
80 int ret = 0;
81 OSSL_PROVIDER *prov = NULL;
82
83 prov = OSSL_PROVIDER_load(NULL, prov_name);
84 if (prov == NULL) {
85 BIO_printf(bio_err, "Failed to load FIPS module\n");
86 goto end;
87 }
88 ret = 1;
89 end:
90 OSSL_PROVIDER_unload(prov);
91 return ret;
92 }
93
94 static int print_mac(BIO *bio, const char *label, const unsigned char *mac,
95 size_t len)
96 {
97 int ret;
98 char *hexstr = NULL;
99
100 hexstr = OPENSSL_buf2hexstr(mac, (long)len);
101 if (hexstr == NULL)
102 return 0;
103 ret = BIO_printf(bio, "%s = %s\n", label, hexstr);
104 OPENSSL_free(hexstr);
105 return ret;
106 }
107
108 static int write_config_header(BIO *out, const char *prov_name,
109 const char *section)
110 {
111 return BIO_printf(out, "openssl_conf = openssl_init\n\n")
112 && BIO_printf(out, "[openssl_init]\n")
113 && BIO_printf(out, "providers = provider_section\n\n")
114 && BIO_printf(out, "[provider_section]\n")
115 && BIO_printf(out, "%s = %s\n\n", prov_name, section);
116 }
117
118 /*
119 * Outputs a fips related config file that contains entries for the fips
120 * module checksum and the installation indicator checksum.
121 *
122 * Returns 1 if the config file is written otherwise it returns 0 on error.
123 */
124 static int write_config_fips_section(BIO *out, const char *section,
125 unsigned char *module_mac,
126 size_t module_mac_len,
127 unsigned char *install_mac,
128 size_t install_mac_len)
129 {
130 int ret = 0;
131
132 if (!(BIO_printf(out, "[%s]\n", section) > 0
133 && BIO_printf(out, "activate = 1\n") > 0
134 && BIO_printf(out, "%s = %s\n", OSSL_PROV_FIPS_PARAM_INSTALL_VERSION,
135 VERSION_VAL) > 0
136 && print_mac(out, OSSL_PROV_FIPS_PARAM_MODULE_MAC, module_mac,
137 module_mac_len)))
138 goto end;
139
140 if (install_mac != NULL) {
141 if (!(print_mac(out, OSSL_PROV_FIPS_PARAM_INSTALL_MAC, install_mac,
142 install_mac_len)
143 && BIO_printf(out, "%s = %s\n",
144 OSSL_PROV_FIPS_PARAM_INSTALL_STATUS,
145 INSTALL_STATUS_VAL) > 0))
146 goto end;
147 }
148 ret = 1;
149 end:
150 return ret;
151 }
152
153 static CONF *generate_config_and_load(const char *prov_name,
154 const char *section,
155 unsigned char *module_mac,
156 size_t module_mac_len)
157 {
158 BIO *mem_bio = NULL;
159 CONF *conf = NULL;
160
161 mem_bio = BIO_new(BIO_s_mem());
162 if (mem_bio == NULL)
163 return 0;
164 if (!write_config_header(mem_bio, prov_name, section)
165 || !write_config_fips_section(mem_bio, section, module_mac,
166 module_mac_len, NULL, 0))
167 goto end;
168
169 conf = app_load_config_bio(mem_bio, NULL);
170 if (conf == NULL)
171 goto end;
172
173 if (CONF_modules_load(conf, NULL, 0) <= 0)
174 goto end;
175 BIO_free(mem_bio);
176 return conf;
177 end:
178 NCONF_free(conf);
179 BIO_free(mem_bio);
180 return NULL;
181 }
182
183 static void free_config_and_unload(CONF *conf)
184 {
185 if (conf != NULL) {
186 NCONF_free(conf);
187 CONF_modules_unload(1);
188 }
189 }
190
191 /*
192 * Returns 1 if the config file entries match the passed in module_mac and
193 * install_mac values, otherwise it returns 0.
194 */
195 static int verify_config(const char *infile, const char *section,
196 unsigned char *module_mac, size_t module_mac_len,
197 unsigned char *install_mac, size_t install_mac_len)
198 {
199 int ret = 0;
200 char *s = NULL;
201 unsigned char *buf1 = NULL, *buf2 = NULL;
202 long len;
203 CONF *conf = NULL;
204
205 /* read in the existing values and check they match the saved values */
206 conf = app_load_config(infile);
207 if (conf == NULL)
208 goto end;
209
210 s = NCONF_get_string(conf, section, OSSL_PROV_FIPS_PARAM_INSTALL_VERSION);
211 if (s == NULL || strcmp(s, VERSION_VAL) != 0) {
212 BIO_printf(bio_err, "version not found\n");
213 goto end;
214 }
215 s = NCONF_get_string(conf, section, OSSL_PROV_FIPS_PARAM_INSTALL_STATUS);
216 if (s == NULL || strcmp(s, INSTALL_STATUS_VAL) != 0) {
217 BIO_printf(bio_err, "install status not found\n");
218 goto end;
219 }
220 s = NCONF_get_string(conf, section, OSSL_PROV_FIPS_PARAM_MODULE_MAC);
221 if (s == NULL) {
222 BIO_printf(bio_err, "Module integrity MAC not found\n");
223 goto end;
224 }
225 buf1 = OPENSSL_hexstr2buf(s, &len);
226 if (buf1 == NULL
227 || (size_t)len != module_mac_len
228 || memcmp(module_mac, buf1, module_mac_len) != 0) {
229 BIO_printf(bio_err, "Module integrity mismatch\n");
230 goto end;
231 }
232 s = NCONF_get_string(conf, section, OSSL_PROV_FIPS_PARAM_INSTALL_MAC);
233 if (s == NULL) {
234 BIO_printf(bio_err, "Install indicator MAC not found\n");
235 goto end;
236 }
237 buf2 = OPENSSL_hexstr2buf(s, &len);
238 if (buf2 == NULL
239 || (size_t)len != install_mac_len
240 || memcmp(install_mac, buf2, install_mac_len) != 0) {
241 BIO_printf(bio_err, "Install indicator status mismatch\n");
242 goto end;
243 }
244 ret = 1;
245 end:
246 OPENSSL_free(buf1);
247 OPENSSL_free(buf2);
248 NCONF_free(conf);
249 return ret;
250 }
251
252 int fipsinstall_main(int argc, char **argv)
253 {
254 int ret = 1, verify = 0;
255 BIO *module_bio = NULL, *mem_bio = NULL, *fout = NULL;
256 char *in_fname = NULL, *out_fname = NULL, *prog, *section_name = NULL;
257 char *prov_name = NULL, *module_fname = NULL;
258 static const char *mac_name = DEFAULT_MAC_NAME;
259 EVP_MAC_CTX *ctx = NULL, *ctx2 = NULL;
260 STACK_OF(OPENSSL_STRING) *opts = NULL;
261 OPTION_CHOICE o;
262 unsigned char *read_buffer = NULL;
263 unsigned char module_mac[EVP_MAX_MD_SIZE];
264 size_t module_mac_len = EVP_MAX_MD_SIZE;
265 unsigned char install_mac[EVP_MAX_MD_SIZE];
266 size_t install_mac_len = EVP_MAX_MD_SIZE;
267 EVP_MAC *mac = NULL;
268 CONF *conf = NULL;
269
270 section_name = DEFAULT_FIPS_SECTION;
271
272 prog = opt_init(argc, argv, fipsinstall_options);
273 while ((o = opt_next()) != OPT_EOF) {
274 switch (o) {
275 case OPT_EOF:
276 case OPT_ERR:
277 opthelp:
278 BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
279 goto end;
280 case OPT_HELP:
281 opt_help(fipsinstall_options);
282 ret = 0;
283 goto end;
284 case OPT_IN:
285 in_fname = opt_arg();
286 break;
287 case OPT_OUT:
288 out_fname = opt_arg();
289 break;
290 case OPT_PROV_NAME:
291 prov_name = opt_arg();
292 break;
293 case OPT_MODULE:
294 module_fname = opt_arg();
295 break;
296 case OPT_SECTION_NAME:
297 section_name = opt_arg();
298 break;
299 case OPT_MAC_NAME:
300 mac_name = opt_arg();
301 break;
302 case OPT_MACOPT:
303 if (opts == NULL)
304 opts = sk_OPENSSL_STRING_new_null();
305 if (opts == NULL || !sk_OPENSSL_STRING_push(opts, opt_arg()))
306 goto opthelp;
307 break;
308 case OPT_VERIFY:
309 verify = 1;
310 break;
311 }
312 }
313 argc = opt_num_rest();
314 if (module_fname == NULL
315 || (verify && in_fname == NULL)
316 || (!verify && (out_fname == NULL || prov_name == NULL))
317 || opts == NULL
318 || argc != 0)
319 goto opthelp;
320
321 module_bio = bio_open_default(module_fname, 'r', FORMAT_BINARY);
322 if (module_bio == NULL) {
323 BIO_printf(bio_err, "Failed to open module file\n");
324 goto end;
325 }
326
327 read_buffer = app_malloc(BUFSIZE, "I/O buffer");
328 if (read_buffer == NULL)
329 goto end;
330
331 mac = EVP_MAC_fetch(NULL, mac_name, NULL);
332 if (mac == NULL) {
333 BIO_printf(bio_err, "Unable to get MAC of type %s\n", mac_name);
334 goto end;
335 }
336
337 ctx = EVP_MAC_CTX_new(mac);
338 if (ctx == NULL) {
339 BIO_printf(bio_err, "Unable to create MAC CTX for module check\n");
340 goto end;
341 }
342
343 if (opts != NULL) {
344 int ok = 1;
345 OSSL_PARAM *params =
346 app_params_new_from_opts(opts, EVP_MAC_settable_ctx_params(mac));
347
348 if (params == NULL)
349 goto end;
350
351 if (!EVP_MAC_CTX_set_params(ctx, params)) {
352 BIO_printf(bio_err, "MAC parameter error\n");
353 ERR_print_errors(bio_err);
354 ok = 0;
355 }
356 app_params_free(params);
357 if (!ok)
358 goto end;
359 }
360
361 ctx2 = EVP_MAC_CTX_dup(ctx);
362 if (ctx2 == NULL) {
363 BIO_printf(bio_err, "Unable to create MAC CTX for install indicator\n");
364 goto end;
365 }
366
367 if (!do_mac(ctx, read_buffer, module_bio, module_mac, &module_mac_len))
368 goto end;
369
370 mem_bio = BIO_new_mem_buf((const void *)INSTALL_STATUS_VAL,
371 strlen(INSTALL_STATUS_VAL));
372 if (mem_bio == NULL) {
373 BIO_printf(bio_err, "Unable to create memory BIO\n");
374 goto end;
375 }
376 if (!do_mac(ctx2, read_buffer, mem_bio, install_mac, &install_mac_len))
377 goto end;
378
379 if (verify) {
380 if (!verify_config(in_fname, section_name, module_mac, module_mac_len,
381 install_mac, install_mac_len))
382 goto end;
383 BIO_printf(bio_out, "VERIFY PASSED\n");
384 } else {
385
386 conf = generate_config_and_load(prov_name, section_name, module_mac,
387 module_mac_len);
388 if (conf == NULL)
389 goto end;
390 if (!load_fips_prov_and_run_self_test(prov_name))
391 goto end;
392
393 fout = bio_open_default(out_fname, 'w', FORMAT_TEXT);
394 if (fout == NULL) {
395 BIO_printf(bio_err, "Failed to open file\n");
396 goto end;
397 }
398 if (!write_config_fips_section(fout, section_name, module_mac,
399 module_mac_len, install_mac,
400 install_mac_len))
401 goto end;
402 BIO_printf(bio_out, "INSTALL PASSED\n");
403 }
404
405 ret = 0;
406 end:
407 if (ret == 1) {
408 BIO_printf(bio_err, "%s FAILED\n", verify ? "VERIFY" : "INSTALL");
409 ERR_print_errors(bio_err);
410 }
411
412 BIO_free(fout);
413 BIO_free(mem_bio);
414 BIO_free(module_bio);
415 sk_OPENSSL_STRING_free(opts);
416 EVP_MAC_free(mac);
417 EVP_MAC_CTX_free(ctx2);
418 EVP_MAC_CTX_free(ctx);
419 OPENSSL_free(read_buffer);
420 free_config_and_unload(conf);
421 return ret;
422 }