Make rcu_thread_key context-aware
[openssl.git] / apps / fipsinstall.c
1 /*
2  * Copyright 2019-2020 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 <openssl/core_names.h>
17 #include <openssl/self_test.h>
18 #include <openssl/fipskey.h>
19 #include "apps.h"
20 #include "progs.h"
21
22 #define BUFSIZE 4096
23
24 /* Configuration file values */
25 #define VERSION_KEY  "version"
26 #define VERSION_VAL  "1"
27 #define INSTALL_STATUS_VAL "INSTALL_SELF_TEST_KATS_RUN"
28
29 static OSSL_CALLBACK self_test_events;
30 static char *self_test_corrupt_desc = NULL;
31 static char *self_test_corrupt_type = NULL;
32 static int self_test_log = 1;
33 static int quiet = 0;
34
35 typedef enum OPTION_choice {
36     OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
37     OPT_IN, OPT_OUT, OPT_MODULE,
38     OPT_PROV_NAME, OPT_SECTION_NAME, OPT_MAC_NAME, OPT_MACOPT, OPT_VERIFY,
39     OPT_NO_LOG, OPT_CORRUPT_DESC, OPT_CORRUPT_TYPE, OPT_QUIET, OPT_CONFIG,
40     OPT_NO_CONDITIONAL_ERRORS,
41     OPT_NO_SECURITY_CHECKS
42 } OPTION_CHOICE;
43
44 const OPTIONS fipsinstall_options[] = {
45     OPT_SECTION("General"),
46     {"help", OPT_HELP, '-', "Display this summary"},
47     {"verify", OPT_VERIFY, '-',
48         "Verify a config file instead of generating one"},
49     {"module", OPT_MODULE, '<', "File name of the provider module"},
50     {"provider_name", OPT_PROV_NAME, 's', "FIPS provider name"},
51     {"section_name", OPT_SECTION_NAME, 's',
52      "FIPS Provider config section name (optional)"},
53      {"no_conditional_errors", OPT_NO_CONDITIONAL_ERRORS, '-',
54       "Disable the ability of the fips module to enter an error state if"
55       " any conditional self tests fail"},
56     {"no_security_checks", OPT_NO_SECURITY_CHECKS, '-',
57      "Disable the run-time FIPS security checks in the module"},
58     OPT_SECTION("Input"),
59     {"in", OPT_IN, '<', "Input config file, used when verifying"},
60
61     OPT_SECTION("Output"),
62     {"out", OPT_OUT, '>', "Output config file, used when generating"},
63     {"mac_name", OPT_MAC_NAME, 's', "MAC name"},
64     {"macopt", OPT_MACOPT, 's', "MAC algorithm parameters in n:v form. "
65                                 "See 'PARAMETER NAMES' in the EVP_MAC_ docs"},
66     {"noout", OPT_NO_LOG, '-', "Disable logging of self test events"},
67     {"corrupt_desc", OPT_CORRUPT_DESC, 's', "Corrupt a self test by description"},
68     {"corrupt_type", OPT_CORRUPT_TYPE, 's', "Corrupt a self test by type"},
69     {"config", OPT_CONFIG, '<', "The parent config to verify"},
70     {"quiet", OPT_QUIET, '-', "No messages, just exit status"},
71     {NULL}
72 };
73
74 static int do_mac(EVP_MAC_CTX *ctx, unsigned char *tmp, BIO *in,
75                   unsigned char *out, size_t *out_len)
76 {
77     int ret = 0;
78     int i;
79     size_t outsz = *out_len;
80
81     if (!EVP_MAC_init(ctx))
82         goto err;
83     if (EVP_MAC_CTX_get_mac_size(ctx) > outsz)
84         goto end;
85     while ((i = BIO_read(in, (char *)tmp, BUFSIZE)) != 0) {
86         if (i < 0 || !EVP_MAC_update(ctx, tmp, i))
87             goto err;
88     }
89 end:
90     if (!EVP_MAC_final(ctx, out, out_len, outsz))
91         goto err;
92     ret = 1;
93 err:
94     return ret;
95 }
96
97 static int load_fips_prov_and_run_self_test(const char *prov_name)
98 {
99     int ret = 0;
100     OSSL_PROVIDER *prov = NULL;
101
102     prov = OSSL_PROVIDER_load(NULL, prov_name);
103     if (prov == NULL) {
104         BIO_printf(bio_err, "Failed to load FIPS module\n");
105         goto end;
106     }
107     ret = 1;
108 end:
109     OSSL_PROVIDER_unload(prov);
110     return ret;
111 }
112
113 static int print_mac(BIO *bio, const char *label, const unsigned char *mac,
114                      size_t len)
115 {
116     int ret;
117     char *hexstr = NULL;
118
119     hexstr = OPENSSL_buf2hexstr(mac, (long)len);
120     if (hexstr == NULL)
121         return 0;
122     ret = BIO_printf(bio, "%s = %s\n", label, hexstr);
123     OPENSSL_free(hexstr);
124     return ret;
125 }
126
127 static int write_config_header(BIO *out, const char *prov_name,
128                                const char *section)
129 {
130     return BIO_printf(out, "openssl_conf = openssl_init\n\n")
131            && BIO_printf(out, "[openssl_init]\n")
132            && BIO_printf(out, "providers = provider_section\n\n")
133            && BIO_printf(out, "[provider_section]\n")
134            && BIO_printf(out, "%s = %s\n\n", prov_name, section);
135 }
136
137 /*
138  * Outputs a fips related config file that contains entries for the fips
139  * module checksum, installation indicator checksum and the options
140  * conditional_errors and security_checks.
141  *
142  * Returns 1 if the config file is written otherwise it returns 0 on error.
143  */
144 static int write_config_fips_section(BIO *out, const char *section,
145                                      unsigned char *module_mac,
146                                      size_t module_mac_len,
147                                      int conditional_errors,
148                                      int security_checks,
149                                      unsigned char *install_mac,
150                                      size_t install_mac_len)
151 {
152     int ret = 0;
153
154     if (BIO_printf(out, "[%s]\n", section) <= 0
155         || BIO_printf(out, "activate = 1\n") <= 0
156         || BIO_printf(out, "%s = %s\n", OSSL_PROV_FIPS_PARAM_INSTALL_VERSION,
157                       VERSION_VAL) <= 0
158         || BIO_printf(out, "%s = %s\n", OSSL_PROV_FIPS_PARAM_CONDITIONAL_ERRORS,
159                       conditional_errors ? "1" : "0") <= 0
160         || BIO_printf(out, "%s = %s\n", OSSL_PROV_FIPS_PARAM_SECURITY_CHECKS,
161                       security_checks ? "1" : "0") <= 0
162         || !print_mac(out, OSSL_PROV_FIPS_PARAM_MODULE_MAC, module_mac,
163                       module_mac_len))
164         goto end;
165
166     if (install_mac != NULL) {
167         if (!print_mac(out, OSSL_PROV_FIPS_PARAM_INSTALL_MAC, install_mac,
168                        install_mac_len)
169             || BIO_printf(out, "%s = %s\n", OSSL_PROV_FIPS_PARAM_INSTALL_STATUS,
170                           INSTALL_STATUS_VAL) <= 0)
171         goto end;
172     }
173     ret = 1;
174 end:
175     return ret;
176 }
177
178 static CONF *generate_config_and_load(const char *prov_name,
179                                       const char *section,
180                                       unsigned char *module_mac,
181                                       size_t module_mac_len,
182                                       int conditional_errors,
183                                       int security_checks)
184 {
185     BIO *mem_bio = NULL;
186     CONF *conf = NULL;
187
188     mem_bio = BIO_new(BIO_s_mem());
189     if (mem_bio  == NULL)
190         return 0;
191     if (!write_config_header(mem_bio, prov_name, section)
192          || !write_config_fips_section(mem_bio, section,
193                                        module_mac, module_mac_len,
194                                        conditional_errors,
195                                        security_checks,
196                                        NULL, 0))
197         goto end;
198
199     conf = app_load_config_bio(mem_bio, NULL);
200     if (conf == NULL)
201         goto end;
202
203     if (CONF_modules_load(conf, NULL, 0) <= 0)
204         goto end;
205     BIO_free(mem_bio);
206     return conf;
207 end:
208     NCONF_free(conf);
209     BIO_free(mem_bio);
210     return NULL;
211 }
212
213 static void free_config_and_unload(CONF *conf)
214 {
215     if (conf != NULL) {
216         NCONF_free(conf);
217         CONF_modules_unload(1);
218     }
219 }
220
221 static int verify_module_load(const char *parent_config_file)
222 {
223     return OSSL_LIB_CTX_load_config(NULL, parent_config_file);
224 }
225
226 /*
227  * Returns 1 if the config file entries match the passed in module_mac and
228  * install_mac values, otherwise it returns 0.
229  */
230 static int verify_config(const char *infile, const char *section,
231                          unsigned char *module_mac, size_t module_mac_len,
232                          unsigned char *install_mac, size_t install_mac_len)
233 {
234     int ret = 0;
235     char *s = NULL;
236     unsigned char *buf1 = NULL, *buf2 = NULL;
237     long len;
238     CONF *conf = NULL;
239
240     /* read in the existing values and check they match the saved values */
241     conf = app_load_config(infile);
242     if (conf == NULL)
243         goto end;
244
245     s = NCONF_get_string(conf, section, OSSL_PROV_FIPS_PARAM_INSTALL_VERSION);
246     if (s == NULL || strcmp(s, VERSION_VAL) != 0) {
247         BIO_printf(bio_err, "version not found\n");
248         goto end;
249     }
250     s = NCONF_get_string(conf, section, OSSL_PROV_FIPS_PARAM_INSTALL_STATUS);
251     if (s == NULL || strcmp(s, INSTALL_STATUS_VAL) != 0) {
252         BIO_printf(bio_err, "install status not found\n");
253         goto end;
254     }
255     s = NCONF_get_string(conf, section, OSSL_PROV_FIPS_PARAM_MODULE_MAC);
256     if (s == NULL) {
257         BIO_printf(bio_err, "Module integrity MAC not found\n");
258         goto end;
259     }
260     buf1 = OPENSSL_hexstr2buf(s, &len);
261     if (buf1 == NULL
262             || (size_t)len != module_mac_len
263             || memcmp(module_mac, buf1, module_mac_len) != 0) {
264         BIO_printf(bio_err, "Module integrity mismatch\n");
265         goto end;
266     }
267     s = NCONF_get_string(conf, section, OSSL_PROV_FIPS_PARAM_INSTALL_MAC);
268     if (s == NULL) {
269         BIO_printf(bio_err, "Install indicator MAC not found\n");
270         goto end;
271     }
272     buf2 = OPENSSL_hexstr2buf(s, &len);
273     if (buf2 == NULL
274             || (size_t)len != install_mac_len
275             || memcmp(install_mac, buf2, install_mac_len) != 0) {
276         BIO_printf(bio_err, "Install indicator status mismatch\n");
277         goto end;
278     }
279     ret = 1;
280 end:
281     OPENSSL_free(buf1);
282     OPENSSL_free(buf2);
283     NCONF_free(conf);
284     return ret;
285 }
286
287 int fipsinstall_main(int argc, char **argv)
288 {
289     int ret = 1, verify = 0, gotkey = 0, gotdigest = 0;
290     int enable_conditional_errors = 1, enable_security_checks = 1;
291     const char *section_name = "fips_sect";
292     const char *mac_name = "HMAC";
293     const char *prov_name = "fips";
294     BIO *module_bio = NULL, *mem_bio = NULL, *fout = NULL;
295     char *in_fname = NULL, *out_fname = NULL, *prog;
296     char *module_fname = NULL, *parent_config = NULL, *module_path = NULL;
297     const char *tail;
298     EVP_MAC_CTX *ctx = NULL, *ctx2 = NULL;
299     STACK_OF(OPENSSL_STRING) *opts = NULL;
300     OPTION_CHOICE o;
301     unsigned char *read_buffer = NULL;
302     unsigned char module_mac[EVP_MAX_MD_SIZE];
303     size_t module_mac_len = EVP_MAX_MD_SIZE;
304     unsigned char install_mac[EVP_MAX_MD_SIZE];
305     size_t install_mac_len = EVP_MAX_MD_SIZE;
306     EVP_MAC *mac = NULL;
307     CONF *conf = NULL;
308
309     if ((opts = sk_OPENSSL_STRING_new_null()) == NULL)
310         goto end;
311
312     prog = opt_init(argc, argv, fipsinstall_options);
313     while ((o = opt_next()) != OPT_EOF) {
314         switch (o) {
315         case OPT_EOF:
316         case OPT_ERR:
317 opthelp:
318             BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
319             goto cleanup;
320         case OPT_HELP:
321             opt_help(fipsinstall_options);
322             ret = 0;
323             goto end;
324         case OPT_IN:
325             in_fname = opt_arg();
326             break;
327         case OPT_OUT:
328             out_fname = opt_arg();
329             break;
330         case OPT_NO_CONDITIONAL_ERRORS:
331             enable_conditional_errors = 0;
332             break;
333         case OPT_NO_SECURITY_CHECKS:
334             enable_security_checks = 0;
335             break;
336         case OPT_QUIET:
337             quiet = 1;
338             /* FALLTHROUGH */
339         case OPT_NO_LOG:
340             self_test_log = 0;
341             break;
342         case OPT_CORRUPT_DESC:
343             self_test_corrupt_desc = opt_arg();
344             break;
345         case OPT_CORRUPT_TYPE:
346             self_test_corrupt_type = opt_arg();
347             break;
348         case OPT_PROV_NAME:
349             prov_name = opt_arg();
350             break;
351         case OPT_MODULE:
352             module_fname = opt_arg();
353             break;
354         case OPT_SECTION_NAME:
355             section_name = opt_arg();
356             break;
357         case OPT_MAC_NAME:
358             mac_name = opt_arg();
359             break;
360         case OPT_CONFIG:
361             parent_config = opt_arg();
362             break;
363         case OPT_MACOPT:
364             if (!sk_OPENSSL_STRING_push(opts, opt_arg()))
365                 goto opthelp;
366             if (strncmp(opt_arg(), "hexkey:", 7) == 0)
367                 gotkey = 1;
368             else if (strncmp(opt_arg(), "digest:", 7) == 0)
369                 gotdigest = 1;
370             break;
371         case OPT_VERIFY:
372             verify = 1;
373             break;
374         }
375     }
376     argc = opt_num_rest();
377
378     if (parent_config != NULL) {
379         /* Test that a parent config can load the module */
380         if (verify_module_load(parent_config)) {
381             ret = OSSL_PROVIDER_available(NULL, prov_name) ? 0 : 1;
382             if (!quiet)
383                 BIO_printf(bio_out, "FIPS provider is %s\n",
384                            ret == 0 ? "available" : " not available");
385         }
386         goto end;
387     }
388     if (module_fname == NULL
389         || (verify && in_fname == NULL)
390         || (!verify && out_fname == NULL)
391         || argc != 0)
392         goto opthelp;
393
394     tail = opt_path_end(module_fname);
395     if (tail != NULL) {
396         module_path = OPENSSL_strdup(module_fname);
397         if (module_path == NULL)
398             goto end;
399         module_path[tail - module_fname] = '\0';
400         if (!OSSL_PROVIDER_set_default_search_path(NULL, module_path))
401             goto end;
402     }
403
404     if (self_test_log
405             || self_test_corrupt_desc != NULL
406             || self_test_corrupt_type != NULL)
407         OSSL_SELF_TEST_set_callback(NULL, self_test_events, NULL);
408
409     /* Use the default FIPS HMAC digest and key if not specified. */
410     if (!gotdigest && !sk_OPENSSL_STRING_push(opts, "digest:SHA256"))
411         goto end;
412     if (!gotkey && !sk_OPENSSL_STRING_push(opts, "hexkey:" FIPS_KEY_STRING))
413         goto end;
414
415     module_bio = bio_open_default(module_fname, 'r', FORMAT_BINARY);
416     if (module_bio == NULL) {
417         BIO_printf(bio_err, "Failed to open module file\n");
418         goto end;
419     }
420
421     read_buffer = app_malloc(BUFSIZE, "I/O buffer");
422     if (read_buffer == NULL)
423         goto end;
424
425     mac = EVP_MAC_fetch(NULL, mac_name, NULL);
426     if (mac == NULL) {
427         BIO_printf(bio_err, "Unable to get MAC of type %s\n", mac_name);
428         goto end;
429     }
430
431     ctx = EVP_MAC_CTX_new(mac);
432     if (ctx == NULL) {
433         BIO_printf(bio_err, "Unable to create MAC CTX for module check\n");
434         goto end;
435     }
436
437     if (opts != NULL) {
438         int ok = 1;
439         OSSL_PARAM *params =
440             app_params_new_from_opts(opts, EVP_MAC_settable_ctx_params(mac));
441
442         if (params == NULL)
443             goto end;
444
445         if (!EVP_MAC_CTX_set_params(ctx, params)) {
446             BIO_printf(bio_err, "MAC parameter error\n");
447             ERR_print_errors(bio_err);
448             ok = 0;
449         }
450         app_params_free(params);
451         if (!ok)
452             goto end;
453     }
454
455     ctx2 = EVP_MAC_CTX_dup(ctx);
456     if (ctx2 == NULL) {
457         BIO_printf(bio_err, "Unable to create MAC CTX for install indicator\n");
458         goto end;
459     }
460
461     if (!do_mac(ctx, read_buffer, module_bio, module_mac, &module_mac_len))
462         goto end;
463
464     mem_bio = BIO_new_mem_buf((const void *)INSTALL_STATUS_VAL,
465                               strlen(INSTALL_STATUS_VAL));
466     if (mem_bio == NULL) {
467         BIO_printf(bio_err, "Unable to create memory BIO\n");
468         goto end;
469     }
470     if (!do_mac(ctx2, read_buffer, mem_bio, install_mac, &install_mac_len))
471         goto end;
472
473     if (verify) {
474         if (!verify_config(in_fname, section_name, module_mac, module_mac_len,
475                            install_mac, install_mac_len))
476             goto end;
477         if (!quiet)
478             BIO_printf(bio_out, "VERIFY PASSED\n");
479     } else {
480
481         conf = generate_config_and_load(prov_name, section_name, module_mac,
482                                         module_mac_len,
483                                         enable_conditional_errors,
484                                         enable_security_checks);
485         if (conf == NULL)
486             goto end;
487         if (!load_fips_prov_and_run_self_test(prov_name))
488             goto end;
489
490         fout = bio_open_default(out_fname, 'w', FORMAT_TEXT);
491         if (fout == NULL) {
492             BIO_printf(bio_err, "Failed to open file\n");
493             goto end;
494         }
495         if (!write_config_fips_section(fout, section_name,
496                                        module_mac, module_mac_len,
497                                        enable_conditional_errors,
498                                        enable_security_checks,
499                                        install_mac, install_mac_len))
500             goto end;
501         if (!quiet)
502             BIO_printf(bio_out, "INSTALL PASSED\n");
503     }
504
505     ret = 0;
506 end:
507     if (ret == 1) {
508         if (!quiet)
509             BIO_printf(bio_err, "%s FAILED\n", verify ? "VERIFY" : "INSTALL");
510         ERR_print_errors(bio_err);
511     }
512
513 cleanup:
514     OPENSSL_free(module_path);
515     BIO_free(fout);
516     BIO_free(mem_bio);
517     BIO_free(module_bio);
518     sk_OPENSSL_STRING_free(opts);
519     EVP_MAC_free(mac);
520     EVP_MAC_CTX_free(ctx2);
521     EVP_MAC_CTX_free(ctx);
522     OPENSSL_free(read_buffer);
523     free_config_and_unload(conf);
524     return ret;
525 }
526
527 static int self_test_events(const OSSL_PARAM params[], void *arg)
528 {
529     const OSSL_PARAM *p = NULL;
530     const char *phase = NULL, *type = NULL, *desc = NULL;
531     int ret = 0;
532
533     p = OSSL_PARAM_locate_const(params, OSSL_PROV_PARAM_SELF_TEST_PHASE);
534     if (p == NULL || p->data_type != OSSL_PARAM_UTF8_STRING)
535         goto err;
536     phase = (const char *)p->data;
537
538     p = OSSL_PARAM_locate_const(params, OSSL_PROV_PARAM_SELF_TEST_DESC);
539     if (p == NULL || p->data_type != OSSL_PARAM_UTF8_STRING)
540         goto err;
541     desc = (const char *)p->data;
542
543     p = OSSL_PARAM_locate_const(params, OSSL_PROV_PARAM_SELF_TEST_TYPE);
544     if (p == NULL || p->data_type != OSSL_PARAM_UTF8_STRING)
545         goto err;
546     type = (const char *)p->data;
547
548     if (self_test_log) {
549         if (strcmp(phase, OSSL_SELF_TEST_PHASE_START) == 0)
550             BIO_printf(bio_out, "%s : (%s) : ", desc, type);
551         else if (strcmp(phase, OSSL_SELF_TEST_PHASE_PASS) == 0
552                  || strcmp(phase, OSSL_SELF_TEST_PHASE_FAIL) == 0)
553             BIO_printf(bio_out, "%s\n", phase);
554     }
555     /*
556      * The self test code will internally corrupt the KAT test result if an
557      * error is returned during the corrupt phase.
558      */
559     if (strcmp(phase, OSSL_SELF_TEST_PHASE_CORRUPT) == 0
560             && (self_test_corrupt_desc != NULL
561                 || self_test_corrupt_type != NULL)) {
562         if (self_test_corrupt_desc != NULL
563                 && strcmp(self_test_corrupt_desc, desc) != 0)
564             goto end;
565         if (self_test_corrupt_type != NULL
566                 && strcmp(self_test_corrupt_type, type) != 0)
567             goto end;
568         BIO_printf(bio_out, "%s ", phase);
569         goto err;
570     }
571 end:
572     ret = 1;
573 err:
574     return ret;
575 }