Fix c_rehash script, add -fingerprint option to crl.
authorDr. Stephen Henson <steve@openssl.org>
Thu, 18 May 2000 00:33:00 +0000 (00:33 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Thu, 18 May 2000 00:33:00 +0000 (00:33 +0000)
CHANGES
Configure
Makefile.org
apps/Makefile.ssl
apps/crl.c
crypto/x509/x509.h
crypto/x509/x_all.c
tools/c_rehash.in

diff --git a/CHANGES b/CHANGES
index ab8f8531fa6fb171ed43f5bf69881173a7ebec88..bb2e353d59cf75f3d0a9ab1b2ba3925f83d3f5db 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,12 @@
 
  Changes between 0.9.5a and 0.9.6  [xx XXX 2000]
 
+  *) Enhance c_rehash script. Old version would mishandle certificates
+     with the same subject name hash and wouldn't handle CRLs at all.
+     Added -fingerprint option to crl utility, to support new c_rehash
+     features.
+     [Steve Henson]
+
   *) Eliminate non-ANSI declarations in crypto.h and stack.h.
         [Ulf Möller]
 
index 1de6c3fb104ea9799e6eb97fa27bb3b5a09affd0..3e86c05a871a58bee6f96f04c705cfd24fc7aa68 100755 (executable)
--- a/Configure
+++ b/Configure
@@ -890,12 +890,13 @@ EOF
        ### (system 'make depend') == 0 or exit $? if $depflags ne "";
        # Run "make depend" manually if you want to be able to delete
        # the source code files of ciphers you left out.
-       &dofile("tools/c_rehash",$openssldir,'^DIR=',   'DIR=%s',);
        if ( $perl =~ m@^/@) {
+           &dofile("tools/c_rehash",$perl,'^#!/', '#!%s','^my \$dir;$', 'my $dir = "' . $openssldir . '";');
            &dofile("apps/der_chop",$perl,'^#!/', '#!%s');
            &dofile("apps/CA.pl",$perl,'^#!/', '#!%s');
        } else {
            # No path for Perl known ...
+           &dofile("tools/c_rehash",'/usr/local/bin/perl','^#!/', '#!%s','^my \$dir;$', 'my $dir = "' . $openssldir . '";');
            &dofile("apps/der_chop",'/usr/local/bin/perl','^#!/', '#!%s');
            &dofile("apps/CA.pl",'/usr/local/bin/perl','^#!/', '#!%s');
        }           
index 5ca1493925f12f783ab5b4cded8ce56e7fbaabe8..cf98fb515e4b94e52ef4a56cf04bdc4e344f1779 100644 (file)
@@ -262,7 +262,7 @@ dclean:
 
 rehash: rehash.time
 rehash.time: certs
-       @(OPENSSL="`pwd`/apps/openssl"; export OPENSSL; sh tools/c_rehash certs)
+       @(OPENSSL="`pwd`/apps/openssl"; export OPENSSL; $(PERL) tools/c_rehash certs)
        touch rehash.time
 
 test:   tests
index fef670db2307094dba21bf8c81d3377beb974f81..0d0cd888b47a72a758ebd52787cc621f2da0cbb6 100644 (file)
@@ -135,7 +135,7 @@ $(DLIBCRYPTO):
 $(PROGRAM): progs.h $(E_OBJ) $(PROGRAM).o $(DLIBCRYPTO) $(DLIBSSL)
        $(RM) $(PROGRAM)
        $(CC) -o $(PROGRAM) $(CFLAGS) $(PROGRAM).o $(E_OBJ) $(PEX_LIBS) $(LIBSSL) $(LIBCRYPTO) $(EX_LIBS)
-       @(cd ..; OPENSSL="`pwd`/apps/openssl"; export OPENSSL; sh tools/c_rehash certs)
+       @(cd ..; OPENSSL="`pwd`/apps/openssl"; export OPENSSL; $(PERL) tools/c_rehash certs)
 
 progs.h: progs.pl
        $(PERL) progs.pl $(E_EXE) >progs.h
index 338f46d97c5f00b95ab4d997f2df8e3527db1644..b1c3325f21ec8e2d322d01c656765e8140bcb653 100644 (file)
@@ -104,6 +104,7 @@ int MAIN(int argc, char **argv)
        int informat,outformat;
        char *infile=NULL,*outfile=NULL;
        int hash=0,issuer=0,lastupdate=0,nextupdate=0,noout=0,text=0;
+       int fingerprint = 0;
        char **pp,buf[256];
        X509_STORE *store = NULL;
        X509_STORE_CTX ctx;
@@ -111,6 +112,7 @@ int MAIN(int argc, char **argv)
        X509_OBJECT xobj;
        EVP_PKEY *pkey;
        int do_ver = 0;
+       const EVP_MD *md_alg,*digest=EVP_md5();
 
        apps_startup();
 
@@ -183,6 +185,13 @@ int MAIN(int argc, char **argv)
                        nextupdate= ++num;
                else if (strcmp(*argv,"-noout") == 0)
                        noout= ++num;
