xref: /freebsd/crypto/openssl/tools/c_rehash (revision 4757b351ea9d59d71d4a38b82506d2d16fcd560d)
1*4757b351SPierre Pronchery#!/usr/local/bin/perl
2*4757b351SPierre Pronchery
3*4757b351SPierre Pronchery# WARNING: do not edit!
4*4757b351SPierre Pronchery# Generated by Makefile from tools/c_rehash.in
5*4757b351SPierre Pronchery# Copyright 1999-2025 The OpenSSL Project Authors. All Rights Reserved.
6*4757b351SPierre Pronchery#
7*4757b351SPierre Pronchery# Licensed under the Apache License 2.0 (the "License").  You may not use
8*4757b351SPierre Pronchery# this file except in compliance with the License.  You can obtain a copy
9*4757b351SPierre Pronchery# in the file LICENSE in the source distribution or at
10*4757b351SPierre Pronchery# https://www.openssl.org/source/license.html
11*4757b351SPierre Pronchery
12*4757b351SPierre Pronchery# Perl c_rehash script, scan all files in a directory
13*4757b351SPierre Pronchery# and add symbolic links to their hash values.
14*4757b351SPierre Pronchery
15*4757b351SPierre Proncherymy $dir = "/usr/local/openssl";
16*4757b351SPierre Proncherymy $prefix = "/usr/local";
17*4757b351SPierre Pronchery
18*4757b351SPierre Proncherymy $errorcount = 0;
19*4757b351SPierre Proncherymy $openssl = $ENV{OPENSSL} || "openssl";
20*4757b351SPierre Proncherymy $pwd;
21*4757b351SPierre Proncherymy $x509hash = "-subject_hash";
22*4757b351SPierre Proncherymy $crlhash = "-hash";
23*4757b351SPierre Proncherymy $verbose = 0;
24*4757b351SPierre Proncherymy $symlink_exists=eval {symlink("",""); 1};
25*4757b351SPierre Proncherymy $removelinks = 1;
26*4757b351SPierre Pronchery
27*4757b351SPierre Pronchery##  Parse flags.
28*4757b351SPierre Proncherywhile ( $ARGV[0] =~ /^-/ ) {
29*4757b351SPierre Pronchery    my $flag = shift @ARGV;
30*4757b351SPierre Pronchery    last if ( $flag eq '--');
31*4757b351SPierre Pronchery    if ( $flag eq '-old') {
32*4757b351SPierre Pronchery        $x509hash = "-subject_hash_old";
33*4757b351SPierre Pronchery        $crlhash = "-hash_old";
34*4757b351SPierre Pronchery    } elsif ( $flag eq '-h' || $flag eq '-help' ) {
35*4757b351SPierre Pronchery        help();
36*4757b351SPierre Pronchery    } elsif ( $flag eq '-n' ) {
37*4757b351SPierre Pronchery        $removelinks = 0;
38*4757b351SPierre Pronchery    } elsif ( $flag eq '-v' ) {
39*4757b351SPierre Pronchery        $verbose++;
40*4757b351SPierre Pronchery    }
41*4757b351SPierre Pronchery    else {
42*4757b351SPierre Pronchery        print STDERR "Usage error; try -h.\n";
43*4757b351SPierre Pronchery        exit 1;
44*4757b351SPierre Pronchery    }
45*4757b351SPierre Pronchery}
46*4757b351SPierre Pronchery
47*4757b351SPierre Proncherysub help {
48*4757b351SPierre Pronchery    print "Usage: c_rehash [-old] [-h] [-help] [-v] [dirs...]\n";
49*4757b351SPierre Pronchery    print "   -old use old-style digest\n";
50*4757b351SPierre Pronchery    print "   -h or -help print this help text\n";
51*4757b351SPierre Pronchery    print "   -v print files removed and linked\n";
52*4757b351SPierre Pronchery    exit 0;
53*4757b351SPierre Pronchery}
54*4757b351SPierre Pronchery
55*4757b351SPierre Proncheryeval "require Cwd";
56*4757b351SPierre Proncheryif (defined(&Cwd::getcwd)) {
57*4757b351SPierre Pronchery    $pwd=Cwd::getcwd();
58*4757b351SPierre Pronchery} else {
59*4757b351SPierre Pronchery    $pwd=`pwd`;
60*4757b351SPierre Pronchery    chomp($pwd);
61*4757b351SPierre Pronchery}
62*4757b351SPierre Pronchery
63*4757b351SPierre Pronchery# DOS/Win32 or Unix delimiter?  Prefix our installdir, then search.
64*4757b351SPierre Proncherymy $path_delim = ($pwd =~ /^[a-z]\:/i) ? ';' : ':';
65*4757b351SPierre Pronchery$ENV{PATH} = "$prefix/bin" . ($ENV{PATH} ? $path_delim . $ENV{PATH} : "");
66*4757b351SPierre Pronchery
67*4757b351SPierre Proncheryif (!(-f $openssl && -x $openssl)) {
68*4757b351SPierre Pronchery    my $found = 0;
69*4757b351SPierre Pronchery    foreach (split /$path_delim/, $ENV{PATH}) {
70*4757b351SPierre Pronchery        if (-f "$_/$openssl" && -x "$_/$openssl") {
71*4757b351SPierre Pronchery            $found = 1;
72*4757b351SPierre Pronchery            $openssl = "$_/$openssl";
73*4757b351SPierre Pronchery            last;
74*4757b351SPierre Pronchery        }
75*4757b351SPierre Pronchery    }
76*4757b351SPierre Pronchery    if ($found == 0) {
77*4757b351SPierre Pronchery        print STDERR "c_rehash: rehashing skipped ('openssl' program not available)\n";
78*4757b351SPierre Pronchery        exit 0;
79*4757b351SPierre Pronchery    }
80*4757b351SPierre Pronchery}
81*4757b351SPierre Pronchery
82*4757b351SPierre Proncheryif (@ARGV) {
83*4757b351SPierre Pronchery    @dirlist = @ARGV;
84*4757b351SPierre Pronchery} elsif ($ENV{SSL_CERT_DIR}) {
85*4757b351SPierre Pronchery    @dirlist = split /$path_delim/, $ENV{SSL_CERT_DIR};
86*4757b351SPierre Pronchery} else {
87*4757b351SPierre Pronchery    $dirlist[0] = "$dir/certs";
88*4757b351SPierre Pronchery}
89*4757b351SPierre Pronchery
90*4757b351SPierre Proncheryif (-d $dirlist[0]) {
91*4757b351SPierre Pronchery    chdir $dirlist[0];
92*4757b351SPierre Pronchery    $openssl="$pwd/$openssl" if (!(-f $openssl && -x $openssl));
93*4757b351SPierre Pronchery    chdir $pwd;
94*4757b351SPierre Pronchery}
95*4757b351SPierre Pronchery
96*4757b351SPierre Proncheryforeach (@dirlist) {
97*4757b351SPierre Pronchery    if (-d $_ ) {
98*4757b351SPierre Pronchery        if ( -w $_) {
99*4757b351SPierre Pronchery            hash_dir($_);
100*4757b351SPierre Pronchery        } else {
101*4757b351SPierre Pronchery            print "Skipping $_, can't write\n";
102*4757b351SPierre Pronchery            $errorcount++;
103*4757b351SPierre Pronchery        }
104*4757b351SPierre Pronchery    }
105*4757b351SPierre Pronchery}
106*4757b351SPierre Proncheryexit($errorcount);
107*4757b351SPierre Pronchery
108*4757b351SPierre Proncherysub copy_file {
109*4757b351SPierre Pronchery    my ($src_fname, $dst_fname) = @_;
110*4757b351SPierre Pronchery
111*4757b351SPierre Pronchery    if (open(my $in, "<", $src_fname)) {
112*4757b351SPierre Pronchery        if (open(my $out, ">", $dst_fname)) {
113*4757b351SPierre Pronchery            print $out $_ while (<$in>);
114*4757b351SPierre Pronchery            close $out;
115*4757b351SPierre Pronchery        } else {
116*4757b351SPierre Pronchery            warn "Cannot open $dst_fname for write, $!";
117*4757b351SPierre Pronchery        }
118*4757b351SPierre Pronchery        close $in;
119*4757b351SPierre Pronchery    } else {
120*4757b351SPierre Pronchery        warn "Cannot open $src_fname for read, $!";
121*4757b351SPierre Pronchery    }
122*4757b351SPierre Pronchery}
123*4757b351SPierre Pronchery
124*4757b351SPierre Proncherysub hash_dir {
125*4757b351SPierre Pronchery    my $dir = shift;
126*4757b351SPierre Pronchery    my %hashlist;
127*4757b351SPierre Pronchery
128*4757b351SPierre Pronchery    print "Doing $dir\n";
129*4757b351SPierre Pronchery
130*4757b351SPierre Pronchery    if (!chdir $dir) {
131*4757b351SPierre Pronchery        print STDERR "WARNING: Cannot chdir to '$dir', $!\n";
132*4757b351SPierre Pronchery        return;
133*4757b351SPierre Pronchery    }
134*4757b351SPierre Pronchery
135*4757b351SPierre Pronchery    opendir(DIR, ".") || print STDERR "WARNING: Cannot opendir '.', $!\n";
136*4757b351SPierre Pronchery    my @flist = sort readdir(DIR);
137*4757b351SPierre Pronchery    closedir DIR;
138*4757b351SPierre Pronchery    if ( $removelinks ) {
139*4757b351SPierre Pronchery        # Delete any existing symbolic links
140*4757b351SPierre Pronchery        foreach (grep {/^[\da-f]+\.r{0,1}\d+$/} @flist) {
141*4757b351SPierre Pronchery            if (-l $_) {
142*4757b351SPierre Pronchery                print "unlink $_\n" if $verbose;
143*4757b351SPierre Pronchery                unlink $_ || warn "Can't unlink $_, $!\n";
144*4757b351SPierre Pronchery            }
145*4757b351SPierre Pronchery        }
146*4757b351SPierre Pronchery    }
147*4757b351SPierre Pronchery    FILE: foreach $fname (grep {/\.(pem|crt|cer|crl)$/} @flist) {
148*4757b351SPierre Pronchery        # Check to see if certificates and/or CRLs present.
149*4757b351SPierre Pronchery        my ($cert, $crl) = check_file($fname);
150*4757b351SPierre Pronchery        if (!$cert && !$crl) {
151*4757b351SPierre Pronchery            print STDERR "WARNING: $fname does not contain a certificate or CRL: skipping\n";
152*4757b351SPierre Pronchery            next;
153*4757b351SPierre Pronchery        }
154*4757b351SPierre Pronchery        link_hash_cert($fname) if ($cert);
155*4757b351SPierre Pronchery        link_hash_crl($fname) if ($crl);
156*4757b351SPierre Pronchery    }
157*4757b351SPierre Pronchery
158*4757b351SPierre Pronchery    chdir $pwd;
159*4757b351SPierre Pronchery}
160*4757b351SPierre Pronchery
161*4757b351SPierre Proncherysub check_file {
162*4757b351SPierre Pronchery    my ($is_cert, $is_crl) = (0,0);
163*4757b351SPierre Pronchery    my $fname = $_[0];
164*4757b351SPierre Pronchery
165*4757b351SPierre Pronchery    open(my $in, "<", $fname);
166*4757b351SPierre Pronchery    while(<$in>) {
167*4757b351SPierre Pronchery        if (/^-----BEGIN (.*)-----/) {
168*4757b351SPierre Pronchery            my $hdr = $1;
169*4757b351SPierre Pronchery            if ($hdr =~ /^(X509 |TRUSTED |)CERTIFICATE$/) {
170*4757b351SPierre Pronchery                $is_cert = 1;
171*4757b351SPierre Pronchery                last if ($is_crl);
172*4757b351SPierre Pronchery            } elsif ($hdr eq "X509 CRL") {
173*4757b351SPierre Pronchery                $is_crl = 1;
174*4757b351SPierre Pronchery                last if ($is_cert);
175*4757b351SPierre Pronchery            }
176*4757b351SPierre Pronchery        }
177*4757b351SPierre Pronchery    }
178*4757b351SPierre Pronchery    close $in;
179*4757b351SPierre Pronchery    return ($is_cert, $is_crl);
180*4757b351SPierre Pronchery}
181*4757b351SPierre Pronchery
182*4757b351SPierre Proncherysub compute_hash {
183*4757b351SPierre Pronchery    my $fh;
184*4757b351SPierre Pronchery    if ( $^O eq "VMS" ) {
185*4757b351SPierre Pronchery        # VMS uses the open through shell
186*4757b351SPierre Pronchery        # The file names are safe there and list form is unsupported
187*4757b351SPierre Pronchery        if (!open($fh, "-|", join(' ', @_))) {
188*4757b351SPierre Pronchery            print STDERR "Cannot compute hash on '$fname'\n";
189*4757b351SPierre Pronchery            return;
190*4757b351SPierre Pronchery        }
191*4757b351SPierre Pronchery    } else {
192*4757b351SPierre Pronchery        if (!open($fh, "-|", @_)) {
193*4757b351SPierre Pronchery            print STDERR "Cannot compute hash on '$fname'\n";
194*4757b351SPierre Pronchery            return;
195*4757b351SPierre Pronchery        }
196*4757b351SPierre Pronchery    }
197*4757b351SPierre Pronchery    return (<$fh>, <$fh>);
198*4757b351SPierre Pronchery}
199*4757b351SPierre Pronchery
200*4757b351SPierre Pronchery# Link a certificate to its subject name hash value, each hash is of
201*4757b351SPierre Pronchery# the form <hash>.<n> where n is an integer. If the hash value already exists
202*4757b351SPierre Pronchery# then we need to up the value of n, unless its a duplicate in which
203*4757b351SPierre Pronchery# case we skip the link. We check for duplicates by comparing the
204*4757b351SPierre Pronchery# certificate fingerprints
205*4757b351SPierre Pronchery
206*4757b351SPierre Proncherysub link_hash_cert {
207*4757b351SPierre Pronchery    link_hash($_[0], 'cert');
208*4757b351SPierre Pronchery}
209*4757b351SPierre Pronchery
210*4757b351SPierre Pronchery# Same as above except for a CRL. CRL links are of the form <hash>.r<n>
211*4757b351SPierre Pronchery
212*4757b351SPierre Proncherysub link_hash_crl {
213*4757b351SPierre Pronchery    link_hash($_[0], 'crl');
214*4757b351SPierre Pronchery}
215*4757b351SPierre Pronchery
216*4757b351SPierre Proncherysub link_hash {
217*4757b351SPierre Pronchery    my ($fname, $type) = @_;
218*4757b351SPierre Pronchery    my $is_cert = $type eq 'cert';
219*4757b351SPierre Pronchery
220*4757b351SPierre Pronchery    my ($hash, $fprint) = compute_hash($openssl,
221*4757b351SPierre Pronchery                                       $is_cert ? "x509" : "crl",
222*4757b351SPierre Pronchery                                       $is_cert ? $x509hash : $crlhash,
223*4757b351SPierre Pronchery                                       "-fingerprint", "-noout",
224*4757b351SPierre Pronchery                                       "-in", $fname);
225*4757b351SPierre Pronchery    chomp $hash;
226*4757b351SPierre Pronchery    $hash =~ s/^.*=// if !$is_cert;
227*4757b351SPierre Pronchery    chomp $fprint;
228*4757b351SPierre Pronchery    return if !$hash;
229*4757b351SPierre Pronchery    $fprint =~ s/^.*=//;
230*4757b351SPierre Pronchery    $fprint =~ tr/://d;
231*4757b351SPierre Pronchery    my $suffix = 0;
232*4757b351SPierre Pronchery    # Search for an unused hash filename
233*4757b351SPierre Pronchery    my $crlmark = $is_cert ? "" : "r";
234*4757b351SPierre Pronchery    while(exists $hashlist{"$hash.$crlmark$suffix"}) {
235*4757b351SPierre Pronchery        # Hash matches: if fingerprint matches its a duplicate cert
236*4757b351SPierre Pronchery        if ($hashlist{"$hash.$crlmark$suffix"} eq $fprint) {
237*4757b351SPierre Pronchery            my $what = $is_cert ? 'certificate' : 'CRL';
238*4757b351SPierre Pronchery            print STDERR "WARNING: Skipping duplicate $what $fname\n";
239*4757b351SPierre Pronchery            return;
240*4757b351SPierre Pronchery        }
241*4757b351SPierre Pronchery        $suffix++;
242*4757b351SPierre Pronchery    }
243*4757b351SPierre Pronchery    $hash .= ".$crlmark$suffix";
244*4757b351SPierre Pronchery    if ($symlink_exists) {
245*4757b351SPierre Pronchery        print "link $fname -> $hash\n" if $verbose;
246*4757b351SPierre Pronchery        symlink $fname, $hash || warn "Can't symlink, $!";
247*4757b351SPierre Pronchery    } else {
248*4757b351SPierre Pronchery        print "copy $fname -> $hash\n" if $verbose;
249*4757b351SPierre Pronchery        copy_file($fname, $hash);
250*4757b351SPierre Pronchery    }
251*4757b351SPierre Pronchery    $hashlist{$hash} = $fprint;
252*4757b351SPierre Pronchery}
253