1183234Ssimon# test/cms-examples.pl
2183234Ssimon# Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3183234Ssimon# project.
4183234Ssimon#
5183234Ssimon# ====================================================================
6183234Ssimon# Copyright (c) 2008 The OpenSSL Project.  All rights reserved.
7183234Ssimon#
8183234Ssimon# Redistribution and use in source and binary forms, with or without
9183234Ssimon# modification, are permitted provided that the following conditions
10183234Ssimon# are met:
11183234Ssimon#
12183234Ssimon# 1. Redistributions of source code must retain the above copyright
13183234Ssimon#    notice, this list of conditions and the following disclaimer.
14183234Ssimon#
15183234Ssimon# 2. Redistributions in binary form must reproduce the above copyright
16183234Ssimon#    notice, this list of conditions and the following disclaimer in
17183234Ssimon#    the documentation and/or other materials provided with the
18183234Ssimon#    distribution.
19183234Ssimon#
20183234Ssimon# 3. All advertising materials mentioning features or use of this
21183234Ssimon#    software must display the following acknowledgment:
22183234Ssimon#    "This product includes software developed by the OpenSSL Project
23183234Ssimon#    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24183234Ssimon#
25183234Ssimon# 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26183234Ssimon#    endorse or promote products derived from this software without
27183234Ssimon#    prior written permission. For written permission, please contact
28183234Ssimon#    licensing@OpenSSL.org.
29183234Ssimon#
30183234Ssimon# 5. Products derived from this software may not be called "OpenSSL"
31183234Ssimon#    nor may "OpenSSL" appear in their names without prior written
32183234Ssimon#    permission of the OpenSSL Project.
33183234Ssimon#
34183234Ssimon# 6. Redistributions of any form whatsoever must retain the following
35183234Ssimon#    acknowledgment:
36183234Ssimon#    "This product includes software developed by the OpenSSL Project
37183234Ssimon#    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38183234Ssimon#
39183234Ssimon# THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40183234Ssimon# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41183234Ssimon# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42183234Ssimon# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43183234Ssimon# ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44183234Ssimon# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45183234Ssimon# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46183234Ssimon# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47183234Ssimon# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48183234Ssimon# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49183234Ssimon# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50183234Ssimon# OF THE POSSIBILITY OF SUCH DAMAGE.
51183234Ssimon# ====================================================================
52183234Ssimon
53183234Ssimon# Perl script to run tests against S/MIME examples in RFC4134
54183234Ssimon# Assumes RFC is in current directory and called "rfc4134.txt"
55183234Ssimon
56183234Ssimonuse MIME::Base64;
57183234Ssimon
58183234Ssimonmy $badttest = 0;
59183234Ssimonmy $verbose  = 1;
60183234Ssimon
61183234Ssimonmy $cmscmd;
62183234Ssimonmy $exdir  = "./";
63183234Ssimonmy $exfile = "./rfc4134.txt";
64183234Ssimon
65183234Ssimonif (-f "../apps/openssl")
66183234Ssimon	{
67183234Ssimon	$cmscmd = "../util/shlib_wrap.sh ../apps/openssl cms";
68183234Ssimon	}
69183234Ssimonelsif (-f "..\\out32dll\\openssl.exe")
70183234Ssimon	{
71183234Ssimon	$cmscmd = "..\\out32dll\\openssl.exe cms";
72183234Ssimon	}
73183234Ssimonelsif (-f "..\\out32\\openssl.exe")
74183234Ssimon	{
75183234Ssimon	$cmscmd = "..\\out32\\openssl.exe cms";
76183234Ssimon	}
77183234Ssimon
78183234Ssimonmy @test_list = (
79183234Ssimon    [ "3.1.bin"  => "dataout" ],
80183234Ssimon    [ "3.2.bin"  => "encode, dataout" ],
81183234Ssimon    [ "4.1.bin"  => "encode, verifyder, cont, dss" ],
82183234Ssimon    [ "4.2.bin"  => "encode, verifyder, cont, rsa" ],
83183234Ssimon    [ "4.3.bin"  => "encode, verifyder, cont_extern, dss" ],
84183234Ssimon    [ "4.4.bin"  => "encode, verifyder, cont, dss" ],
85183234Ssimon    [ "4.5.bin"  => "verifyder, cont, rsa" ],
86183234Ssimon    [ "4.6.bin"  => "encode, verifyder, cont, dss" ],
87183234Ssimon    [ "4.7.bin"  => "encode, verifyder, cont, dss" ],
88183234Ssimon    [ "4.8.eml"  => "verifymime, dss" ],
89183234Ssimon    [ "4.9.eml"  => "verifymime, dss" ],
90183234Ssimon    [ "4.10.bin" => "encode, verifyder, cont, dss" ],
91183234Ssimon    [ "4.11.bin" => "encode, certsout" ],
92183234Ssimon    [ "5.1.bin"  => "encode, envelopeder, cont" ],
93183234Ssimon    [ "5.2.bin"  => "encode, envelopeder, cont" ],
94183234Ssimon    [ "5.3.eml"  => "envelopemime, cont" ],
95183234Ssimon    [ "6.0.bin"  => "encode, digest, cont" ],
96183234Ssimon    [ "7.1.bin"  => "encode, encrypted, cont" ],
97183234Ssimon    [ "7.2.bin"  => "encode, encrypted, cont" ]
98183234Ssimon);
99183234Ssimon
100183234Ssimon# Extract examples from RFC4134 text.
101183234Ssimon# Base64 decode all examples, certificates and
102183234Ssimon# private keys are converted to PEM format.
103183234Ssimon
104183234Ssimonmy ( $filename, $data );
105183234Ssimon
106183234Ssimonmy @cleanup = ( "cms.out", "cms.err", "tmp.der", "tmp.txt" );
107183234Ssimon
108183234Ssimon$data = "";
109183234Ssimon
110183234Ssimonopen( IN, $exfile ) || die "Can't Open RFC examples file $exfile";
111183234Ssimon
112183234Ssimonwhile (<IN>) {
113183234Ssimon    next unless (/^\|/);
114183234Ssimon    s/^\|//;
115183234Ssimon    next if (/^\*/);
116183234Ssimon    if (/^>(.*)$/) {
117183234Ssimon        $filename = $1;
118183234Ssimon        next;
119183234Ssimon    }
120183234Ssimon    if (/^</) {
121183234Ssimon        $filename = "$exdir/$filename";
122183234Ssimon        if ( $filename =~ /\.bin$/ || $filename =~ /\.eml$/ ) {
123183234Ssimon            $data = decode_base64($data);
124183234Ssimon            open OUT, ">$filename";
125183234Ssimon            binmode OUT;
126183234Ssimon            print OUT $data;
127183234Ssimon            close OUT;
128183234Ssimon            push @cleanup, $filename;
129183234Ssimon        }
130183234Ssimon        elsif ( $filename =~ /\.cer$/ ) {
131183234Ssimon            write_pem( $filename, "CERTIFICATE", $data );
132183234Ssimon        }
133183234Ssimon        elsif ( $filename =~ /\.pri$/ ) {
134183234Ssimon            write_pem( $filename, "PRIVATE KEY", $data );
135183234Ssimon        }
136183234Ssimon        $data     = "";
137183234Ssimon        $filename = "";
138183234Ssimon    }
139183234Ssimon    else {
140183234Ssimon        $data .= $_;
141183234Ssimon    }
142183234Ssimon
143183234Ssimon}
144183234Ssimon
145183234Ssimonmy $secretkey =
146183234Ssimon  "73:7c:79:1f:25:ea:d0:e0:46:29:25:43:52:f7:dc:62:91:e5:cb:26:91:7a:da:32";
147183234Ssimon
148183234Ssimonforeach (@test_list) {
149183234Ssimon    my ( $file, $tlist ) = @$_;
150183234Ssimon    print "Example file $file:\n";
151183234Ssimon    if ( $tlist =~ /encode/ ) {
152183234Ssimon        run_reencode_test( $exdir, $file );
153183234Ssimon    }
154183234Ssimon    if ( $tlist =~ /certsout/ ) {
155183234Ssimon        run_certsout_test( $exdir, $file );
156183234Ssimon    }
157183234Ssimon    if ( $tlist =~ /dataout/ ) {
158183234Ssimon        run_dataout_test( $exdir, $file );
159183234Ssimon    }
160183234Ssimon    if ( $tlist =~ /verify/ ) {
161183234Ssimon        run_verify_test( $exdir, $tlist, $file );
162183234Ssimon    }
163183234Ssimon    if ( $tlist =~ /digest/ ) {
164183234Ssimon        run_digest_test( $exdir, $tlist, $file );
165183234Ssimon    }
166183234Ssimon    if ( $tlist =~ /encrypted/ ) {
167183234Ssimon        run_encrypted_test( $exdir, $tlist, $file, $secretkey );
168183234Ssimon    }
169183234Ssimon    if ( $tlist =~ /envelope/ ) {
170183234Ssimon        run_envelope_test( $exdir, $tlist, $file );
171183234Ssimon    }
172183234Ssimon
173183234Ssimon}
174183234Ssimon
175183234Ssimonforeach (@cleanup) {
176183234Ssimon    unlink $_;
177183234Ssimon}
178183234Ssimon
179183234Ssimonif ($badtest) {
180183234Ssimon    print "\n$badtest TESTS FAILED!!\n";
181183234Ssimon}
182183234Ssimonelse {
183183234Ssimon    print "\n***All tests successful***\n";
184183234Ssimon}
185183234Ssimon
186183234Ssimonsub write_pem {
187183234Ssimon    my ( $filename, $str, $data ) = @_;
188183234Ssimon
189183234Ssimon    $filename =~ s/\.[^.]*$/.pem/;
190183234Ssimon
191183234Ssimon    push @cleanup, $filename;
192183234Ssimon
193183234Ssimon    open OUT, ">$filename";
194183234Ssimon
195183234Ssimon    print OUT "-----BEGIN $str-----\n";
196183234Ssimon    print OUT $data;
197183234Ssimon    print OUT "-----END $str-----\n";
198183234Ssimon
199183234Ssimon    close OUT;
200183234Ssimon}
201183234Ssimon
202183234Ssimonsub run_reencode_test {
203183234Ssimon    my ( $cmsdir, $tfile ) = @_;
204183234Ssimon    unlink "tmp.der";
205183234Ssimon
206183234Ssimon    system( "$cmscmd -cmsout -inform DER -outform DER"
207183234Ssimon          . " -in $cmsdir/$tfile -out tmp.der" );
208183234Ssimon
209183234Ssimon    if ($?) {
210183234Ssimon        print "\tReencode command FAILED!!\n";
211183234Ssimon        $badtest++;
212183234Ssimon    }
213183234Ssimon    elsif ( !cmp_files( "$cmsdir/$tfile", "tmp.der" ) ) {
214183234Ssimon        print "\tReencode FAILED!!\n";
215183234Ssimon        $badtest++;
216183234Ssimon    }
217183234Ssimon    else {
218183234Ssimon        print "\tReencode passed\n" if $verbose;
219183234Ssimon    }
220183234Ssimon}
221183234Ssimon
222183234Ssimonsub run_certsout_test {
223183234Ssimon    my ( $cmsdir, $tfile ) = @_;
224183234Ssimon    unlink "tmp.der";
225183234Ssimon    unlink "tmp.pem";
226183234Ssimon
227183234Ssimon    system( "$cmscmd -cmsout -inform DER -certsout tmp.pem"
228183234Ssimon          . " -in $cmsdir/$tfile -out tmp.der" );
229183234Ssimon
230183234Ssimon    if ($?) {
231183234Ssimon        print "\tCertificate output command FAILED!!\n";
232183234Ssimon        $badtest++;
233183234Ssimon    }
234183234Ssimon    else {
235183234Ssimon        print "\tCertificate output passed\n" if $verbose;
236183234Ssimon    }
237183234Ssimon}
238183234Ssimon
239183234Ssimonsub run_dataout_test {
240183234Ssimon    my ( $cmsdir, $tfile ) = @_;
241183234Ssimon    unlink "tmp.txt";
242183234Ssimon
243183234Ssimon    system(
244183234Ssimon        "$cmscmd -data_out -inform DER" . " -in $cmsdir/$tfile -out tmp.txt" );
245183234Ssimon
246183234Ssimon    if ($?) {
247183234Ssimon        print "\tDataout command FAILED!!\n";
248183234Ssimon        $badtest++;
249183234Ssimon    }
250183234Ssimon    elsif ( !cmp_files( "$cmsdir/ExContent.bin", "tmp.txt" ) ) {
251183234Ssimon        print "\tDataout compare FAILED!!\n";
252183234Ssimon        $badtest++;
253183234Ssimon    }
254183234Ssimon    else {
255183234Ssimon        print "\tDataout passed\n" if $verbose;
256183234Ssimon    }
257183234Ssimon}
258183234Ssimon
259183234Ssimonsub run_verify_test {
260183234Ssimon    my ( $cmsdir, $tlist, $tfile ) = @_;
261183234Ssimon    unlink "tmp.txt";
262183234Ssimon
263183234Ssimon    $form   = "DER"                     if $tlist =~ /verifyder/;
264183234Ssimon    $form   = "SMIME"                   if $tlist =~ /verifymime/;
265183234Ssimon    $cafile = "$cmsdir/CarlDSSSelf.pem" if $tlist =~ /dss/;
266183234Ssimon    $cafile = "$cmsdir/CarlRSASelf.pem" if $tlist =~ /rsa/;
267183234Ssimon
268183234Ssimon    $cmd =
269183234Ssimon        "$cmscmd -verify -inform $form"
270183234Ssimon      . " -CAfile $cafile"
271183234Ssimon      . " -in $cmsdir/$tfile -out tmp.txt";
272183234Ssimon
273183234Ssimon    $cmd .= " -content $cmsdir/ExContent.bin" if $tlist =~ /cont_extern/;
274183234Ssimon
275183234Ssimon    system("$cmd 2>cms.err 1>cms.out");
276183234Ssimon
277183234Ssimon    if ($?) {
278183234Ssimon        print "\tVerify command FAILED!!\n";
279183234Ssimon        $badtest++;
280183234Ssimon    }
281183234Ssimon    elsif ( $tlist =~ /cont/
282183234Ssimon        && !cmp_files( "$cmsdir/ExContent.bin", "tmp.txt" ) )
283183234Ssimon    {
284183234Ssimon        print "\tVerify content compare FAILED!!\n";
285183234Ssimon        $badtest++;
286183234Ssimon    }
287183234Ssimon    else {
288183234Ssimon        print "\tVerify passed\n" if $verbose;
289183234Ssimon    }
290183234Ssimon}
291183234Ssimon
292183234Ssimonsub run_envelope_test {
293183234Ssimon    my ( $cmsdir, $tlist, $tfile ) = @_;
294183234Ssimon    unlink "tmp.txt";
295183234Ssimon
296183234Ssimon    $form = "DER"   if $tlist =~ /envelopeder/;
297183234Ssimon    $form = "SMIME" if $tlist =~ /envelopemime/;
298183234Ssimon
299183234Ssimon    $cmd =
300183234Ssimon        "$cmscmd -decrypt -inform $form"
301183234Ssimon      . " -recip $cmsdir/BobRSASignByCarl.pem"
302183234Ssimon      . " -inkey $cmsdir/BobPrivRSAEncrypt.pem"
303183234Ssimon      . " -in $cmsdir/$tfile -out tmp.txt";
304183234Ssimon
305183234Ssimon    system("$cmd 2>cms.err 1>cms.out");
306183234Ssimon
307183234Ssimon    if ($?) {
308183234Ssimon        print "\tDecrypt command FAILED!!\n";
309183234Ssimon        $badtest++;
310183234Ssimon    }
311183234Ssimon    elsif ( $tlist =~ /cont/
312183234Ssimon        && !cmp_files( "$cmsdir/ExContent.bin", "tmp.txt" ) )
313183234Ssimon    {
314183234Ssimon        print "\tDecrypt content compare FAILED!!\n";
315183234Ssimon        $badtest++;
316183234Ssimon    }
317183234Ssimon    else {
318183234Ssimon        print "\tDecrypt passed\n" if $verbose;
319183234Ssimon    }
320183234Ssimon}
321183234Ssimon
322183234Ssimonsub run_digest_test {
323183234Ssimon    my ( $cmsdir, $tlist, $tfile ) = @_;
324183234Ssimon    unlink "tmp.txt";
325183234Ssimon
326183234Ssimon    my $cmd =
327183234Ssimon      "$cmscmd -digest_verify -inform DER" . " -in $cmsdir/$tfile -out tmp.txt";
328183234Ssimon
329183234Ssimon    system("$cmd 2>cms.err 1>cms.out");
330183234Ssimon
331183234Ssimon    if ($?) {
332183234Ssimon        print "\tDigest verify command FAILED!!\n";
333183234Ssimon        $badtest++;
334183234Ssimon    }
335183234Ssimon    elsif ( $tlist =~ /cont/
336183234Ssimon        && !cmp_files( "$cmsdir/ExContent.bin", "tmp.txt" ) )
337183234Ssimon    {
338183234Ssimon        print "\tDigest verify content compare FAILED!!\n";
339183234Ssimon        $badtest++;
340183234Ssimon    }
341183234Ssimon    else {
342183234Ssimon        print "\tDigest verify passed\n" if $verbose;
343183234Ssimon    }
344183234Ssimon}
345183234Ssimon
346183234Ssimonsub run_encrypted_test {
347183234Ssimon    my ( $cmsdir, $tlist, $tfile, $key ) = @_;
348183234Ssimon    unlink "tmp.txt";
349183234Ssimon
350183234Ssimon    system( "$cmscmd -EncryptedData_decrypt -inform DER"
351183234Ssimon          . " -secretkey $key"
352183234Ssimon          . " -in $cmsdir/$tfile -out tmp.txt" );
353183234Ssimon
354183234Ssimon    if ($?) {
355183234Ssimon        print "\tEncrypted Data command FAILED!!\n";
356183234Ssimon        $badtest++;
357183234Ssimon    }
358183234Ssimon    elsif ( $tlist =~ /cont/
359183234Ssimon        && !cmp_files( "$cmsdir/ExContent.bin", "tmp.txt" ) )
360183234Ssimon    {
361183234Ssimon        print "\tEncrypted Data content compare FAILED!!\n";
362183234Ssimon        $badtest++;
363183234Ssimon    }
364183234Ssimon    else {
365183234Ssimon        print "\tEncryptedData verify passed\n" if $verbose;
366183234Ssimon    }
367183234Ssimon}
368183234Ssimon
369183234Ssimonsub cmp_files {
370183234Ssimon    my ( $f1, $f2 ) = @_;
371183234Ssimon    my ( $fp1, $fp2 );
372183234Ssimon
373183234Ssimon    my ( $rd1, $rd2 );
374183234Ssimon
375183234Ssimon    if ( !open( $fp1, "<$f1" ) ) {
376183234Ssimon        print STDERR "Can't Open file $f1\n";
377183234Ssimon        return 0;
378183234Ssimon    }
379183234Ssimon
380183234Ssimon    if ( !open( $fp2, "<$f2" ) ) {
381183234Ssimon        print STDERR "Can't Open file $f2\n";
382183234Ssimon        return 0;
383183234Ssimon    }
384183234Ssimon
385183234Ssimon    binmode $fp1;
386183234Ssimon    binmode $fp2;
387183234Ssimon
388183234Ssimon    my $ret = 0;
389183234Ssimon
390183234Ssimon    for ( ; ; ) {
391183234Ssimon        $n1 = sysread $fp1, $rd1, 4096;
392183234Ssimon        $n2 = sysread $fp2, $rd2, 4096;
393183234Ssimon        last if ( $n1 != $n2 );
394183234Ssimon        last if ( $rd1 ne $rd2 );
395183234Ssimon
396183234Ssimon        if ( $n1 == 0 ) {
397183234Ssimon            $ret = 1;
398183234Ssimon            last;
399183234Ssimon        }
400183234Ssimon
401183234Ssimon    }
402183234Ssimon
403183234Ssimon    close $fp1;
404183234Ssimon    close $fp2;
405183234Ssimon
406183234Ssimon    return $ret;
407183234Ssimon
408183234Ssimon}
409183234Ssimon
410