+               else if (strcmp(*argv,"-fingerprint") == 0)
+                       fingerprint= ++num;
+               else if ((md_alg=EVP_get_digestbyname(*argv + 1)))
+                       {
+                       /* ok */
+                       digest=md_alg;
+                       }
                else
                        {
                        BIO_printf(bio_err,"unknown option %s\n",*argv);
@@ -274,6 +283,26 @@ bad:
                                        BIO_printf(bio_out,"NONE");
                                BIO_printf(bio_out,"\n");
                                }
+                       if (fingerprint == i)
+                               {
+                               int j;
+                               unsigned int n;
+                               unsigned char md[EVP_MAX_MD_SIZE];
+
+                               if (!X509_CRL_digest(x,digest,md,&n))
+                                       {
+                                       BIO_printf(bio_err,"out of memory\n");
+                                       goto end;
+                                       }
+                               BIO_printf(bio_out,"%s Fingerprint=",
+                                               OBJ_nid2sn(EVP_MD_type(digest)));
+                               for (j=0; j<(int)n; j++)
+                                       {
+                                       BIO_printf(bio_out,"%02X%c",md[j],
+                                               (j+1 == (int)n)
+                                               ?'\n':':');
+                                       }
+                               }
                        }
                }
 
index d2ad77815e343601902c7fd489c2a6db89701594..a0aaad8366a49d0b1306ff56857e71375d177588 100644 (file)
@@ -660,6 +660,8 @@ int X509_CRL_sign(X509_CRL *x, EVP_PKEY *pkey, const EVP_MD *md);
 int NETSCAPE_SPKI_sign(NETSCAPE_SPKI *x, EVP_PKEY *pkey, const EVP_MD *md);
 
 int X509_digest(X509 *data,const EVP_MD *type,unsigned char *md,unsigned int *len);
+int X509_CRL_digest(X509_CRL *data,const EVP_MD *type,unsigned char *md,unsigned int *len);
+int X509_REQ_digest(X509_REQ *data,const EVP_MD *type,unsigned char *md,unsigned int *len);
 int X509_NAME_digest(X509_NAME *data,const EVP_MD *type,
        unsigned char *md,unsigned int *len);
 #endif
index d2bf3c8e1c69f6aa1430b4dbd8d138869db08372..b67ca243dc3e88100ffee76095935b54ff8c8661 100644 (file)
@@ -417,6 +417,18 @@ int X509_digest(X509 *data, const EVP_MD *type, unsigned char *md,
        return(ASN1_digest((int (*)())i2d_X509,type,(char *)data,md,len));
        }
 
