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