1#! /usr/bin/env perl
2# Copyright 2020-2023 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;
13use File::Spec::Functions qw/curdir abs2rel/;
14use File::Copy;
15use OpenSSL::Glob;
16use OpenSSL::Test qw/:DEFAULT srctop_dir bldtop_dir bldtop_file srctop_file data_file/;
17use OpenSSL::Test::Utils;
18
19BEGIN {
20    setup("test_cli_fips");
21}
22use lib srctop_dir('Configurations');
23use lib bldtop_dir('.');
24use platform;
25
26my $no_check = disabled("fips") || disabled('fips-securitychecks');
27plan skip_all => "Test only supported in a fips build with security checks"
28    if $no_check;
29plan tests => 11;
30
31my $fipsmodule = bldtop_file('providers', platform->dso('fips'));
32my $fipsconf = srctop_file("test", "fips-and-base.cnf");
33my $defaultconf = srctop_file("test", "default.cnf");
34my $tbs_data = $fipsmodule;
35my $bogus_data = $fipsconf;
36
37$ENV{OPENSSL_CONF} = $fipsconf;
38
39ok(run(app(['openssl', 'list', '-public-key-methods', '-verbose'])),
40   "provider listing of public key methods");
41ok(run(app(['openssl', 'list', '-public-key-algorithms', '-verbose'])),
42   "provider listing of public key algorithms");
43ok(run(app(['openssl', 'list', '-key-managers', '-verbose'])),
44   "provider listing of keymanagers");
45ok(run(app(['openssl', 'list', '-key-exchange-algorithms', '-verbose'])),
46   "provider listing of key exchange algorithms");
47ok(run(app(['openssl', 'list', '-kem-algorithms', '-verbose'])),
48   "provider listing of key encapsulation algorithms");
49ok(run(app(['openssl', 'list', '-signature-algorithms', '-verbose'])),
50   "provider listing of signature algorithms");
51ok(run(app(['openssl', 'list', '-asymcipher-algorithms', '-verbose'])),
52   "provider listing of encryption algorithms");
53ok(run(app(['openssl', 'list', '-key-managers', '-verbose', '-select', 'DSA' ])),
54   "provider listing of one item in the keymanager");
55
56sub pubfrompriv {
57    my $prefix = shift;
58    my $key = shift;
59    my $pub_key = shift;
60    my $type = shift;
61
62    ok(run(app(['openssl', 'pkey',
63                '-in', $key,
64                '-pubout',
65                '-out', $pub_key])),
66        $prefix.': '."Create the public key with $type parameters");
67
68}
69
70my $tsignverify_count = 9;
71sub tsignverify {
72    my $prefix = shift;
73    my $fips_key = shift;
74    my $fips_pub_key = shift;
75    my $nonfips_key = shift;
76    my $nonfips_pub_key = shift;
77    my $fips_sigfile = $prefix.'.fips.sig';
78    my $nonfips_sigfile = $prefix.'.nonfips.sig';
79    my $sigfile = '';
80    my $testtext = '';
81
82    $ENV{OPENSSL_CONF} = $fipsconf;
83
84    $sigfile = $fips_sigfile;
85    $testtext = $prefix.': '.
86        'Sign something with a FIPS key';
87    ok(run(app(['openssl', 'dgst', '-sha256',
88                '-sign', $fips_key,
89                '-out', $sigfile,
90                $tbs_data])),
91       $testtext);
92
93    $testtext = $prefix.': '.
94        'Verify something with a FIPS key';
95    ok(run(app(['openssl', 'dgst', '-sha256',
96                '-verify', $fips_pub_key,
97                '-signature', $sigfile,
98                $tbs_data])),
99       $testtext);
100
101    $testtext = $prefix.': '.
102        'Verify a valid signature against the wrong data with a FIPS key'.
103        ' (should fail)';
104    ok(!run(app(['openssl', 'dgst', '-sha256',
105                 '-verify', $fips_pub_key,
106                 '-signature', $sigfile,
107                 $bogus_data])),
108       $testtext);
109
110    $ENV{OPENSSL_CONF} = $defaultconf;
111
112    SKIP : {
113        skip "FIPS failure testing", 6
114            if ($nonfips_key eq '');
115
116        $sigfile = $nonfips_sigfile;
117        $testtext = $prefix.': '.
118            'Sign something with a non-FIPS key'.
119            ' with the default provider';
120        ok(run(app(['openssl', 'dgst', '-sha256',
121                    '-sign', $nonfips_key,
122                    '-out', $sigfile,
123                    $tbs_data])),
124           $testtext);
125
126        $testtext = $prefix.': '.
127            'Verify something with a non-FIPS key'.
128            ' with the default provider';
129        ok(run(app(['openssl', 'dgst', '-sha256',
130                    '-verify', $nonfips_pub_key,
131                    '-signature', $sigfile,
132                    $tbs_data])),
133           $testtext);
134
135        $ENV{OPENSSL_CONF} = $fipsconf;
136
137        $testtext = $prefix.': '.
138            'Sign something with a non-FIPS key'.
139            ' (should fail)';
140        ok(!run(app(['openssl', 'dgst', '-sha256',
141                     '-sign', $nonfips_key,
142                     '-out', $prefix.'.nonfips.fail.sig',
143                     $tbs_data])),
144           $testtext);
145
146        $testtext = $prefix.': '.
147            'Verify something with a non-FIPS key'.
148            ' (should fail)';
149        ok(!run(app(['openssl', 'dgst', '-sha256',
150                     '-verify', $nonfips_pub_key,
151                     '-signature', $sigfile,
152                     $tbs_data])),
153           $testtext);
154
155        $testtext = $prefix.': '.
156            'Verify something with a non-FIPS key'.
157		    ' in FIPS mode but with a non-FIPS property query';
158        ok(run(app(['openssl', 'dgst',
159				    '-provider', 'default',
160				    '-propquery', '?fips!=yes',
161				    '-sha256',
162                    '-verify', $nonfips_pub_key,
163                    '-signature', $sigfile,
164                    $tbs_data])),
165           $testtext);
166
167        $testtext = $prefix.': '.
168            'Verify a valid signature against the wrong data with a non-FIPS key'.
169            ' (should fail)';
170        ok(!run(app(['openssl', 'dgst', '-sha256',
171                     '-verify', $nonfips_pub_key,
172                     '-signature', $sigfile,
173                     $bogus_data])),
174           $testtext);
175   }
176}
177
178SKIP : {
179    skip "FIPS EC tests because of no ec in this build", 1
180        if disabled("ec");
181
182    subtest EC => sub {
183        my $testtext_prefix = 'EC';
184        my $a_fips_curve = 'prime256v1';
185        my $fips_key = $testtext_prefix.'.fips.priv.pem';
186        my $fips_pub_key = $testtext_prefix.'.fips.pub.pem';
187        my $a_nonfips_curve = 'brainpoolP256r1';
188        my $nonfips_key = $testtext_prefix.'.nonfips.priv.pem';
189        my $nonfips_pub_key = $testtext_prefix.'.nonfips.pub.pem';
190        my $testtext = '';
191        my $curvename = '';
192
193        plan tests => 5 + $tsignverify_count;
194
195        $ENV{OPENSSL_CONF} = $defaultconf;
196        $curvename = $a_nonfips_curve;
197        $testtext = $testtext_prefix.': '.
198            'Generate a key with a non-FIPS algorithm with the default provider';
199        ok(run(app(['openssl', 'genpkey', '-algorithm', 'EC',
200                    '-pkeyopt', 'ec_paramgen_curve:'.$curvename,
201                    '-out', $nonfips_key])),
202           $testtext);
203
204        pubfrompriv($testtext_prefix, $nonfips_key, $nonfips_pub_key, "non-FIPS");
205
206        $ENV{OPENSSL_CONF} = $fipsconf;
207
208        $curvename = $a_fips_curve;
209        $testtext = $testtext_prefix.': '.
210            'Generate a key with a FIPS algorithm';
211        ok(run(app(['openssl', 'genpkey', '-algorithm', 'EC',
212                    '-pkeyopt', 'ec_paramgen_curve:'.$curvename,
213                    '-out', $fips_key])),
214           $testtext);
215
216        pubfrompriv($testtext_prefix, $fips_key, $fips_pub_key, "FIPS");
217
218        $curvename = $a_nonfips_curve;
219        $testtext = $testtext_prefix.': '.
220            'Generate a key with a non-FIPS algorithm'.
221            ' (should fail)';
222        ok(!run(app(['openssl', 'genpkey', '-algorithm', 'EC',
223                     '-pkeyopt', 'ec_paramgen_curve:'.$curvename,
224                     '-out', $testtext_prefix.'.'.$curvename.'.priv.pem'])),
225           $testtext);
226
227        tsignverify($testtext_prefix, $fips_key, $fips_pub_key, $nonfips_key,
228                    $nonfips_pub_key);
229    };
230}
231
232SKIP: {
233    skip "FIPS RSA tests because of no rsa in this build", 1
234        if disabled("rsa");
235
236    subtest RSA => sub {
237        my $testtext_prefix = 'RSA';
238        my $fips_key = $testtext_prefix.'.fips.priv.pem';
239        my $fips_pub_key = $testtext_prefix.'.fips.pub.pem';
240        my $nonfips_key = $testtext_prefix.'.nonfips.priv.pem';
241        my $nonfips_pub_key = $testtext_prefix.'.nonfips.pub.pem';
242        my $testtext = '';
243
244        plan tests => 5 + $tsignverify_count;
245
246        $ENV{OPENSSL_CONF} = $defaultconf;
247        $testtext = $testtext_prefix.': '.
248            'Generate a key with a non-FIPS algorithm with the default provider';
249        ok(run(app(['openssl', 'genpkey', '-algorithm', 'RSA',
250                    '-pkeyopt', 'rsa_keygen_bits:512',
251                    '-out', $nonfips_key])),
252           $testtext);
253
254        pubfrompriv($testtext_prefix, $nonfips_key, $nonfips_pub_key, "non-FIPS");
255
256        $ENV{OPENSSL_CONF} = $fipsconf;
257
258        $testtext = $testtext_prefix.': '.
259            'Generate a key with a FIPS algorithm';
260        ok(run(app(['openssl', 'genpkey', '-algorithm', 'RSA',
261                    '-pkeyopt', 'rsa_keygen_bits:2048',
262                    '-out', $fips_key])),
263           $testtext);
264
265        pubfrompriv($testtext_prefix, $fips_key, $fips_pub_key, "FIPS");
266
267        $testtext = $testtext_prefix.': '.
268            'Generate a key with a non-FIPS algorithm'.
269            ' (should fail)';
270        ok(!run(app(['openssl', 'genpkey', '-algorithm', 'RSA',
271                    '-pkeyopt', 'rsa_keygen_bits:512',
272                     '-out', $testtext_prefix.'.fail.priv.pem'])),
273           $testtext);
274
275        tsignverify($testtext_prefix, $fips_key, $fips_pub_key, $nonfips_key,
276                    $nonfips_pub_key);
277    };
278}
279
280SKIP : {
281    skip "FIPS DSA tests because of no dsa in this build", 1
282        if disabled("dsa");
283
284    subtest DSA => sub {
285        my $testtext_prefix = 'DSA';
286        my $fips_key = $testtext_prefix.'.fips.priv.pem';
287        my $fips_pub_key = $testtext_prefix.'.fips.pub.pem';
288        my $nonfips_key = $testtext_prefix.'.nonfips.priv.pem';
289        my $nonfips_pub_key = $testtext_prefix.'.nonfips.pub.pem';
290        my $testtext = '';
291        my $fips_param = $testtext_prefix.'.fips.param.pem';
292        my $nonfips_param = $testtext_prefix.'.nonfips.param.pem';
293        my $shortnonfips_param = $testtext_prefix.'.shortnonfips.param.pem';
294
295        plan tests => 13 + $tsignverify_count;
296
297        $ENV{OPENSSL_CONF} = $defaultconf;
298
299        $testtext = $testtext_prefix.': '.
300            'Generate non-FIPS params with the default provider';
301        ok(run(app(['openssl', 'genpkey', '-genparam',
302                    '-algorithm', 'DSA',
303                    '-pkeyopt', 'type:fips186_2',
304                    '-pkeyopt', 'dsa_paramgen_bits:512',
305                    '-out', $nonfips_param])),
306           $testtext);
307
308        $ENV{OPENSSL_CONF} = $fipsconf;
309
310        $testtext = $testtext_prefix.': '.
311            'Generate FIPS params';
312        ok(run(app(['openssl', 'genpkey', '-genparam',
313                    '-algorithm', 'DSA',
314                    '-pkeyopt', 'dsa_paramgen_bits:2048',
315                    '-out', $fips_param])),
316           $testtext);
317
318        $testtext = $testtext_prefix.': '.
319            'Generate non-FIPS params'.
320            ' (should fail)';
321        ok(!run(app(['openssl', 'genpkey', '-genparam',
322                     '-algorithm', 'DSA',
323                    '-pkeyopt', 'dsa_paramgen_bits:512',
324                     '-out', $testtext_prefix.'.fail.param.pem'])),
325           $testtext);
326
327        $testtext = $testtext_prefix.': '.
328            'Generate non-FIPS params using non-FIPS property query'.
329            ' (dsaparam)';
330        ok(run(app(['openssl', 'dsaparam', '-provider', 'default',
331                    '-propquery', '?fips!=yes',
332                    '-out', $shortnonfips_param, '1024'])),
333            $testtext);
334
335        $testtext = $testtext_prefix.': '.
336            'Generate non-FIPS params using non-FIPS property query'.
337            ' (genpkey)';
338        ok(run(app(['openssl', 'genpkey', '-provider', 'default',
339                    '-propquery', '?fips!=yes',
340                    '-genparam', '-algorithm', 'DSA',
341                    '-pkeyopt', 'dsa_paramgen_bits:512'])),
342            $testtext);
343
344        $ENV{OPENSSL_CONF} = $defaultconf;
345
346        $testtext = $testtext_prefix.': '.
347            'Generate a key with non-FIPS params with the default provider';
348        ok(run(app(['openssl', 'genpkey',
349                    '-paramfile', $nonfips_param,
350                    '-pkeyopt', 'type:fips186_2',
351                    '-out', $nonfips_key])),
352           $testtext);
353
354        pubfrompriv($testtext_prefix, $nonfips_key, $nonfips_pub_key, "non-FIPS");
355
356        $ENV{OPENSSL_CONF} = $fipsconf;
357
358        $testtext = $testtext_prefix.': '.
359            'Generate a key with FIPS parameters';
360        ok(run(app(['openssl', 'genpkey',
361                    '-paramfile', $fips_param,
362                    '-pkeyopt', 'type:fips186_4',
363                    '-out', $fips_key])),
364           $testtext);
365
366        pubfrompriv($testtext_prefix, $fips_key, $fips_pub_key, "FIPS");
367
368        $testtext = $testtext_prefix.': '.
369            'Generate a key with non-FIPS parameters'.
370            ' (should fail)';
371        ok(!run(app(['openssl', 'genpkey',
372                     '-paramfile', $nonfips_param,
373                     '-pkeyopt', 'type:fips186_2',
374                     '-out', $testtext_prefix.'.fail.priv.pem'])),
375           $testtext);
376
377        $testtext = $testtext_prefix.': '.
378            'Generate a key with non-FIPS parameters using non-FIPS property'.
379            ' query (dsaparam)';
380        ok(run(app(['openssl', 'dsaparam', '-provider', 'default',
381                    '-propquery', '?fips!=yes',
382                    '-noout', '-genkey', '1024'])),
383            $testtext);
384
385        $testtext = $testtext_prefix.': '.
386            'Generate a key with non-FIPS parameters using non-FIPS property'.
387            ' query (gendsa)';
388        ok(run(app(['openssl', 'gendsa', '-provider', 'default',
389                    '-propquery', '?fips!=yes',
390                    $shortnonfips_param])),
391            $testtext);
392
393        $testtext = $testtext_prefix.': '.
394            'Generate a key with non-FIPS parameters using non-FIPS property'.
395            ' query (genpkey)';
396        ok(run(app(['openssl', 'genpkey', '-provider', 'default',
397                    '-propquery', '?fips!=yes',
398                    '-paramfile', $nonfips_param,
399                    '-pkeyopt', 'type:fips186_2',
400                    '-out', $testtext_prefix.'.fail.priv.pem'])),
401            $testtext);
402
403        tsignverify($testtext_prefix, $fips_key, $fips_pub_key, '', '');
404    };
405}
406