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