+int X509_CRL_digest(X509_CRL *data, const EVP_MD *type, unsigned char *md,
+            unsigned int *len)
+       {
+       return(ASN1_digest((int (*)())i2d_X509_CRL,type,(char *)data,md,len));
+       }
+
+int X509_REQ_digest(X509_REQ *data, const EVP_MD *type, unsigned char *md,
+            unsigned int *len)
+       {
+       return(ASN1_digest((int (*)())i2d_X509_REQ,type,(char *)data,md,len));
+       }
+
 int X509_NAME_digest(X509_NAME *data, const EVP_MD *type, unsigned char *md,
             unsigned int *len)
        {
index cc3b65871f06a8987e9509ebe32de9244bd4221a..baec7c14ff4308a3062996597f0c27a1dbef54d0 100644 (file)
-#!/bin/sh
-#
-# redo the hashes for the certificates in your cert path or the ones passed
-# on the command line.
-#
-
-if [ "$OPENSSL"x = "x" -o ! -x "$OPENSSL" ]; then
-       OPENSSL='openssl'
-       export OPENSSL
-fi
-DIR=/usr/local/ssl
-PATH=$DIR/bin:$PATH
-
-if [ ! -f "$OPENSSL" ]; then
-    found=0
-    for dir in . `echo $PATH | sed -e 's/:/ /g'`; do
-        if [ -f "$dir/$OPENSSL" ]; then
-            found=1
-            break
-        fi
-    done
-    if [ $found = 0 ]; then
-        echo "c_rehash: rehashing skipped ('openssl' program not available)" 1>&2
-        exit 0
-    fi
-fi
-
-SSL_DIR=$DIR/certs
-
-if [ "$*" = "" ]; then
-       CERTS=${*:-${SSL_CERT_DIR:-$SSL_DIR}}
-else
-       CERTS=$*
-fi
-
-IFS=': '
-for i in $CERTS
-do
-  (
-  IFS=' '
-  if [ -d $i -a -w $i ]; then
-    cd $i
-    echo "Doing $i"
-    for i in *.pem
-    do
-      if [ $i != '*.pem' ]; then
-        h=`$OPENSSL x509 -hash -noout -in $i`
-       if [ "x$h" = "x" ]; then
-         echo $i does not contain a certificate
-       else
-          if [ -f $h.0 ]; then
-            /bin/rm -f $h.0
-          fi
-          echo "$i => $h.0"
-          ln -s $i $h.0
-       fi
-      fi
-    done
-  fi
-  )
-done
+#!/usr/local/bin/perl
+
+
+# Perl c_rehash script, scan all files in a directory
+# and add symbolic links to their hash values.
+
+my $openssl;
+
+my $dir;
+
+if(defined $ENV{OPENSSL}) {
+       $openssl = $ENV{OPENSSL};
+} else {
+       $openssl = "openssl";
+       $ENV{OPENSSL} = $openssl;
+}
+
+$ENV{PATH} .= ":$dir/bin";
+
+if(! -f $openssl) {
+       my $found = 0;
+       foreach (split /:/, $ENV{PATH}) {
+               if(-f "$_/$openssl") {
+                       $found = 1;
+                       last;
+               }       
+       }
+       if($found == 0) {
+               print STDERR "c_rehash: rehashing skipped ('openssl' program not available)\n";
+               exit 0;
+       }
+}
+
+if(@ARGV) {
+       @dirlist = @ARGV;
+} elsif($ENV{SSL_CERT_DIR}) {
+       @dirlist = split /:/, $ENV{SSL_CERT_DIR};
+} else {
+       $dirlist[0] = "$dir/certs";
+}
+
+
+foreach (@dirlist) {
+       if(-d $_ and -w $_) {
+               hash_dir($_);
+       }
+}
+
+sub hash_dir {
+       my %hashlist;
+       print "Doing $_[0]\n";
+       chdir $_[0];
+       opendir(DIR, ".");
+       my @flist = readdir(DIR);
+       # Delete any existing symbolic links
+       foreach (grep {/^[\da-f]+\.r{0,1}\d+$/} @flist) {
+               if(-l $_) {
+                       unlink $_;
+               }
+       }
+       closedir DIR;
+       FILE: foreach $fname (grep {/\.pem$/} @flist) {
+               # Check to see if certificates and/or CRLs present.
+               my ($cert, $crl) = check_file($fname);
+               if(!$cert && !$crl) {
+                       print STDERR "WARNING: $fname does not contain a certificate or CRL: skipping\n";
+                       next;
+               }
+               link_hash_cert($fname) if($cert);
+               link_hash_crl($fname) if($crl);
+       }
+}
+
+sub check_file {
+       my ($is_cert, $is_crl) = (0,0);
+       my $fname = $_[0];
+       open IN, $fname;
+       while(<IN>) {
+               if(/^-----BEGIN (.*)-----/) {
+                       my $hdr = $1;
+                       if($hdr =~ /^(X509 |TRUSTED |)CERTIFICATE$/) {
+                               $is_cert = 1;
+                               last if($is_crl);
+                       } elsif($hdr eq "X509 CRL") {
+                               $is_crl = 1;
+                               last if($is_cert);
+                       }
+               }
+       }
+       close IN;
+       return ($is_cert, $is_crl);
+}
+
+
+# Link a certificate to its subject name hash value, each hash is of
+# the form <hash>.<n> where n is an integer. If the hash value already exists
+# then we need to up the value of n, unless its a duplicate in which
+# case we skip the link. We check for duplicates by comparing the
+# certificate fingerprints
+
+sub link_hash_cert {
+               my $fname = $_[0];
+               my ($hash, $fprint) = `$openssl x509 -hash -fingerprint -noout -in $fname`;
+               chomp $hash;
+               chomp $fprint;
+               $fprint =~ s/^.*=//;
+               $fprint =~ tr/://d;
+               my $suffix = 0;
+               # Search for an unused hash filename
+               while(exists $hashlist{"$hash.$suffix"}) {
+                       # Hash matches: if fingerprint matches its a duplicate cert
+                       if($hashlist{"$hash.$suffix"} eq $fprint) {
+                               print STDERR "WARNING: Skipping duplicate certificate $fname\n";
+                               return;
+                       }
+                       $suffix++;
+               }
+               $hash .= ".$suffix";
+               print "$fname => $hash\n";
+               symlink $fname, $hash;
+               $hashlist{$hash} = $fprint;
+}
+
+# Same as above except for a CRL. CRL links are of the form <hash>.r<n>
+
+sub link_hash_crl {
+               my $fname = $_[0];
+               my ($hash, $fprint) = `$openssl crl -hash -fingerprint -noout -in $fname`;
+               chomp $hash;
+               chomp $fprint;
+               $fprint =~ s/^.*=//;
+               $fprint =~ tr/://d;
+               my $suffix = 0;
+               # Search for an unused hash filename
+               while(exists $hashlist{"$hash.r$suffix"}) {
+                       # Hash matches: if fingerprint matches its a duplicate cert
+                       if($hashlist{"$hash.r$suffix"} eq $fprint) {
+                               print STDERR "WARNING: Skipping duplicate CRL $fname\n";
+                               return;
+                       }
+                       $suffix++;
+               }
+               $hash .= ".r$suffix";
+               print "$fname => $hash\n";
+               symlink $fname, $hash;
+               $hashlist{$hash} = $fprint;
+}
+