xref: /openssl/test/recipes/20-test_dhparam.t (revision 9ae1e659)
1#! /usr/bin/env perl
2# Copyright 2020-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
10use strict;
11use warnings;
12
13use File::Copy;
14use File::Compare qw/compare/;
15use OpenSSL::Test qw(:DEFAULT data_file srctop_file);
16use OpenSSL::Test::Utils;
17
18#Tests for the dhparam CLI application
19
20setup("test_dhparam");
21
22plan skip_all => "DH is not supported in this build"
23    if disabled("dh");
24plan tests => 23;
25
26my $fipsconf = srctop_file("test", "fips-and-base.cnf");
27
28sub checkdhparams {
29    my $file = shift; #Filename containing params
30    my $type = shift; #PKCS3 or X9.42?
31    my $gen = shift; #2, 5 or something else (0 is "something else")?
32    my $format = shift; #DER or PEM?
33    my $bits = shift; #Number of bits in p
34    my $keybits = shift; #Recommended private key bits
35    my $pemtype;
36    my $readtype;
37    my $readbits = 0;
38    my $genline;
39
40    if (-T $file) {
41        #Text file. Check it looks like PEM
42        open(PEMFILE, '<', $file) or die $!;
43        if (my $firstline = <PEMFILE>) {
44            $firstline =~ s/\R$//;
45            if ($firstline eq "-----BEGIN DH PARAMETERS-----") {
46                $pemtype = "PKCS3";
47            } elsif ($firstline eq "-----BEGIN X9.42 DH PARAMETERS-----") {
48                $pemtype = "X9.42";
49            } else {
50                $pemtype = "";
51            }
52        } else {
53            $pemtype = "";
54        }
55        close(PEMFILE);
56        ok(($format eq "PEM") && defined $pemtype, "Checking format is PEM");
57    } else {
58        ok($format eq "DER", "Checking format is DER");
59        #No PEM type in this case, so we just set the pemtype to the expected
60        #type so that we never fail that part of the test
61        $pemtype = $type;
62    }
63    my @textdata = run(app(['openssl', 'dhparam', '-in', $file, '-noout',
64                            '-text', '-inform', $format]), capture => 1);
65    chomp(@textdata);
66    #Trim trailing whitespace
67    @textdata = grep { s/\s*$//g } @textdata;
68    if (grep { $_ =~ 'Q:' } @textdata) {
69        $readtype = "X9.42";
70    } else {
71        $readtype = "PKCS3";
72    }
73    ok(($type eq $pemtype) && ($type eq $readtype),
74       "Checking parameter type is ".$type." ($pemtype, $readtype)");
75
76    if (defined $textdata[0] && $textdata[0] =~ /DH Parameters: \((\d+) bit\)/) {
77        $readbits = $1;
78    }
79    ok($bits == $readbits, "Checking number of bits is $bits");
80    if ($gen == 2 || $gen == 5) {
81        #For generators 2 and 5 the value appears on the same line
82        $genline = "G:    $gen (0x$gen)";
83    } else {
84        #For any other generator the value appears on the following line
85        $genline = "G:";
86    }
87
88    ok((grep { (index($_, $genline) + length ($genline)) == length ($_)} @textdata),
89       "Checking generator is correct");
90
91    if ($keybits) {
92        my $keybits_line = "recommended-private-length: $keybits bits";
93        ok((grep { (index($_, $keybits_line) + length($keybits_line))
94                   == length($_) } @textdata),
95           "Checking recommended private key bits is correct");
96    }
97}
98
99#Test some "known good" parameter files to check that we can read them
100subtest "Read: 1024 bit PKCS3 params, generator 2, PEM file" => sub {
101    plan tests => 4;
102    checkdhparams(data_file("pkcs3-2-1024.pem"), "PKCS3", 2, "PEM", 1024);
103};
104subtest "Read: 1024 bit PKCS3 params, generator 5, PEM file" => sub {
105    plan tests => 4;
106    checkdhparams(data_file("pkcs3-5-1024.pem"), "PKCS3", 5, "PEM", 1024);
107};
108subtest "Read: 2048 bit PKCS3 params, generator 2, PEM file" => sub {
109    plan tests => 4;
110    checkdhparams(data_file("pkcs3-2-2048.pem"), "PKCS3", 2, "PEM", 2048);
111};
112subtest "Read: 1024 bit X9.42 params, PEM file" => sub {
113    plan tests => 4;
114    checkdhparams(data_file("x942-0-1024.pem"), "X9.42", 0, "PEM", 1024);
115};
116subtest "Read: 1024 bit PKCS3 params, generator 2, DER file" => sub {
117    plan tests => 4;
118    checkdhparams(data_file("pkcs3-2-1024.der"), "PKCS3", 2, "DER", 1024);
119};
120subtest "Read: 1024 bit PKCS3 params, generator 5, DER file" => sub {
121    plan tests => 4;
122    checkdhparams(data_file("pkcs3-5-1024.der"), "PKCS3", 5, "DER", 1024);
123};
124subtest "Read: 2048 bit PKCS3 params, generator 2, DER file" => sub {
125    plan tests => 4;
126    checkdhparams(data_file("pkcs3-2-2048.der"), "PKCS3", 2, "DER", 2048);
127};
128subtest "Read: 1024 bit X9.42 params, DER file" => sub {
129    checkdhparams(data_file("x942-0-1024.der"), "X9.42", 0, "DER", 1024);
130};
131
132#Test that generating parameters of different types creates what we expect. We
133#use 512 for the size for speed reasons. Don't use this in real applications!
134subtest "Generate: 512 bit PKCS3 params, generator 2, PEM file" => sub {
135    plan tests => 6;
136    ok(run(app([ 'openssl', 'dhparam', '-out', 'gen-pkcs3-2-512.pem',
137                 '512' ])));
138    checkdhparams("gen-pkcs3-2-512.pem", "PKCS3", 2, "PEM", 512, 125);
139};
140subtest "Generate: 512 bit PKCS3 params, explicit generator 2, PEM file" => sub {
141    plan tests => 6;
142    ok(run(app([ 'openssl', 'dhparam', '-out', 'gen-pkcs3-exp2-512.pem', '-2',
143                 '512' ])));
144    checkdhparams("gen-pkcs3-exp2-512.pem", "PKCS3", 2, "PEM", 512, 125);
145};
146subtest "Generate: 512 bit PKCS3 params, generator 5, PEM file" => sub {
147    plan tests => 6;
148    ok(run(app([ 'openssl', 'dhparam', '-out', 'gen-pkcs3-5-512.pem', '-5',
149                 '512' ])));
150    checkdhparams("gen-pkcs3-5-512.pem", "PKCS3", 5, "PEM", 512, 125);
151};
152subtest "Generate: 512 bit PKCS3 params, generator 2, explicit PEM file" => sub {
153    plan tests => 6;
154    ok(run(app([ 'openssl', 'dhparam', '-out', 'gen-pkcs3-2-512.exp.pem',
155                 '-outform', 'PEM', '512' ])));
156    checkdhparams("gen-pkcs3-2-512.exp.pem", "PKCS3", 2, "PEM", 512, 125);
157};
158SKIP: {
159    skip "Skipping tests that require DSA", 4 if disabled("dsa");
160
161    subtest "Generate: 512 bit X9.42 params, generator 0, PEM file" => sub {
162        plan tests => 5;
163        ok(run(app([ 'openssl', 'dhparam', '-out', 'gen-x942-0-512.pem',
164                    '-dsaparam', '512' ])));
165        checkdhparams("gen-x942-0-512.pem", "X9.42", 0, "PEM", 512);
166    };
167    subtest "Generate: 512 bit X9.42 params, explicit generator 2, PEM file" => sub {
168        plan tests => 1;
169        #Expected to fail - you cannot select a generator with '-dsaparam'
170        ok(!run(app([ 'openssl', 'dhparam', '-out', 'gen-x942-exp2-512.pem', '-2',
171                    '-dsaparam', '512' ])));
172    };
173    subtest "Generate: 512 bit X9.42 params, generator 5, PEM file" => sub {
174        plan tests => 1;
175        #Expected to fail - you cannot select a generator with '-dsaparam'
176        ok(!run(app([ 'openssl', 'dhparam', '-out', 'gen-x942-5-512.pem',
177                    '-5', '-dsaparam', '512' ])));
178    };
179    subtest "Generate: 512 bit X9.42 params, generator 0, DER file" => sub {
180        plan tests => 5;
181        ok(run(app([ 'openssl', 'dhparam', '-out', 'gen-x942-0-512.der',
182                    '-dsaparam', '-outform', 'DER', '512' ])));
183        checkdhparams("gen-x942-0-512.der", "X9.42", 0, "DER", 512);
184    };
185}
186SKIP: {
187    skip "Skipping tests that are only supported in a fips build with security ".
188        "checks", 4 if (disabled("fips") || disabled("fips-securitychecks"));
189
190    $ENV{OPENSSL_CONF} = $fipsconf;
191
192    ok(!run(app(['openssl', 'dhparam', '-check', '512'])),
193        "Generating 512 bit DH params should fail in FIPS mode");
194
195    ok(run(app(['openssl', 'dhparam', '-provider', 'default', '-propquery',
196            '?fips!=yes', '-check', '512'])),
197        "Generating 512 bit DH params should succeed in FIPS mode using".
198        " non-FIPS property query");
199
200    SKIP: {
201        skip "Skipping tests that require DSA", 2 if disabled("dsa");
202
203        ok(!run(app(['openssl', 'dhparam', '-dsaparam', '-check', '512'])),
204            "Generating 512 bit DSA-style DH params should fail in FIPS mode");
205
206        ok(run(app(['openssl', 'dhparam', '-provider', 'default', '-propquery',
207                '?fips!=yes', '-dsaparam', '-check', '512'])),
208            "Generating 512 bit DSA-style DH params should succeed in FIPS".
209            " mode using non-FIPS property query");
210    }
211
212    delete $ENV{OPENSSL_CONF};
213}
214
215my $input = data_file("pkcs3-2-1024.pem");
216ok(run(app(["openssl", "dhparam", "-noout", "-text"],
217           stdin => $input)),
218   "stdinbuffer input test that uses BIO_gets");
219
220my $inout = "inout.pem";
221copy($input, $inout);
222ok(run(app(['openssl', 'dhparam', '-in', $inout, '-out', $inout])),
223    "identical infile and outfile");
224ok(!compare($input, $inout), "converted file $inout did not change");
225