#!/usr/local/bin/perl5 # # der_chop ... this is one total hack that Eric is really not proud of # so don't look at it and don't ask for support # # The "documentation" for this (i.e. all the comments) are my fault --tjh # # This program takes the "raw" output of derparse/asn1parse and # converts it into tokens and then runs regular expression matches # to try to figure out what to grab to get the things that are needed # and it is possible that this will do the wrong thing as it is a *hack* # # SSLeay 0.5.2+ should have direct read support for x509 (via -inform NET) # [I know ... promises promises :-)] # # To convert a Netscape Certificate: # der_chop < ServerCert.der > cert.pem # To convert a Netscape Key (and encrypt it again to protect it) # rsa -inform NET -in ServerKey.der -des > key.pem # # 23-Apr-96 eay Added the extra ASN.1 string types, I still think this # is an evil hack. If nothing else the parsing should # be relative, not absolute. # 19-Apr-96 tjh hacked (with eay) into 0.5.x format # # Tim Hudson # tjh@cryptsoft.com # require 'getopts.pl'; $debug=0; # this was the 0.4.x way of doing things ... $cmd="derparse"; $x509_cmd="x509"; $crl_cmd="crl"; $rc4_cmd="rc4"; $md2_cmd="md2"; $md4_cmd="md4"; $rsa_cmd="rsa -des -inform der "; # this was the 0.5.x way of doing things ... $cmd="openssl asn1parse"; $x509_cmd="openssl x509"; $crl_cmd="openssl crl"; $rc4_cmd="openssl rc4"; $md2_cmd="openssl md2"; $md4_cmd="openssl md4"; $rsa_cmd="openssl rsa -des -inform der "; &Getopts('vd:') || die "usage:$0 [-v] [-d num] file"; $depth=($opt_d =~ /^\d+$/)?$opt_d:0; &init_der(); if ($#ARGV != -1) { foreach $file (@ARGV) { print STDERR "doing $file\n"; &dofile($file); } } else { $file="/tmp/a$$.DER"; open(OUT,">$file") || die "unable to open $file:$!\n"; for (;;) { $i=sysread(STDIN,$b,1024*10); last if ($i <= 0); $i=syswrite(OUT,$b,$i); } &dofile($file); unlink($file); } sub dofile { local($file)=@_; local(@p); $b=&load_file($file); @p=&load_file_parse($file); foreach $_ (@p) { ($off,$d,$hl,$len)=&parse_line($_); $d-=$depth; next if ($d != 0); next if ($len == 0); $o=substr($b,$off,$len+$hl); ($str,@data)=&der_str($o); print "$str\n" if ($opt_v); if ($str =~ /^$crl/) { open(OUT,"|$crl_cmd -inform d -hash -issuer") || die "unable to run $crl_cmd:$!\n"; print OUT $o; close(OUT); } elsif ($str =~ /^$x509/) { open(OUT,"|$x509_cmd -inform d -hash -subject -issuer") || die "unable to run $x509_cmd:$!\n"; print OUT $o; close(OUT); } elsif ($str =~ /^$rsa/) { ($type)=($data[3] =~ /OBJECT_IDENTIFIER :(.*)\s*$/); next unless ($type eq "rsaEncryption"); ($off,$d,$hl,$len)=&parse_line($data[5]); $os=substr($o,$off+$hl,$len); open(OUT,"|$rsa_cmd") || die "unable to run $rsa_cmd:$!\n"; print OUT $os; close(OUT); } elsif ($str =~ /^0G-1D-1G/) { ($off,$d,$hl,$len)=&parse_line($data[1]); $os=substr($o,$off+$hl,$len); print STDERR "<$os>\n" if $opt_v; &do_certificate($o,@data) if (($os eq "certificate") && ($str =! /^0G-1D-1G-2G-3F-3E-2D/)); &do_private_key($o,@data) if (($os eq "private-key") && ($str =! /^0G-1D-1G-2G-3F-3E-2D/)); } } } sub der_str { local($str)=@_; local(*OUT,*IN,@a,$t,$d,$ret); local($file)="/tmp/b$$.DER"; local(@ret); open(OUT,">$file"); print OUT $str; close(OUT); open(IN,"$cmd -inform 'd' -in $file |") || die "unable to run $cmd:$!\n"; $ret=""; while () { chop; push(@ret,$_); print STDERR "$_\n" if ($debug); @a=split(/\s*:\s*/); ($d)=($a[1] =~ /d=\s*(\d+)/); $a[2] =~ s/\s+$//; $t=$DER_s2i{$a[2]}; $ret.="$d$t-"; } close(IN); unlink($file); chop $ret; $ret =~ s/(-3H(-4G-5F-5[IJKMQRS])+)+/-NAME/g; $ret =~ s/(-3G-4B-4L)+/-RCERT/g; return($ret,@ret); } sub init_der { $crl= "0G-1G-2G-3F-3E-2G-NAME-2L-2L-2G-RCERT-1G-2F-2E-1C"; $x509="0G-1G-2B-2G-3F-3E-2G-NAME-2G-3L-3L-2G-NAME-2G-3G-4F-4E-3C-1G-2F-2E-1C"; $rsa= "0G-1B-1G-2F-2E-1D"; %DER_i2s=( # SSLeay 0.4.x has this list "A","EOC", "B","INTEGER", "C","BIT STRING", "D","OCTET STRING", "E","NULL", "F","OBJECT", "G","SEQUENCE", "H","SET", "I","PRINTABLESTRING", "J","T61STRING", "K","IA5STRING", "L","UTCTIME", "M","NUMERICSTRING", "N","VIDEOTEXSTRING", "O","GENERALIZEDTIME", "P","GRAPHICSTRING", "Q","ISO64STRING", "R","GENERALSTRING", "S","UNIVERSALSTRING", # SSLeay 0.5.x changed some things ... and I'm # leaving in the old stuff but adding in these # to handle the new as well --tjh # - Well I've just taken them out and added the extra new # ones :-) - eay ); foreach (keys %DER_i2s) { $DER_s2i{$DER_i2s{$_}}=$_; } } sub parse_line { local($_)=@_; return(/\s*(\d+):d=\s*(\d+)\s+hl=\s*(\d+)\s+l=\s*(\d+|inf)\s/); } # 0:d=0 hl=4 l=377 cons: univ: SEQUENCE # 4:d=1 hl=2 l= 11 prim: univ: OCTET_STRING # 17:d=1 hl=4 l=360 cons: univ: SEQUENCE # 21:d=2 hl=2 l= 12 cons: univ: SEQUENCE # 23:d=3 hl=2 l= 8 prim: univ: OBJECT_IDENTIFIER :rc4 # 33:d=3 hl=2 l= 0 prim: univ: NULL # 35:d=2 hl=4 l=342 prim: univ: OCTET_STRING sub do_private_key { local($data,@struct)=@_; local($file)="/tmp/b$$.DER"; local($off,$d,$hl,$len,$_,$b,@p,$s); ($type)=($struct[4] =~ /OBJECT_IDENTIFIER :(.*)\s*$/); if ($type eq "rc4") { ($off,$d,$hl,$len)=&parse_line($struct[6]); open(OUT,"|$rc4_cmd >$file") || die "unable to run $rc4_cmd:$!\n"; print OUT substr($data,$off+$hl,$len); close(OUT); $b=&load_file($file); unlink($file); ($s,@p)=&der_str($b); die "unknown rsa key type\n$s\n" if ($s ne '0G-1B-1G-2F-2E-1D'); local($off,$d,$hl,$len)=&parse_line($p[5]); $b=substr($b,$off+$hl,$len); ($s,@p)=&der_str($b); open(OUT,"|$rsa_cmd") || die "unable to run $rsa_cmd:$!\n"; print OUT $b; close(OUT); } else { print "'$type' is unknown\n"; exit(1); } } sub do_certificate { local($data,@struct)=@_; local($file)="/tmp/b$$.DER"; local($off,$d,$hl,$len,$_,$b,@p,$s); ($off,$d,$hl,$len)=&parse_line($struct[2]); $b=substr($data,$off,$len+$hl); open(OUT,"|$x509_cmd -inform d") || die "unable to run $x509_cmd:$!\n"; print OUT $b; close(OUT); } sub load_file { local($file)=@_; local(*IN,$r,$b,$i); $r=""; open(IN,"<$file") || die "unable to open $file:$!\n"; for (;;) { $i=sysread(IN,$b,10240); last if ($i <= 0); $r.=$b; } close(IN); return($r); } sub load_file_parse { local($file)=@_; local(*IN,$r,@ret,$_,$i,$n,$b); open(IN,"$cmd -inform d -in $file|") || die "unable to run der_parse\n"; while () { chop; push(@ret,$_); } return($r,@ret); }