1#! /usr/bin/env perl
2# Copyright 2008-2016 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# Perl script to run tests against S/MIME examples in RFC4134
10# Assumes RFC is in current directory and called "rfc4134.txt"
11
12use MIME::Base64;
13
14my $badttest = 0;
15my $verbose  = 1;
16
17my $cmscmd;
18my $exdir  = "./";
19my $exfile = "./rfc4134.txt";
20
21if (-f "../apps/openssl")
22	{
23	$cmscmd = "../util/shlib_wrap.sh ../apps/openssl cms";
24	}
25elsif (-f "..\\out32dll\\openssl.exe")
26	{
27	$cmscmd = "..\\out32dll\\openssl.exe cms";
28	}
29elsif (-f "..\\out32\\openssl.exe")
30	{
31	$cmscmd = "..\\out32\\openssl.exe cms";
32	}
33
34my @test_list = (
35    [ "3.1.bin"  => "dataout" ],
36    [ "3.2.bin"  => "encode, dataout" ],
37    [ "4.1.bin"  => "encode, verifyder, cont, dss" ],
38    [ "4.2.bin"  => "encode, verifyder, cont, rsa" ],
39    [ "4.3.bin"  => "encode, verifyder, cont_extern, dss" ],
40    [ "4.4.bin"  => "encode, verifyder, cont, dss" ],
41    [ "4.5.bin"  => "verifyder, cont, rsa" ],
42    [ "4.6.bin"  => "encode, verifyder, cont, dss" ],
43    [ "4.7.bin"  => "encode, verifyder, cont, dss" ],
44    [ "4.8.eml"  => "verifymime, dss" ],
45    [ "4.9.eml"  => "verifymime, dss" ],
46    [ "4.10.bin" => "encode, verifyder, cont, dss" ],
47    [ "4.11.bin" => "encode, certsout" ],
48    [ "5.1.bin"  => "encode, envelopeder, cont" ],
49    [ "5.2.bin"  => "encode, envelopeder, cont" ],
50    [ "5.3.eml"  => "envelopemime, cont" ],
51    [ "6.0.bin"  => "encode, digest, cont" ],
52    [ "7.1.bin"  => "encode, encrypted, cont" ],
53    [ "7.2.bin"  => "encode, encrypted, cont" ]
54);
55
56# Extract examples from RFC4134 text.
57# Base64 decode all examples, certificates and
58# private keys are converted to PEM format.
59
60my ( $filename, $data );
61
62my @cleanup = ( "cms.out", "cms.err", "tmp.der", "tmp.txt" );
63
64$data = "";
65
66open( IN, $exfile ) || die "Can't Open RFC examples file $exfile";
67
68while (<IN>) {
69    next unless (/^\|/);
70    s/^\|//;
71    next if (/^\*/);
72    if (/^>(.*)$/) {
73        $filename = $1;
74        next;
75    }
76    if (/^</) {
77        $filename = "$exdir/$filename";
78        if ( $filename =~ /\.bin$/ || $filename =~ /\.eml$/ ) {
79            $data = decode_base64($data);
80            open OUT, ">$filename";
81            binmode OUT;
82            print OUT $data;
83            close OUT;
84            push @cleanup, $filename;
85        }
86        elsif ( $filename =~ /\.cer$/ ) {
87            write_pem( $filename, "CERTIFICATE", $data );
88        }
89        elsif ( $filename =~ /\.pri$/ ) {
90            write_pem( $filename, "PRIVATE KEY", $data );
91        }
92        $data     = "";
93        $filename = "";
94    }
95    else {
96        $data .= $_;
97    }
98
99}
100
101my $secretkey =
102  "73:7c:79:1f:25:ea:d0:e0:46:29:25:43:52:f7:dc:62:91:e5:cb:26:91:7a:da:32";
103
104foreach (@test_list) {
105    my ( $file, $tlist ) = @$_;
106    print "Example file $file:\n";
107    if ( $tlist =~ /encode/ ) {
108        run_reencode_test( $exdir, $file );
109    }
110    if ( $tlist =~ /certsout/ ) {
111        run_certsout_test( $exdir, $file );
112    }
113    if ( $tlist =~ /dataout/ ) {
114        run_dataout_test( $exdir, $file );
115    }
116    if ( $tlist =~ /verify/ ) {
117        run_verify_test( $exdir, $tlist, $file );
118    }
119    if ( $tlist =~ /digest/ ) {
120        run_digest_test( $exdir, $tlist, $file );
121    }
122    if ( $tlist =~ /encrypted/ ) {
123        run_encrypted_test( $exdir, $tlist, $file, $secretkey );
124    }
125    if ( $tlist =~ /envelope/ ) {
126        run_envelope_test( $exdir, $tlist, $file );
127    }
128
129}
130
131foreach (@cleanup) {
132    unlink $_;
133}
134
135if ($badtest) {
136    print "\n$badtest TESTS FAILED!!\n";
137}
138else {
139    print "\n***All tests successful***\n";
140}
141
142sub write_pem {
143    my ( $filename, $str, $data ) = @_;
144
145    $filename =~ s/\.[^.]*$/.pem/;
146
147    push @cleanup, $filename;
148
149    open OUT, ">$filename";
150
151    print OUT "-----BEGIN $str-----\n";
152    print OUT $data;
153    print OUT "-----END $str-----\n";
154
155    close OUT;
156}
157
158sub run_reencode_test {
159    my ( $cmsdir, $tfile ) = @_;
160    unlink "tmp.der";
161
162    system( "$cmscmd -cmsout -inform DER -outform DER"
163          . " -in $cmsdir/$tfile -out tmp.der" );
164
165    if ($?) {
166        print "\tReencode command FAILED!!\n";
167        $badtest++;
168    }
169    elsif ( !cmp_files( "$cmsdir/$tfile", "tmp.der" ) ) {
170        print "\tReencode FAILED!!\n";
171        $badtest++;
172    }
173    else {
174        print "\tReencode passed\n" if $verbose;
175    }
176}
177
178sub run_certsout_test {
179    my ( $cmsdir, $tfile ) = @_;
180    unlink "tmp.der";
181    unlink "tmp.pem";
182
183    system( "$cmscmd -cmsout -inform DER -certsout tmp.pem"
184          . " -in $cmsdir/$tfile -out tmp.der" );
185
186    if ($?) {
187        print "\tCertificate output command FAILED!!\n";
188        $badtest++;
189    }
190    else {
191        print "\tCertificate output passed\n" if $verbose;
192    }
193}
194
195sub run_dataout_test {
196    my ( $cmsdir, $tfile ) = @_;
197    unlink "tmp.txt";
198
199    system(
200        "$cmscmd -data_out -inform DER" . " -in $cmsdir/$tfile -out tmp.txt" );
201
202    if ($?) {
203        print "\tDataout command FAILED!!\n";
204        $badtest++;
205    }
206    elsif ( !cmp_files( "$cmsdir/ExContent.bin", "tmp.txt" ) ) {
207        print "\tDataout compare FAILED!!\n";
208        $badtest++;
209    }
210    else {
211        print "\tDataout passed\n" if $verbose;
212    }
213}
214
215sub run_verify_test {
216    my ( $cmsdir, $tlist, $tfile ) = @_;
217    unlink "tmp.txt";
218
219    $form   = "DER"                     if $tlist =~ /verifyder/;
220    $form   = "SMIME"                   if $tlist =~ /verifymime/;
221    $cafile = "$cmsdir/CarlDSSSelf.pem" if $tlist =~ /dss/;
222    $cafile = "$cmsdir/CarlRSASelf.pem" if $tlist =~ /rsa/;
223
224    $cmd =
225        "$cmscmd -verify -inform $form"
226      . " -CAfile $cafile"
227      . " -in $cmsdir/$tfile -out tmp.txt";
228
229    $cmd .= " -content $cmsdir/ExContent.bin" if $tlist =~ /cont_extern/;
230
231    system("$cmd 2>cms.err 1>cms.out");
232
233    if ($?) {
234        print "\tVerify command FAILED!!\n";
235        $badtest++;
236    }
237    elsif ( $tlist =~ /cont/
238        && !cmp_files( "$cmsdir/ExContent.bin", "tmp.txt" ) )
239    {
240        print "\tVerify content compare FAILED!!\n";
241        $badtest++;
242    }
243    else {
244        print "\tVerify passed\n" if $verbose;
245    }
246}
247
248sub run_envelope_test {
249    my ( $cmsdir, $tlist, $tfile ) = @_;
250    unlink "tmp.txt";
251
252    $form = "DER"   if $tlist =~ /envelopeder/;
253    $form = "SMIME" if $tlist =~ /envelopemime/;
254
255    $cmd =
256        "$cmscmd -decrypt -inform $form"
257      . " -recip $cmsdir/BobRSASignByCarl.pem"
258      . " -inkey $cmsdir/BobPrivRSAEncrypt.pem"
259      . " -in $cmsdir/$tfile -out tmp.txt";
260
261    system("$cmd 2>cms.err 1>cms.out");
262
263    if ($?) {
264        print "\tDecrypt command FAILED!!\n";
265        $badtest++;
266    }
267    elsif ( $tlist =~ /cont/
268        && !cmp_files( "$cmsdir/ExContent.bin", "tmp.txt" ) )
269    {
270        print "\tDecrypt content compare FAILED!!\n";
271        $badtest++;
272    }
273    else {
274        print "\tDecrypt passed\n" if $verbose;
275    }
276}
277
278sub run_digest_test {
279    my ( $cmsdir, $tlist, $tfile ) = @_;
280    unlink "tmp.txt";
281
282    my $cmd =
283      "$cmscmd -digest_verify -inform DER" . " -in $cmsdir/$tfile -out tmp.txt";
284
285    system("$cmd 2>cms.err 1>cms.out");
286
287    if ($?) {
288        print "\tDigest verify command FAILED!!\n";
289        $badtest++;
290    }
291    elsif ( $tlist =~ /cont/
292        && !cmp_files( "$cmsdir/ExContent.bin", "tmp.txt" ) )
293    {
294        print "\tDigest verify content compare FAILED!!\n";
295        $badtest++;
296    }
297    else {
298        print "\tDigest verify passed\n" if $verbose;
299    }
300}
301
302sub run_encrypted_test {
303    my ( $cmsdir, $tlist, $tfile, $key ) = @_;
304    unlink "tmp.txt";
305
306    system( "$cmscmd -EncryptedData_decrypt -inform DER"
307          . " -secretkey $key"
308          . " -in $cmsdir/$tfile -out tmp.txt" );
309
310    if ($?) {
311        print "\tEncrypted Data command FAILED!!\n";
312        $badtest++;
313    }
314    elsif ( $tlist =~ /cont/
315        && !cmp_files( "$cmsdir/ExContent.bin", "tmp.txt" ) )
316    {
317        print "\tEncrypted Data content compare FAILED!!\n";
318        $badtest++;
319    }
320    else {
321        print "\tEncryptedData verify passed\n" if $verbose;
322    }
323}
324
325sub cmp_files {
326    my ( $f1, $f2 ) = @_;
327    my ( $fp1, $fp2 );
328
329    my ( $rd1, $rd2 );
330
331    if ( !open( $fp1, "<$f1" ) ) {
332        print STDERR "Can't Open file $f1\n";
333        return 0;
334    }
335
336    if ( !open( $fp2, "<$f2" ) ) {
337        print STDERR "Can't Open file $f2\n";
338        return 0;
339    }
340
341    binmode $fp1;
342    binmode $fp2;
343
344    my $ret = 0;
345
346    for ( ; ; ) {
347        $n1 = sysread $fp1, $rd1, 4096;
348        $n2 = sysread $fp2, $rd2, 4096;
349        last if ( $n1 != $n2 );
350        last if ( $rd1 ne $rd2 );
351
352        if ( $n1 == 0 ) {
353            $ret = 1;
354            last;
355        }
356
357    }
358
359    close $fp1;
360    close $fp2;
361
362    return $ret;
363
364}
365
366