1 1.1 christos #! /usr/bin/env perl 2 1.1 christos # Copyright 2015-2024 The OpenSSL Project Authors. All Rights Reserved. 3 1.1 christos # 4 1.1 christos # Licensed under the Apache License 2.0 (the "License"). You may not use 5 1.1 christos # this file except in compliance with the License. You can obtain a copy 6 1.1 christos # in the file LICENSE in the source distribution or at 7 1.1 christos # https://www.openssl.org/source/license.html 8 1.1 christos 9 1.1 christos 10 1.1 christos use strict; 11 1.1 christos use warnings; 12 1.1 christos 13 1.1 christos use File::Compare qw/compare_text/; 14 1.1 christos use File::Copy; 15 1.1 christos use OpenSSL::Test qw/:DEFAULT/; 16 1.1 christos use Time::Piece; 17 1.1 christos use POSIX qw(strftime); 18 1.1 christos 19 1.1 christos my %conversionforms = ( 20 1.1 christos # Default conversion forms. Other series may be added with 21 1.1 christos # specific test types as key. 22 1.1 christos "*" => [ "d", "p" ], 23 1.1 christos "msb" => [ "d", "p", "msblob" ], 24 1.1 christos "pvk" => [ "d", "p", "pvk" ], 25 1.1 christos ); 26 1.1 christos sub tconversion { 27 1.1 christos my %opts = @_; 28 1.1 christos 29 1.1 christos die "Missing option -type" unless $opts{-type}; 30 1.1 christos die "Missing option -in" unless $opts{-in}; 31 1.1 christos my $testtype = $opts{-type}; 32 1.1 christos my $t = $opts{-in}; 33 1.1 christos my $prefix = $opts{-prefix} // $testtype; 34 1.1 christos my @conversionforms = 35 1.1 christos defined($conversionforms{$testtype}) ? 36 1.1 christos @{$conversionforms{$testtype}} : 37 1.1 christos @{$conversionforms{"*"}}; 38 1.1 christos my @openssl_args; 39 1.1 christos if (defined $opts{-args}) { 40 1.1 christos @openssl_args = @{$opts{-args}} if ref $opts{-args} eq 'ARRAY'; 41 1.1 christos @openssl_args = ($opts{-args}) if ref $opts{-args} eq ''; 42 1.1 christos } 43 1.1 christos @openssl_args = ($testtype) unless @openssl_args; 44 1.1 christos 45 1.1 christos my $n = scalar @conversionforms; 46 1.1 christos my $totaltests = 47 1.1 christos 1 # for initializing 48 1.1 christos + $n # initial conversions from p to all forms (A) 49 1.1 christos + $n*$n # conversion from result of A to all forms (B) 50 1.1 christos + 1 # comparing original test file to p form of A 51 1.1 christos + $n*($n-1); # comparing first conversion to each form in A with B 52 1.1 christos $totaltests-- if ($testtype eq "p7d"); # no comparison of original test file 53 1.1 christos $totaltests -= $n if ($testtype eq "pvk"); # no comparisons of the pvk form 54 1.1 christos plan tests => $totaltests; 55 1.1 christos 56 1.1 christos my @cmd = ("openssl", @openssl_args); 57 1.1 christos 58 1.1 christos my $init; 59 1.1 christos if (scalar @openssl_args > 0 && $openssl_args[0] eq "pkey") { 60 1.1 christos $init = ok(run(app([@cmd, "-in", $t, "-out", "$prefix-fff.p"])), 61 1.1 christos 'initializing'); 62 1.1 christos } else { 63 1.1 christos $init = ok(copy($t, "$prefix-fff.p"), 'initializing'); 64 1.1 christos } 65 1.1 christos if (!$init) { 66 1.1 christos diag("Trying to copy $t to $prefix-fff.p : $!"); 67 1.1 christos } 68 1.1 christos 69 1.1 christos SKIP: { 70 1.1 christos skip "Not initialized, skipping...", 22 unless $init; 71 1.1 christos 72 1.1 christos foreach my $to (@conversionforms) { 73 1.1 christos ok(run(app([@cmd, 74 1.1 christos "-in", "$prefix-fff.p", 75 1.1 christos "-inform", "p", 76 1.1 christos "-out", "$prefix-f.$to", 77 1.1 christos "-outform", $to])), 78 1.1 christos "p -> $to"); 79 1.1 christos } 80 1.1 christos 81 1.1 christos foreach my $to (@conversionforms) { 82 1.1 christos foreach my $from (@conversionforms) { 83 1.1 christos ok(run(app([@cmd, 84 1.1 christos "-in", "$prefix-f.$from", 85 1.1 christos "-inform", $from, 86 1.1 christos "-out", "$prefix-ff.$from$to", 87 1.1 christos "-outform", $to])), 88 1.1 christos "$from -> $to"); 89 1.1 christos } 90 1.1 christos } 91 1.1 christos 92 1.1 christos if ($testtype ne "p7d") { 93 1.1 christos is(cmp_text("$prefix-fff.p", "$prefix-f.p"), 0, 94 1.1 christos 'comparing orig to p'); 95 1.1 christos } 96 1.1 christos 97 1.1 christos foreach my $to (@conversionforms) { 98 1.1 christos next if $to eq "d" or $to eq "pvk"; 99 1.1 christos foreach my $from (@conversionforms) { 100 1.1 christos is(cmp_text("$prefix-f.$to", "$prefix-ff.$from$to"), 0, 101 1.1 christos "comparing $to to $from$to"); 102 1.1 christos } 103 1.1 christos } 104 1.1 christos } 105 1.1 christos } 106 1.1 christos 107 1.1 christos sub cmp_text { 108 1.1 christos return compare_text(@_, sub { 109 1.1 christos $_[0] =~ s/\R//g; 110 1.1 christos $_[1] =~ s/\R//g; 111 1.1 christos return $_[0] ne $_[1]; 112 1.1 christos }); 113 1.1 christos } 114 1.1 christos 115 1.1 christos sub file_contains { 116 1.1 christos my ($file, $pattern) = @_; 117 1.1 christos open(DATA, $file) or return 0; 118 1.1 christos $_= join('', <DATA>); 119 1.1 christos close(DATA); 120 1.1 christos s/\s+/ /g; # take multiple whitespace (including newline) as single space 121 1.1 christos return m/$pattern/ ? 1 : 0; 122 1.1 christos } 123 1.1 christos 124 1.1 christos sub test_file_contains { 125 1.1 christos my ($desc, $file, $pattern, $expected) = @_; 126 1.1 christos $expected //= 1; 127 1.1 christos return is(file_contains($file, $pattern), $expected, 128 1.1 christos "$desc should ".($expected ? "" : "not ")."contain '$pattern'"); 129 1.1 christos } 130 1.1 christos 131 1.1 christos sub cert_contains { 132 1.1 christos my ($cert, $pattern, $expected, $name) = @_; 133 1.1 christos my $out = "cert_contains.out"; 134 1.1 christos run(app(["openssl", "x509", "-noout", "-text", "-in", $cert, "-out", $out])); 135 1.1 christos return test_file_contains(($name ? "$name: " : "").$cert, $out, $pattern, $expected); 136 1.1 christos # not unlinking $out 137 1.1 christos } 138 1.1 christos 139 1.1 christos sub has_version { 140 1.1 christos my ($cert, $expect) = @_; 141 1.1 christos cert_contains($cert, "Version: $expect", 1); 142 1.1 christos } 143 1.1 christos 144 1.1 christos sub has_SKID { 145 1.1 christos my ($cert, $expect) = @_; 146 1.1 christos cert_contains($cert, "Subject Key Identifier", $expect); 147 1.1 christos } 148 1.1 christos 149 1.1 christos sub has_AKID { 150 1.1 christos my ($cert, $expect) = @_; 151 1.1 christos cert_contains($cert, "Authority Key Identifier", $expect); 152 1.1 christos } 153 1.1 christos 154 1.1 christos sub uniq (@) { 155 1.1 christos my %seen = (); 156 1.1 christos grep { not $seen{$_}++ } @_; 157 1.1 christos } 158 1.1 christos 159 1.1 christos sub file_n_different_lines { 160 1.1 christos my $filename = shift @_; 161 1.1 christos open(DATA, $filename) or return 0; 162 1.1 christos chomp(my @lines = <DATA>); 163 1.1 christos close(DATA); 164 1.1 christos return scalar(uniq @lines); 165 1.1 christos } 166 1.1 christos 167 1.1 christos sub cert_ext_has_n_different_lines { 168 1.1 christos my ($cert, $expected, $exts, $name) = @_; 169 1.1 christos my $out = "cert_n_different_exts.out"; 170 1.1 christos run(app(["openssl", "x509", "-noout", "-ext", $exts, 171 1.1 christos "-in", $cert, "-out", $out])); 172 1.1 christos is(file_n_different_lines($out), $expected, ($name ? "$name: " : ""). 173 1.1 christos "$cert '$exts' output should contain $expected different lines"); 174 1.1 christos # not unlinking $out 175 1.1 christos } 176 1.1 christos 177 1.1 christos # extracts string value of certificate field from a -text formatted-output 178 1.1 christos sub get_field { 179 1.1 christos my ($f, $field) = @_; 180 1.1 christos my $string = ""; 181 1.1 christos open my $fh, $f or die; 182 1.1 christos while (my $line = <$fh>) { 183 1.1 christos if ($line =~ /$field:\s+(.*)/) { 184 1.1 christos $string = $1; 185 1.1 christos } 186 1.1 christos } 187 1.1 christos close $fh; 188 1.1 christos return $string; 189 1.1 christos } 190 1.1 christos 191 1.1 christos sub get_issuer { 192 1.1 christos return get_field(@_, "Issuer"); 193 1.1 christos } 194 1.1 christos 195 1.1 christos sub get_not_before { 196 1.1 christos return get_field(@_, "Not Before"); 197 1.1 christos } 198 1.1 christos 199 1.1 christos # Date as yyyy-mm-dd 200 1.1 christos sub get_not_before_date { 201 1.1 christos return Time::Piece->strptime( 202 1.1 christos get_not_before(@_), 203 1.1 christos "%b %d %T %Y %Z")->date; 204 1.1 christos } 205 1.1 christos 206 1.1 christos sub get_not_after { 207 1.1 christos return get_field(@_, "Not After "); 208 1.1 christos } 209 1.1 christos 210 1.1 christos # Date as yyyy-mm-dd 211 1.1 christos sub get_not_after_date { 212 1.1 christos return Time::Piece->strptime( 213 1.1 christos get_not_after(@_), 214 1.1 christos "%b %d %T %Y %Z")->date; 215 1.1 christos } 216 1.1 christos 217 1.1 christos 1; 218