1#! /usr/bin/env perl
2# Copyright 2019-2022 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
9use strict;
10use warnings;
11
12use File::Spec::Functions qw(:DEFAULT abs2rel);
13use File::Copy;
14use OpenSSL::Glob;
15use OpenSSL::Test qw/:DEFAULT srctop_dir srctop_file bldtop_dir bldtop_file/;
16use OpenSSL::Test::Utils;
17
18BEGIN {
19    setup("test_fipsinstall");
20}
21use lib srctop_dir('Configurations');
22use lib bldtop_dir('.');
23use platform;
24
25plan skip_all => "Test only supported in a fips build" if disabled("fips");
26
27plan tests => 29;
28
29my $infile = bldtop_file('providers', platform->dso('fips'));
30my $fipskey = $ENV{FIPSKEY} // config('FIPSKEY') // '00';
31
32# Read in a text $infile and replace the regular expression in $srch with the
33# value in $repl and output to a new file $outfile.
34sub replace_line_file_internal {
35
36    my ($infile, $srch, $repl, $outfile) = @_;
37    my $msg;
38
39    open(my $in, "<", $infile) or return 0;
40    read($in, $msg, 1024);
41    close $in;
42
43    $msg =~ s/$srch/$repl/;
44
45    open(my $fh, ">", $outfile) or return 0;
46    print $fh $msg;
47    close $fh;
48    return 1;
49}
50
51# Read in the text input file 'fips.cnf'
52# and replace a single Key = Value line with a new value in $value.
53# OR remove the Key = Value line if the passed in $value is empty.
54# and then output a new file $outfile.
55# $key is the Key to find
56sub replace_line_file {
57    my ($key, $value, $outfile) = @_;
58
59    my $srch = qr/$key\s*=\s*\S*\n/;
60    my $rep;
61    if ($value eq "") {
62        $rep = "";
63    } else {
64       $rep = "$key = $value\n";
65    }
66    return replace_line_file_internal('fips.cnf', $srch, $rep, $outfile);
67}
68
69# Read in the text input file 'test/fips.cnf'
70# and replace the .cnf file used in
71# .include fipsmodule.cnf with a new value in $value.
72# and then output a new file $outfile.
73# $key is the Key to find
74sub replace_parent_line_file {
75    my ($value, $outfile) = @_;
76    my $srch = qr/fipsmodule.cnf/;
77    my $rep = "$value";
78    return replace_line_file_internal(srctop_file("test", 'fips.cnf'),
79                                      $srch, $rep, $outfile);
80}
81
82# fail if no module name
83ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips.cnf', '-module',
84             '-provider_name', 'fips',
85             '-macopt', 'digest:SHA256', '-macopt', "hexkey:$fipskey",
86             '-section_name', 'fips_sect'])),
87   "fipsinstall fail");
88
89# fail to verify if the configuration file is missing
90ok(!run(app(['openssl', 'fipsinstall', '-in', 'dummy.tmp', '-module', $infile,
91             '-provider_name', 'fips', '-mac_name', 'HMAC',
92             '-macopt', 'digest:SHA256', '-macopt', "hexkey:$fipskey",
93             '-section_name', 'fips_sect', '-verify'])),
94   "fipsinstall verify fail");
95
96
97# output a fips.cnf file containing mac data
98ok(run(app(['openssl', 'fipsinstall', '-out', 'fips.cnf', '-module', $infile,
99            '-provider_name', 'fips', '-mac_name', 'HMAC',
100            '-macopt', 'digest:SHA256', '-macopt', "hexkey:$fipskey",
101            '-section_name', 'fips_sect'])),
102   "fipsinstall");
103
104# verify the fips.cnf file
105ok(run(app(['openssl', 'fipsinstall', '-in', 'fips.cnf', '-module', $infile,
106            '-provider_name', 'fips', '-mac_name', 'HMAC',
107            '-macopt', 'digest:SHA256', '-macopt', "hexkey:$fipskey",
108            '-section_name', 'fips_sect', '-verify'])),
109   "fipsinstall verify");
110
111ok(replace_line_file('module-mac', '', 'fips_no_module_mac.cnf')
112   && !run(app(['openssl', 'fipsinstall',
113                '-in', 'fips_no_module_mac.cnf',
114                '-module', $infile,
115                '-provider_name', 'fips', '-mac_name', 'HMAC',
116                '-macopt', 'digest:SHA256', '-macopt', "hexkey:01",
117                '-section_name', 'fips_sect', '-verify'])),
118   "fipsinstall verify fail no module mac");
119
120ok(replace_line_file('install-mac', '', 'fips_no_install_mac.cnf')
121   && !run(app(['openssl', 'fipsinstall',
122                '-in', 'fips_no_install_mac.cnf',
123                '-module', $infile,
124                '-provider_name', 'fips', '-mac_name', 'HMAC',
125                '-macopt', 'digest:SHA256', '-macopt', "hexkey:01",
126                '-section_name', 'fips_sect', '-verify'])),
127   "fipsinstall verify fail no install indicator mac");
128
129ok(replace_line_file('module-mac', '00:00:00:00:00:00',
130                     'fips_bad_module_mac.cnf')
131   && !run(app(['openssl', 'fipsinstall',
132                '-in', 'fips_bad_module_mac.cnf',
133                '-module', $infile,
134                '-provider_name', 'fips', '-mac_name', 'HMAC',
135                '-macopt', 'digest:SHA256', '-macopt', "hexkey:01",
136                '-section_name', 'fips_sect', '-verify'])),
137   "fipsinstall verify fail if invalid module integrity value");
138
139ok(replace_line_file('install-mac', '00:00:00:00:00:00',
140                     'fips_bad_install_mac.cnf')
141   && !run(app(['openssl', 'fipsinstall',
142                '-in', 'fips_bad_install_mac.cnf',
143                '-module', $infile,
144                '-provider_name', 'fips', '-mac_name', 'HMAC',
145                '-macopt', 'digest:SHA256', '-macopt', "hexkey:01",
146                '-section_name', 'fips_sect', '-verify'])),
147   "fipsinstall verify fail if invalid install indicator integrity value");
148
149ok(replace_line_file('install-status', 'INCORRECT_STATUS_STRING',
150                     'fips_bad_indicator.cnf')
151   && !run(app(['openssl', 'fipsinstall',
152                '-in', 'fips_bad_indicator.cnf',
153                '-module', $infile,
154                '-provider_name', 'fips', '-mac_name', 'HMAC',
155                '-macopt', 'digest:SHA256', '-macopt', "hexkey:01",
156                '-section_name', 'fips_sect', '-verify'])),
157   "fipsinstall verify fail if invalid install indicator status");
158
159# fail to verify the fips.cnf file if a different key is used
160ok(!run(app(['openssl', 'fipsinstall', '-in', 'fips.cnf', '-module', $infile,
161             '-provider_name', 'fips', '-mac_name', 'HMAC',
162             '-macopt', 'digest:SHA256', '-macopt', "hexkey:01",
163             '-section_name', 'fips_sect', '-verify'])),
164   "fipsinstall verify fail bad key");
165
166# fail to verify the fips.cnf file if a different mac digest is used
167ok(!run(app(['openssl', 'fipsinstall', '-in', 'fips.cnf', '-module', $infile,
168             '-provider_name', 'fips', '-mac_name', 'HMAC',
169             '-macopt', 'digest:SHA512', '-macopt', "hexkey:$fipskey",
170             '-section_name', 'fips_sect', '-verify'])),
171   "fipsinstall verify fail incorrect digest");
172
173# corrupt the module hmac
174ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips.cnf', '-module', $infile,
175            '-provider_name', 'fips', '-mac_name', 'HMAC',
176            '-macopt', 'digest:SHA256', '-macopt', "hexkey:$fipskey",
177            '-section_name', 'fips_sect', '-corrupt_desc', 'HMAC'])),
178   "fipsinstall fails when the module integrity is corrupted");
179
180# corrupt the first digest
181ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips_fail.cnf', '-module', $infile,
182            '-provider_name', 'fips', '-mac_name', 'HMAC',
183            '-macopt', 'digest:SHA256', '-macopt', "hexkey:$fipskey",
184            '-section_name', 'fips_sect', '-corrupt_desc', 'SHA1'])),
185   "fipsinstall fails when the digest result is corrupted");
186
187# corrupt another digest
188ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips_fail.cnf', '-module', $infile,
189            '-provider_name', 'fips', '-mac_name', 'HMAC',
190            '-macopt', 'digest:SHA256', '-macopt', "hexkey:$fipskey",
191            '-section_name', 'fips_sect', '-corrupt_desc', 'SHA3'])),
192   "fipsinstall fails when the digest result is corrupted");
193
194# corrupt cipher encrypt test
195ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips_fail.cnf', '-module', $infile,
196            '-provider_name', 'fips', '-mac_name', 'HMAC',
197            '-macopt', 'digest:SHA256', '-macopt', "hexkey:$fipskey",
198            '-section_name', 'fips_sect', '-corrupt_desc', 'AES_GCM'])),
199   "fipsinstall fails when the AES_GCM result is corrupted");
200
201# corrupt cipher decrypt test
202ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips_fail.cnf', '-module', $infile,
203            '-provider_name', 'fips', '-mac_name', 'HMAC',
204            '-macopt', 'digest:SHA256', '-macopt', "hexkey:$fipskey",
205            '-section_name', 'fips_sect', '-corrupt_desc', 'AES_ECB_Decrypt'])),
206   "fipsinstall fails when the AES_ECB result is corrupted");
207
208# corrupt DRBG
209ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips_fail.cnf', '-module', $infile,
210            '-provider_name', 'fips', '-mac_name', 'HMAC',
211            '-macopt', 'digest:SHA256', '-macopt', "hexkey:$fipskey",
212            '-section_name', 'fips_sect', '-corrupt_desc', 'CTR'])),
213   "fipsinstall fails when the DRBG CTR result is corrupted");
214
215# corrupt a KAS test
216SKIP: {
217    skip "Skipping KAS DH corruption test because of no dh in this build", 1
218        if disabled("dh");
219
220    ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips.cnf', '-module', $infile,
221                '-provider_name', 'fips', '-mac_name', 'HMAC',
222                '-macopt', 'digest:SHA256', '-macopt', "hexkey:$fipskey",
223                '-section_name', 'fips_sect',
224                '-corrupt_desc', 'DH',
225                '-corrupt_type', 'KAT_KA'])),
226       "fipsinstall fails when the kas result is corrupted");
227}
228
229# corrupt a Signature test
230SKIP: {
231    skip "Skipping Signature DSA corruption test because of no dsa in this build", 1
232        if disabled("dsa");
233    ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips.cnf', '-module', $infile,
234                '-provider_name', 'fips', '-mac_name', 'HMAC',
235                '-macopt', 'digest:SHA256', '-macopt', "hexkey:$fipskey",
236                '-section_name', 'fips_sect',
237                '-corrupt_desc', 'DSA',
238                '-corrupt_type', 'PCT_Signature'])),
239       "fipsinstall fails when the signature result is corrupted");
240}
241
242# corrupt an Asymmetric cipher test
243SKIP: {
244    skip "Skipping Asymmetric RSA corruption test because of no rsa in this build", 1
245        if disabled("rsa");
246    ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips.cnf', '-module', $infile,
247                '-corrupt_desc', 'RSA_Encrypt',
248                '-corrupt_type', 'KAT_AsymmetricCipher'])),
249       "fipsinstall fails when the asymmetric cipher result is corrupted");
250}
251
252# 'local' ensures that this change is only done in this file.
253local $ENV{OPENSSL_CONF_INCLUDE} = abs2rel(curdir());
254
255ok(replace_parent_line_file('fips.cnf', 'fips_parent.cnf')
256   && run(app(['openssl', 'fipsinstall', '-config', 'fips_parent.cnf'])),
257   "verify fips provider loads from a configuration file");
258
259ok(replace_parent_line_file('fips_no_module_mac.cnf',
260                            'fips_parent_no_module_mac.cnf')
261   && !run(app(['openssl', 'fipsinstall',
262                '-config', 'fips_parent_no_module_mac.cnf'])),
263   "verify load config fail no module mac");
264
265ok(replace_parent_line_file('fips_no_install_mac.cnf',
266                            'fips_parent_no_install_mac.cnf')
267   && !run(app(['openssl', 'fipsinstall',
268                '-config', 'fips_parent_no_install_mac.cnf'])),
269   "verify load config fail no install mac");
270
271ok(replace_parent_line_file('fips_bad_indicator.cnf',
272                            'fips_parent_bad_indicator.cnf')
273   && !run(app(['openssl', 'fipsinstall',
274                '-config', 'fips_parent_bad_indicator.cnf'])),
275   "verify load config fail bad indicator");
276
277
278ok(replace_parent_line_file('fips_bad_install_mac.cnf',
279                            'fips_parent_bad_install_mac.cnf')
280   && !run(app(['openssl', 'fipsinstall',
281                '-config', 'fips_parent_bad_install_mac.cnf'])),
282   "verify load config fail bad install mac");
283
284ok(replace_parent_line_file('fips_bad_module_mac.cnf',
285                            'fips_parent_bad_module_mac.cnf')
286   && !run(app(['openssl', 'fipsinstall',
287                '-config', 'fips_parent_bad_module_mac.cnf'])),
288   "verify load config fail bad module mac");
289
290
291my $stconf = "fipsmodule_selftest.cnf";
292
293ok(run(app(['openssl', 'fipsinstall', '-out', $stconf,
294            '-module', $infile, '-self_test_onload'])),
295       "fipsinstall config saved without self test indicator");
296
297ok(!run(app(['openssl', 'fipsinstall', '-in', $stconf,
298             '-module', $infile, '-verify'])),
299        "fipsinstall config verify fails without self test indicator");
300
301ok(run(app(['openssl', 'fipsinstall', '-in', $stconf,
302            '-module', $infile, '-self_test_onload', '-verify'])),
303       "fipsinstall config verify passes when self test indicator is not present");
304