1#! /usr/bin/env perl
2# Copyright 2021-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 OpenSSL::Test;
13use OpenSSL::Test::Utils;
14
15setup("test_gendhparam");
16
17my @testdata = (
18    {
19        algorithm => 'DHX',
20        pkeyopts => [ "type:fips186_4", 'digest:SHA256', 'gindex:1' ],
21        expect => [ 'BEGIN X9.42 DH PARAMETERS', 'gindex:', 'pcounter:', 'SEED:' ],
22        message   => 'DH fips186_4 param gen with verifiable g',
23    },
24    {
25        algorithm => 'DH',
26        pkeyopts => [ "type:fips186_4", 'digest:SHA256', 'gindex:1' ],
27        expect => [ 'ERROR' ],
28        message   => 'fips186_4 param gen should fail if DHX is not used',
29    },
30    {
31        algorithm => 'DHX',
32        pkeyopts => [ "type:fips186_4", 'digest:SHA512-224', 'gindex:1' ],
33        expect => [ 'BEGIN X9.42 DH PARAMETERS', 'gindex:', 'pcounter:', 'SEED:' ],
34        message   => 'DH fips186_4 param gen with verifiable g and truncated digest',
35    },
36    {
37        algorithm => 'DHX',
38        pkeyopts => [ 'type:fips186_2', 'pbits:1024', 'qbits:160' ],
39        expect => [ 'BEGIN X9.42 DH PARAMETERS', 'h:', 'pcounter:', 'SEED:' ],
40        message   => 'DHX fips186_2 param gen with a selected p and q size with unverifyable g',
41    },
42    {
43        algorithm => 'DHX',
44        pkeyopts => [ 'type:fips186_2', 'dh_paramgen_prime_len:1024', 'dh_paramgen_subprime_len:160' ],
45        message   => 'DHX fips186_2 param gen with a selected p and q size using aliased',
46        expect => [ "BEGIN X9.42 DH PARAMETERS" ],
47    },
48    {
49        algorithm => 'DH',
50        pkeyopts => [ 'type:fips186_2', 'dh_paramgen_prime_len:1024', 'dh_paramgen_subprime_len:160' ],
51        message   => 'DH fips186_2 param gen with a selected p and q size using aliases should fail',
52        expect => [ "ERROR" ],
53    },
54    {
55        algorithm => 'DH',
56        pkeyopts => [ 'group:ffdhe2048'],
57        expect => [ 'BEGIN DH PARAMETERS', 'GROUP:' ],
58        message   => 'DH named group ffdhe selection',
59    },
60    {
61        algorithm => 'DH',
62        pkeyopts => [ 'dh_param:ffdhe8192'],
63        expect => [ 'BEGIN DH PARAMETERS', 'GROUP:' ],
64        message   => 'DH named group ffdhe selection using alias',
65    },
66    {
67        algorithm => 'DH',
68        pkeyopts => [ 'group:modp_3072'],
69        expect => [ 'BEGIN DH PARAMETERS', 'GROUP:' ],
70        message   => 'DH named group modp selection',
71    },
72    {
73        algorithm => 'DH',
74        pkeyopts => [ 'dh_param:modp_4096'],
75        message   => 'DH named group modp selection using alias',
76        expect => [ 'BEGIN DH PARAMETERS', 'GROUP:'],
77    },
78    {
79        algorithm => 'DHX',
80        pkeyopts => [ 'group:dh_2048_256' ],
81        expect => [ 'BEGIN X9.42 DH PARAMETERS', 'GROUP:' ],
82        message   => 'DHX RFC5114 named group selection',
83    },
84    {
85        algorithm => 'DHX',
86        pkeyopts => [ 'dh_param:dh_2048_224' ],
87        expect => [ 'BEGIN X9.42 DH PARAMETERS', 'GROUP:' ],
88        message   => 'DHX RFC5114 named group selection using alias',
89    },
90    {
91        algorithm => 'DHX',
92        pkeyopts => [ 'dh_rfc5114:2'],
93        expect => [ 'BEGIN X9.42 DH PARAMETERS', 'GROUP:' ],
94        message   => 'DHX RFC5114 named group selection using an id',
95    },
96    {
97        algorithm => 'DHX',
98        pkeyopts => [ 'dh_rfc5114:1', 'dh_paramgen_type:1' ],
99        expect => [ 'BEGIN X9.42 DH PARAMETERS', 'GROUP:' ],
100        message   => 'DHX paramgen_type is ignored if the group is set',
101    },
102    {
103        algorithm => 'DH',
104        pkeyopts => [ 'dh_rfc5114:1', 'dh_paramgen_type:1' ],
105        expect => [ 'ERROR' ],
106        message   => "Setting dh_paramgen_type to fips186 should fail for DH keys",
107    },
108# These tests using the safeprime generator were removed as they are slow..
109#    {
110#        algorithm => 'DH',
111#        pkeyopts => [ 'type:generator', 'safeprime-generator:5'],
112#        expect => [ 'BEGIN DH PARAMETERS', 'G:    5' ],
113#        message   => 'DH safe prime generator',
114#    },
115#    {
116#        algorithm => 'DH',
117#        pkeyopts => [ 'dh_paramgen_type:0', 'dh_paramgen_generator:5'],
118#        expect => [ 'BEGIN DH PARAMETERS', 'G:    5' ],
119#        message   => 'DH safe prime generator using an alias',
120#    },
121    {
122        algorithm => 'DHX',
123        pkeyopts => [ 'type:generator', 'safeprime-generator:5'],
124        expect => [ 'ERROR' ],
125        message   => 'safe prime generator should fail for DHX',
126    }
127);
128
129plan skip_all => "DH isn't supported in this build" if disabled("dh");
130
131plan tests => scalar @testdata;
132
133foreach my $test (@testdata) {
134    my $alg = $test->{algorithm};
135    my $msg = $test->{message};
136    my @testargs = @{ $test->{pkeyopts} };
137    my @expected = @{ $test->{expect} };
138    my @pkeyopts= ();
139    foreach (@testargs) {
140        push(@pkeyopts, '-pkeyopt');
141        push(@pkeyopts, $_);
142    }
143    my @lines;
144    if ($expected[0] eq 'ERROR') {
145        @lines = run(app(['openssl', 'genpkey', '-genparam',
146                          '-algorithm', $alg, '-text', @pkeyopts],
147                         stderr => undef),
148                     capture => 1);
149    } else {
150        @lines = run(app(['openssl', 'genpkey', '-genparam',
151                          '-algorithm', $alg, '-text', @pkeyopts]),
152                     capture => 1);
153    }
154    ok(compareline(\@lines, \@expected), $msg);
155}
156
157# Check that the stdout output matches the expected value.
158sub compareline {
159    my ($ref_lines, $ref_expected) = @_;
160    my @lines = @$ref_lines;
161    my @expected = @$ref_expected;
162
163    if (@lines == 0 and $expected[0] eq 'ERROR') {
164        return 1;
165    }
166    print "-----------------\n";
167    foreach (@lines) {
168        print "# ".$_;
169    }
170    print "-----------------\n";
171    foreach my $ex (@expected) {
172        if ( !grep { index($_, $ex) >= 0 }  @lines) {
173            print "ERROR: Cannot find: $ex\n";
174            return 0;
175        }
176    }
177    return 1;
178}
179