Move to beta 3.
[openssl.git] / apps / der_chop
1 #!/usr/local/bin/perl
2 #
3 # der_chop ... this is one total hack that Eric is really not proud of
4 #              so don't look at it and don't ask for support
5 #
6 # The "documentation" for this (i.e. all the comments) are my fault --tjh
7 #
8 # This program takes the "raw" output of derparse/asn1parse and 
9 # converts it into tokens and then runs regular expression matches
10 # to try to figure out what to grab to get the things that are needed
11 # and it is possible that this will do the wrong thing as it is a *hack*
12 #
13 # SSLeay 0.5.2+ should have direct read support for x509 (via -inform NET)
14 # [I know ... promises promises :-)]
15 #
16 # To convert a Netscape Certificate:
17 #    der_chop < ServerCert.der > cert.pem
18 # To convert a Netscape Key (and encrypt it again to protect it)
19 #    rsa -inform NET -in ServerKey.der -des > key.pem
20 #
21 # 23-Apr-96 eay    Added the extra ASN.1 string types, I still think this
22 #                  is an evil hack.  If nothing else the parsing should
23 #                  be relative, not absolute.
24 # 19-Apr-96 tjh    hacked (with eay) into 0.5.x format
25 #
26 # Tim Hudson
27 # tjh@cryptsoft.com
28 #
29
30
31 require 'getopts.pl';
32
33 $debug=0;
34
35 # this was the 0.4.x way of doing things ...
36 $cmd="derparse";
37 $x509_cmd="x509";
38 $crl_cmd="crl";
39 $rc4_cmd="rc4";
40 $md2_cmd="md2";
41 $md4_cmd="md4";
42 $rsa_cmd="rsa -des -inform der ";
43
44 # this was the 0.5.x way of doing things ...
45 $cmd="openssl asn1parse";
46 $x509_cmd="openssl x509";
47 $crl_cmd="openssl crl";
48 $rc4_cmd="openssl rc4";
49 $md2_cmd="openssl md2";
50 $md4_cmd="openssl md4";
51 $rsa_cmd="openssl rsa -des -inform der ";
52
53 &Getopts('vd:') || die "usage:$0 [-v] [-d num] file";
54 $depth=($opt_d =~ /^\d+$/)?$opt_d:0;
55
56 &init_der();
57
58 if ($#ARGV != -1)
59         {
60         foreach $file (@ARGV)
61                 {
62                 print STDERR "doing $file\n";
63                 &dofile($file);
64                 }
65         }
66 else
67         {
68         $file="/tmp/a$$.DER";
69         open(OUT,">$file") || die "unable to open $file:$!\n";
70         for (;;)
71                 {
72                 $i=sysread(STDIN,$b,1024*10);
73                 last if ($i <= 0);
74                 $i=syswrite(OUT,$b,$i);
75                 }
76         &dofile($file);
77         unlink($file);
78         }
79         
80 sub dofile
81         {
82         local($file)=@_;
83         local(@p);
84
85         $b=&load_file($file);
86         @p=&load_file_parse($file);
87
88         foreach $_ (@p)
89                 {
90                 ($off,$d,$hl,$len)=&parse_line($_);
91                 $d-=$depth;
92                 next if ($d != 0);
93                 next if ($len == 0);
94
95                 $o=substr($b,$off,$len+$hl);
96                 ($str,@data)=&der_str($o);
97                 print "$str\n" if ($opt_v);
98                 if ($str =~ /^$crl/)
99                         {
100                         open(OUT,"|$crl_cmd -inform d -hash -issuer") ||
101                                 die "unable to run $crl_cmd:$!\n";
102                         print OUT $o;
103                         close(OUT);
104                         }
105                 elsif ($str =~ /^$x509/)
106                         {
107                         open(OUT,"|$x509_cmd -inform d -hash -subject -issuer")
108                                 || die "unable to run $x509_cmd:$!\n";
109                         print OUT $o;
110                         close(OUT);
111                         }
112                 elsif ($str =~ /^$rsa/)
113                         {
114                         ($type)=($data[3] =~ /OBJECT_IDENTIFIER :(.*)\s*$/);
115                         next unless ($type eq "rsaEncryption");
116                         ($off,$d,$hl,$len)=&parse_line($data[5]);
117                         $os=substr($o,$off+$hl,$len);
118                         open(OUT,"|$rsa_cmd")
119                                 || die "unable to run $rsa_cmd:$!\n";
120                         print OUT $os;
121                         close(OUT);
122                         }
123                 elsif ($str =~ /^0G-1D-1G/)
124                         {
125                         ($off,$d,$hl,$len)=&parse_line($data[1]);
126                         $os=substr($o,$off+$hl,$len);
127                         print STDERR "<$os>\n" if $opt_v;
128                         &do_certificate($o,@data)
129                                 if (($os eq "certificate") &&
130                                     ($str =! /^0G-1D-1G-2G-3F-3E-2D/));
131                         &do_private_key($o,@data)
132                                 if (($os eq "private-key") &&
133                                     ($str =! /^0G-1D-1G-2G-3F-3E-2D/));
134                         }
135                 }
136         }
137
138 sub der_str
139         {
140         local($str)=@_;
141         local(*OUT,*IN,@a,$t,$d,$ret);
142         local($file)="/tmp/b$$.DER";
143         local(@ret);
144
145         open(OUT,">$file");
146         print OUT $str;
147         close(OUT);
148         open(IN,"$cmd -inform 'd' -in $file |") ||
149                 die "unable to run $cmd:$!\n";
150         $ret="";
151         while (<IN>)
152                 {
153                 chop;
154                 push(@ret,$_);
155
156                 print STDERR "$_\n" if ($debug);
157
158                 @a=split(/\s*:\s*/);
159                 ($d)=($a[1] =~ /d=\s*(\d+)/);
160                 $a[2] =~ s/\s+$//;
161                 $t=$DER_s2i{$a[2]};
162                 $ret.="$d$t-";
163                 }
164         close(IN);
165         unlink($file);
166         chop $ret;
167         $ret =~ s/(-3H(-4G-5F-5[IJKMQRS])+)+/-NAME/g;
168         $ret =~ s/(-3G-4B-4L)+/-RCERT/g;
169         return($ret,@ret);
170         }
171
172 sub init_der
173         {
174         $crl= "0G-1G-2G-3F-3E-2G-NAME-2L-2L-2G-RCERT-1G-2F-2E-1C";
175         $x509="0G-1G-2B-2G-3F-3E-2G-NAME-2G-3L-3L-2G-NAME-2G-3G-4F-4E-3C-1G-2F-2E-1C";
176         $rsa= "0G-1B-1G-2F-2E-1D";
177
178         %DER_i2s=(
179                 # SSLeay 0.4.x has this list
180                 "A","EOC",
181                 "B","INTEGER",
182                 "C","BIT STRING",
183                 "D","OCTET STRING",
184                 "E","NULL",
185                 "F","OBJECT",
186                 "G","SEQUENCE",
187                 "H","SET",
188                 "I","PRINTABLESTRING",
189                 "J","T61STRING",
190                 "K","IA5STRING",
191                 "L","UTCTIME",
192                 "M","NUMERICSTRING",
193                 "N","VIDEOTEXSTRING",
194                 "O","GENERALIZEDTIME",
195                 "P","GRAPHICSTRING",
196                 "Q","ISO64STRING",
197                 "R","GENERALSTRING",
198                 "S","UNIVERSALSTRING",
199
200                 # SSLeay 0.5.x changed some things ... and I'm
201                 # leaving in the old stuff but adding in these
202                 # to handle the new as well --tjh
203                 # - Well I've just taken them out and added the extra new
204                 # ones :-) - eay
205                 );
206
207         foreach (keys %DER_i2s)
208                 { $DER_s2i{$DER_i2s{$_}}=$_; }
209         }
210
211 sub parse_line
212         {
213         local($_)=@_;
214
215         return(/\s*(\d+):d=\s*(\d+)\s+hl=\s*(\d+)\s+l=\s*(\d+|inf)\s/);
216         }
217
218 #  0:d=0 hl=4 l=377 cons: univ: SEQUENCE          
219 #  4:d=1 hl=2 l= 11 prim: univ: OCTET_STRING      
220 # 17:d=1 hl=4 l=360 cons: univ: SEQUENCE          
221 # 21:d=2 hl=2 l= 12 cons: univ: SEQUENCE          
222 # 23:d=3 hl=2 l=  8 prim: univ: OBJECT_IDENTIFIER :rc4
223 # 33:d=3 hl=2 l=  0 prim: univ: NULL              
224 # 35:d=2 hl=4 l=342 prim: univ: OCTET_STRING
225 sub do_private_key
226         {
227         local($data,@struct)=@_;
228         local($file)="/tmp/b$$.DER";
229         local($off,$d,$hl,$len,$_,$b,@p,$s);
230
231         ($type)=($struct[4] =~ /OBJECT_IDENTIFIER :(.*)\s*$/);
232         if ($type eq "rc4")
233                 {
234                 ($off,$d,$hl,$len)=&parse_line($struct[6]);
235                 open(OUT,"|$rc4_cmd >$file") ||
236                         die "unable to run $rc4_cmd:$!\n";
237                 print OUT substr($data,$off+$hl,$len);
238                 close(OUT);
239
240                 $b=&load_file($file);
241                 unlink($file);
242
243                 ($s,@p)=&der_str($b);
244                 die "unknown rsa key type\n$s\n"
245                         if ($s ne '0G-1B-1G-2F-2E-1D');
246                 local($off,$d,$hl,$len)=&parse_line($p[5]);
247                 $b=substr($b,$off+$hl,$len);
248                 ($s,@p)=&der_str($b);
249                 open(OUT,"|$rsa_cmd") || die "unable to run $rsa_cmd:$!\n";
250                 print OUT $b;
251                 close(OUT);
252                 }
253         else
254                 {
255                 print "'$type' is unknown\n";
256                 exit(1);
257                 }
258         }
259
260 sub do_certificate
261         {
262         local($data,@struct)=@_;
263         local($file)="/tmp/b$$.DER";
264         local($off,$d,$hl,$len,$_,$b,@p,$s);
265
266         ($off,$d,$hl,$len)=&parse_line($struct[2]);
267         $b=substr($data,$off,$len+$hl);
268
269         open(OUT,"|$x509_cmd -inform d") || die "unable to run $x509_cmd:$!\n";
270         print OUT $b;
271         close(OUT);
272         }
273
274 sub load_file
275         {
276         local($file)=@_;
277         local(*IN,$r,$b,$i);
278
279         $r="";
280         open(IN,"<$file") || die "unable to open $file:$!\n";
281         for (;;)
282                 {
283                 $i=sysread(IN,$b,10240);
284                 last if ($i <= 0);
285                 $r.=$b;
286                 }
287         close(IN);
288         return($r);
289         }
290
291 sub load_file_parse
292         {
293         local($file)=@_;
294         local(*IN,$r,@ret,$_,$i,$n,$b);
295
296         open(IN,"$cmd -inform d -in $file|")
297                 || die "unable to run der_parse\n";
298         while (<IN>)
299                 {
300                 chop;
301                 push(@ret,$_);
302                 }
303         return($r,@ret);
304         }
305