Home | History | Annotate | Line # | Download | only in recipes
      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