Update copyright year
[openssl.git] / apps / fipsinstall.c
1 /*
2  * Copyright 2019-2021 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, NULL, 0, NULL))
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
377     /* No extra arguments. */
378     argc = opt_num_rest();
379     if (argc != 0)
380         goto opthelp;
381
382     if (parent_config != NULL) {
383         /* Test that a parent config can load the module */
384         if (verify_module_load(parent_config)) {
385             ret = OSSL_PROVIDER_available(NULL, prov_name) ? 0 : 1;
386             if (!quiet)
387                 BIO_printf(bio_err, "FIPS provider is %s\n",
388                            ret == 0 ? "available" : " not available");
389         }
390         goto end;
391     }
392     if (module_fname == NULL
393             || (verify && in_fname == NULL)
394             || (!verify && out_fname == NULL))
395         goto opthelp;
396
397     tail = opt_path_end(module_fname);
398     if (tail != NULL) {
399         module_path = OPENSSL_strdup(module_fname);
400         if (module_path == NULL)
401             goto end;
402         module_path[tail - module_fname] = '\0';
403         if (!OSSL_PROVIDER_set_default_search_path(NULL, module_path))
404             goto end;
405     }
406
407     if (self_test_log
408             || self_test_corrupt_desc != NULL
409             || self_test_corrupt_type != NULL)
410         OSSL_SELF_TEST_set_callback(NULL, self_test_events, NULL);
411
412     /* Use the default FIPS HMAC digest and key if not specified. */
413     if (!gotdigest && !sk_OPENSSL_STRING_push(opts, "digest:SHA256"))
414         goto end;
415     if (!gotkey && !sk_OPENSSL_STRING_push(opts, "hexkey:" FIPS_KEY_STRING))
416         goto end;
417
418     module_bio = bio_open_default(module_fname, 'r', FORMAT_BINARY);
419     if (module_bio == NULL) {
420         BIO_printf(bio_err, "Failed to open module file\n");
421         goto end;
422     }
423
424     read_buffer = app_malloc(BUFSIZE, "I/O buffer");
425     if (read_buffer == NULL)
426         goto end;
427
428     mac = EVP_MAC_fetch(NULL, mac_name, NULL);
429     if (mac == NULL) {
430         BIO_printf(bio_err, "Unable to get MAC of type %s\n", mac_name);
431         goto end;
432     }
433
434     ctx = EVP_MAC_CTX_new(mac);
435     if (ctx == NULL) {
436         BIO_printf(bio_err, "Unable to create MAC CTX for module check\n");
437         goto end;
438     }
439
440     if (opts != NULL) {
441         int ok = 1;
442         OSSL_PARAM *params =
443             app_params_new_from_opts(opts, EVP_MAC_settable_ctx_params(mac));
444
445         if (params == NULL)
446             goto end;
447
448         if (!EVP_MAC_CTX_set_params(ctx, params)) {
449             BIO_printf(bio_err, "MAC parameter error\n");
450             ERR_print_errors(bio_err);
451             ok = 0;
452         }
453         app_params_free(params);
454         if (!ok)
455             goto end;
456     }
457
458     ctx2 = EVP_MAC_CTX_dup(ctx);
459     if (ctx2 == NULL) {
460         BIO_printf(bio_err, "Unable to create MAC CTX for install indicator\n");
461         goto end;
462     }
463
464     if (!do_mac(ctx, read_buffer, module_bio, module_mac, &module_mac_len))
465         goto end;
466
467     mem_bio = BIO_new_mem_buf((const void *)INSTALL_STATUS_VAL,
468                               strlen(INSTALL_STATUS_VAL));
469     if (mem_bio == NULL) {
470         BIO_printf(bio_err, "Unable to create memory BIO\n");
471         goto end;
472     }
473     if (!do_mac(ctx2, read_buffer, mem_bio, install_mac, &install_mac_len))
474         goto end;
475
476     if (verify) {
477         if (!verify_config(in_fname, section_name, module_mac, module_mac_len,
478                            install_mac, install_mac_len))
479             goto end;
480         if (!quiet)
481             BIO_printf(bio_err, "VERIFY PASSED\n");
482     } else {
483
484         conf = generate_config_and_load(prov_name, section_name, module_mac,
485                                         module_mac_len,
486                                         enable_conditional_errors,
487                                         enable_security_checks);
488         if (conf == NULL)
489             goto end;
490         if (!load_fips_prov_and_run_self_test(prov_name))
491             goto end;
492
493         fout = bio_open_default(out_fname, 'w', FORMAT_TEXT);
494         if (fout == NULL) {
495             BIO_printf(bio_err, "Failed to open file\n");
496             goto end;
497         }
498         if (!write_config_fips_section(fout, section_name,
499                                        module_mac, module_mac_len,
500                                        enable_conditional_errors,
501                                        enable_security_checks,
502                                        install_mac, install_mac_len))
503             goto end;
504         if (!quiet)
505             BIO_printf(bio_err, "INSTALL PASSED\n");
506     }
507
508     ret = 0;
509 end:
510     if (ret == 1) {
511         if (!quiet)
512             BIO_printf(bio_err, "%s FAILED\n", verify ? "VERIFY" : "INSTALL");
513         ERR_print_errors(bio_err);
514     }
515
516 cleanup:
517     OPENSSL_free(module_path);
518     BIO_free(fout);
519     BIO_free(mem_bio);
520     BIO_free(module_bio);
521     sk_OPENSSL_STRING_free(opts);
522     EVP_MAC_free(mac);
523     EVP_MAC_CTX_free(ctx2);
524     EVP_MAC_CTX_free(ctx);
525     OPENSSL_free(read_buffer);
526     free_config_and_unload(conf);
527     return ret;
528 }
529
530 static int self_test_events(const OSSL_PARAM params[], void *arg)
531 {
532     const OSSL_PARAM *p = NULL;
533     const char *phase = NULL, *type = NULL, *desc = NULL;
534     int ret = 0;
535
536     p = OSSL_PARAM_locate_const(params, OSSL_PROV_PARAM_SELF_TEST_PHASE);
537     if (p == NULL || p->data_type != OSSL_PARAM_UTF8_STRING)
538         goto err;
539     phase = (const char *)p->data;
540
541     p = OSSL_PARAM_locate_const(params, OSSL_PROV_PARAM_SELF_TEST_DESC);
542     if (p == NULL || p->data_type != OSSL_PARAM_UTF8_STRING)
543         goto err;
544     desc = (const char *)p->data;
545
546     p = OSSL_PARAM_locate_const(params, OSSL_PROV_PARAM_SELF_TEST_TYPE);
547     if (p == NULL || p->data_type != OSSL_PARAM_UTF8_STRING)
548         goto err;
549     type = (const char *)p->data;
550
551     if (self_test_log) {
552         if (strcmp(phase, OSSL_SELF_TEST_PHASE_START) == 0)
553             BIO_printf(bio_err, "%s : (%s) : ", desc, type);
554         else if (strcmp(phase, OSSL_SELF_TEST_PHASE_PASS) == 0
555                  || strcmp(phase, OSSL_SELF_TEST_PHASE_FAIL) == 0)
556             BIO_printf(bio_err, "%s\n", phase);
557     }
558     /*
559      * The self test code will internally corrupt the KAT test result if an
560      * error is returned during the corrupt phase.
561      */
562     if (strcmp(phase, OSSL_SELF_TEST_PHASE_CORRUPT) == 0
563             && (self_test_corrupt_desc != NULL
564                 || self_test_corrupt_type != NULL)) {
565         if (self_test_corrupt_desc != NULL
566                 && strcmp(self_test_corrupt_desc, desc) != 0)
567             goto end;
568         if (self_test_corrupt_type != NULL
569                 && strcmp(self_test_corrupt_type, type) != 0)
570             goto end;
571         BIO_printf(bio_err, "%s ", phase);
572         goto err;
573     }
574 end:
575     ret = 1;
576 err:
577     return ret;
578 }