Fix rehash/c_rehash doc and behavior.

Both now warn once if directory isn't writeable.
Both now warn on file-write errors (multiple times).
Update manpage to describe both program and script correctly.

Reviewed-by: Richard Levitte <levitte@openssl.org>
This commit is contained in:
Rich Salz 2015-09-07 22:21:38 -04:00 committed by Rich Salz
parent 8c82de991b
commit ff2f6bb084
3 changed files with 55 additions and 35 deletions

View File

@ -313,6 +313,10 @@ static int do_dir(const char *dirname, enum Hash h)
const char *filename;
char *buf;
if (app_access(dirname, W_OK) < 0) {
BIO_printf(bio_err, "Skipping %s, can't write\n", dirname);
return 0;
}
buflen = strlen(dirname);
pathsep = (buflen && dirname[buflen - 1] == '/') ? "" : "/";
buflen += NAME_MAX + 2;

View File

@ -23,7 +23,8 @@ I<flags...>
=head1 DESCRIPTION
On some platforms, the OpenSSL B<rehash> command is available as
an external script called B<c_rehash>. They are functionally equivalent.
an external script called B<c_rehash>. They are functionally equivalent,
except for minor differences noted below.
B<rehash> scans directories and calculates a hash value of each
C<.pem>, C<.crt>, C<.cer>, or C<.crl>
@ -41,12 +42,13 @@ If that is not set then the default directory (installation-specific
but often B</usr/local/ssl/certs>) is processed.
In order for a directory to be processed, the user must have write
permissions on that directory, otherwise it will be skipped.
permissions on that directory, otherwise an error will be generated.
The links created are of the form C<HHHHHHHH.D>, where each B<H>
is a hexadecimal character and B<D> is a single decimal digit.
When processing a directory, B<rehash> will first remove all links
that have a name in that syntax. If you have links in that format
used for other purposes, they will be removed.
that have a name in that syntax, even if they are being used for some
other purpose.
To skip the removal step, use the B<-n> flag.
Hashes for CRL's look similar except the letter B<r> appears after
the period, like this: C<HHHHHHHH.rD>.
@ -57,9 +59,13 @@ full SHA-1 fingerprint. A warning will be displayed if a duplicate
is found.
A warning will also be displayed if there are files that
cannot be parsed as either a certificate or a CRL.
cannot be parsed as either a certificate or a CRL or if
more than one such object appears in the file.
The program uses the B<openssl> program to compute the hashes and
=head2 Script Configuration
The B<c_rehash> script
uses the B<openssl> program to compute the hashes and
fingerprints. If not found in the user's B<PATH>, then set the
B<OPENSSL> environment variable to the full pathname.
Any program can be used, it will be invoked as follows for either
@ -79,8 +85,8 @@ optionally prefixed with some text and an equals sign.
=item B<-old>
Use old-style hashing (MD5, as opposed to SHA-1) for generating
links for releases before 1.0.0. Note that current versions will
not use the old style.
links to be used for releases before 1.0.0.
Note that current versions will not use the old style.
=item B<-h>

View File

