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