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