@ -54,24 +54,24 @@ if (defined(&Cwd::getcwd)) {
my $path_delim = ($pwd =~ /^[a-z]\:/i) ? ';' : ':';
$ENV{PATH} = "$prefix/bin" . ($ENV{PATH} ? $path_delim . $ENV{PATH} : "");
if(! -x $openssl) {
if (! -x $openssl) {
my $found = 0;
foreach (split /$path_delim/, $ENV{PATH}) {
if(-x "$_/$openssl") {
if (-x "$_/$openssl") {
$found = 1;
$openssl = "$_/$openssl";
last;
}
}
if($found == 0) {
if ($found == 0) {
print STDERR "c_rehash: rehashing skipped ('openssl' program not available)\n";
exit 0;
}
}
if(@ARGV) {
if (@ARGV) {
@dirlist = @ARGV;
} elsif($ENV{SSL_CERT_DIR}) {
} elsif ($ENV{SSL_CERT_DIR}) {
@dirlist = split /$path_delim/, $ENV{SSL_CERT_DIR};
} else {
$dirlist[0] = "$dir/certs";
@ -84,8 +84,12 @@ if (-d $dirlist[0]) {
}
foreach (@dirlist) {
if(-d $_ and -w $_) {
if (-d $_ ) {
if ( -w $_) {
hash_dir($_);
} else {
print "Skipping $_, can't write\n";
}
}
}
@ -99,21 +103,21 @@ sub hash_dir {
if ( $removelinks ) {
# Delete any existing symbolic links
foreach (grep {/^[\da-f]+\.r{0,1}\d+$/} @flist) {
if(-l $_) {
unlink $_;
if (-l $_) {
print "unlink $_" if $verbose;
unlink $_ || warn "Can't unlink $_, $!\n";
}
}
}
FILE: foreach $fname (grep {/\.(pem)|(crt)|(cer)|(crl)$/} @flist) {
# Check to see if certificates and/or CRLs present.
my ($cert, $crl) = check_file($fname);
if(!$cert && !$crl) {
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);
link_hash_cert($fname) if ($cert);
link_hash_crl($fname) if ($crl);
}
}
@ -122,14 +126,14 @@ sub check_file {
my $fname = $_[0];
open IN, $fname;
while(<IN>) {
if(/^-----BEGIN (.*)-----/) {
if (/^-----BEGIN (.*)-----/) {
my $hdr = $1;
if($hdr =~ /^(X509 |TRUSTED |)CERTIFICATE$/) {
if ($hdr =~ /^(X509 |TRUSTED |)CERTIFICATE$/) {
$is_cert = 1;
last if($is_crl);
} elsif($hdr eq "X509 CRL") {
last if ($is_crl);
} elsif ($hdr eq "X509 CRL") {
$is_crl = 1;
last if($is_cert);
last if ($is_cert);
}
}
}
@ -156,7 +160,7 @@ sub link_hash_cert {
# 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) {
if ($hashlist{"$hash.$suffix"} eq $fprint) {
print STDERR "WARNING: Skipping duplicate certificate $fname\n";
return;
}
@ -164,15 +168,21 @@ sub link_hash_cert {
}
$hash .= ".$suffix";
if ($symlink_exists) {
symlink $fname, $hash;
print "link $fname -> $hash\n" if $verbose;
symlink $fname, $hash || warn "Can't symlink, $!";
} else {
open IN,"<$fname" or die "can't open $fname for read";
open OUT,">$hash" or die "can't open $hash for write";
print OUT <IN>; # does the job for small text files
close OUT;
close IN;
print "copy $fname -> $hash\n" if $verbose;
if (open($in, "<", $fname)) {
if (open($out,">", $hash)) {
print $out $_ while (<$in>);
close $out;
} else {
warn "can't open $hash for write, $!";
}
close $in;
} else {
warn "can't open $fname for read, $!";
}
}
$hashlist{$hash} = $fprint;
}
@ -191,7 +201,7 @@ sub link_hash_crl {
# 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) {
if ($hashlist{"$hash.r$suffix"} eq $fprint) {
print STDERR "WARNING: Skipping duplicate CRL $fname\n";
return;
}
@ -199,12 +209,12 @@ sub link_hash_crl {
}
$hash .= ".r$suffix";
if ($symlink_exists) {
symlink $fname, $hash;
print "link $fname -> $hash\n" if $verbose;
symlink $fname, $hash || warn "Can't symlink, $!";
} else {
system ("cp", $fname, $hash);
print "cp $fname -> $hash\n" if $verbose;
system ("cp", $fname, $hash);
warn "Can't copy, $!" if ($? >> 8) != 0;
}
$hashlist{$hash} = $fprint;
}