Skip to content

Commit 7a9c027

Browse files
faramir-devmattcaswell
authored andcommitted
Fix file operations in c_rehash.
CVE-2022-2068 Reviewed-by: Matt Caswell <matt@openssl.org> Reviewed-by: Richard Levitte <levitte@openssl.org>
1 parent d633ef7 commit 7a9c027

File tree

1 file changed

+107
-102
lines changed

1 file changed

+107
-102
lines changed

Diff for: tools/c_rehash.in

+107-102
Original file line numberDiff line numberDiff line change
@@ -89,52 +89,78 @@ foreach (@dirlist) {
8989
}
9090
}
9191

92+
sub copy_file {
93+
my ($src_fname, $dst_fname) = @_;
94+
95+
if (open(my $in, "<", $src_fname)) {
96+
if (open(my $out, ">", $dst_fname)) {
97+
print $out $_ while (<$in>);
98+
close $out;
99+
} else {
100+
warn "Cannot open $dst_fname for write, $!";
101+
}
102+
close $in;
103+
} else {
104+
warn "Cannot open $src_fname for read, $!";
105+
}
106+
}
107+
92108
sub hash_dir {
93-
my %hashlist;
94-
print "Doing $_[0]\n";
95-
chdir $_[0];
96-
opendir(DIR, ".");
97-
my @flist = readdir(DIR);
98-
closedir DIR;
99-
if ( $removelinks ) {
100-
# Delete any existing symbolic links
101-
foreach (grep {/^[\da-f]+\.r{0,1}\d+$/} @flist) {
102-
if(-l $_) {
103-
unlink $_;
104-
print "unlink $_" if $verbose;
105-
}
106-
}
107-
}
108-
FILE: foreach $fname (grep {/\.(pem)|(crt)|(cer)|(crl)$/} @flist) {
109-
# Check to see if certificates and/or CRLs present.
110-
my ($cert, $crl) = check_file($fname);
111-
if(!$cert && !$crl) {
112-
print STDERR "WARNING: $fname does not contain a certificate or CRL: skipping\n";
113-
next;
114-
}
115-
link_hash_cert($fname) if($cert);
116-
link_hash_crl($fname) if($crl);
117-
}
109+
my $dir = shift;
110+
my %hashlist;
111+
112+
print "Doing $dir\n";
113+
114+
if (!chdir $dir) {
115+
print STDERR "WARNING: Cannot chdir to '$dir', $!\n";
116+
return;
117+
}
118+
119+
opendir(DIR, ".") || print STDERR "WARNING: Cannot opendir '.', $!\n";
120+
my @flist = sort readdir(DIR);
121+
closedir DIR;
122+
if ( $removelinks ) {
123+
# Delete any existing symbolic links
124+
foreach (grep {/^[\da-f]+\.r{0,1}\d+$/} @flist) {
125+
if (-l $_) {
126+
print "unlink $_\n" if $verbose;
127+
unlink $_ || warn "Can't unlink $_, $!\n";
128+
}
129+
}
130+
}
131+
FILE: foreach $fname (grep {/\.(pem)|(crt)|(cer)|(crl)$/} @flist) {
132+
# Check to see if certificates and/or CRLs present.
133+
my ($cert, $crl) = check_file($fname);
134+
if (!$cert && !$crl) {
135+
print STDERR "WARNING: $fname does not contain a certificate or CRL: skipping\n";
136+
next;
137+
}
138+
link_hash_cert($fname) if ($cert);
139+
link_hash_crl($fname) if ($crl);
140+
}
141+
142+
chdir $pwd;
118143
}
119144

120145
sub check_file {
121-
my ($is_cert, $is_crl) = (0,0);
122-
my $fname = $_[0];
123-
open IN, $fname;
124-
while(<IN>) {
125-
if(/^-----BEGIN (.*)-----/) {
126-
my $hdr = $1;
127-
if($hdr =~ /^(X509 |TRUSTED |)CERTIFICATE$/) {
128-
$is_cert = 1;
129-
last if($is_crl);
130-
} elsif($hdr eq "X509 CRL") {
131-
$is_crl = 1;
132-
last if($is_cert);
133-
}
134-
}
135-
}
136-
close IN;
137-
return ($is_cert, $is_crl);
146+
my ($is_cert, $is_crl) = (0,0);
147+
my $fname = $_[0];
148+
149+
open(my $in, "<", $fname);
150+
while(<$in>) {
151+
if (/^-----BEGIN (.*)-----/) {
152+
my $hdr = $1;
153+
if ($hdr =~ /^(X509 |TRUSTED |)CERTIFICATE$/) {
154+
$is_cert = 1;
155+
last if ($is_crl);
156+
} elsif ($hdr eq "X509 CRL") {
157+
$is_crl = 1;
158+
last if ($is_cert);
159+
}
160+
}
161+
}
162+
close $in;
163+
return ($is_cert, $is_crl);
138164
}
139165

140166
sub compute_hash {
@@ -162,70 +188,49 @@ sub compute_hash {
162188
# certificate fingerprints
163189

164190
sub link_hash_cert {
165-
my $fname = $_[0];
166-
my ($hash, $fprint) = compute_hash($openssl, "x509", $x509hash,
167-
"-fingerprint", "-noout",
168-
"-in", $fname);
169-
chomp $hash;
170-
chomp $fprint;
171-
return if !$hash;
172-
$fprint =~ s/^.*=//;
173-
$fprint =~ tr/://d;
174-
my $suffix = 0;
175-
# Search for an unused hash filename
176-
while(exists $hashlist{"$hash.$suffix"}) {
177-
# Hash matches: if fingerprint matches its a duplicate cert
178-
if($hashlist{"$hash.$suffix"} eq $fprint) {
179-
print STDERR "WARNING: Skipping duplicate certificate $fname\n";
180-
return;
181-
}
182-
$suffix++;
183-
}
184-
$hash .= ".$suffix";
185-
if ($symlink_exists) {
186-
symlink $fname, $hash;
187-
print "link $fname -> $hash\n" if $verbose;
188-
} else {
189-
open IN,"<$fname" or die "can't open $fname for read";
190-
open OUT,">$hash" or die "can't open $hash for write";
191-
print OUT <IN>; # does the job for small text files
192-
close OUT;
193-
close IN;
194-
print "copy $fname -> $hash\n" if $verbose;
195-
}
196-
$hashlist{$hash} = $fprint;
191+
link_hash($_[0], 'cert');
197192
}
198193

199194
# Same as above except for a CRL. CRL links are of the form <hash>.r<n>
200195

201196
sub link_hash_crl {
202-
my $fname = $_[0];
203-
my ($hash, $fprint) = compute_hash($openssl, "crl", $crlhash,
204-
"-fingerprint", "-noout",
205-
"-in", $fname);
206-
chomp $hash;
207-
chomp $fprint;
208-
return if !$hash;
209-
$fprint =~ s/^.*=//;
210-
$fprint =~ tr/://d;
211-
my $suffix = 0;
212-
# Search for an unused hash filename
213-
while(exists $hashlist{"$hash.r$suffix"}) {
214-
# Hash matches: if fingerprint matches its a duplicate cert
215-
if($hashlist{"$hash.r$suffix"} eq $fprint) {
216-
print STDERR "WARNING: Skipping duplicate CRL $fname\n";
217-
return;
218-
}
219-
$suffix++;
220-
}
221-
$hash .= ".r$suffix";
222-
if ($symlink_exists) {
223-
symlink $fname, $hash;
224-
print "link $fname -> $hash\n" if $verbose;
225-
} else {
226-
system ("cp", $fname, $hash);
227-
print "cp $fname -> $hash\n" if $verbose;
228-
}
229-
$hashlist{$hash} = $fprint;
197+
link_hash($_[0], 'crl');
198+
}
199+
200+
sub link_hash {
201+
my ($fname, $type) = @_;
202+
my $is_cert = $type eq 'cert';
203+
204+
my ($hash, $fprint) = compute_hash($openssl,
205+
$is_cert ? "x509" : "crl",
206+
$is_cert ? $x509hash : $crlhash,
207+
"-fingerprint", "-noout",
208+
"-in", $fname);
209+
chomp $hash;
210+
chomp $fprint;
211+
return if !$hash;
212+
$fprint =~ s/^.*=//;
213+
$fprint =~ tr/://d;
214+
my $suffix = 0;
215+
# Search for an unused hash filename
216+
my $crlmark = $is_cert ? "" : "r";
217+
while(exists $hashlist{"$hash.$crlmark$suffix"}) {
218+
# Hash matches: if fingerprint matches its a duplicate cert
219+
if ($hashlist{"$hash.$crlmark$suffix"} eq $fprint) {
220+
my $what = $is_cert ? 'certificate' : 'CRL';
221+
print STDERR "WARNING: Skipping duplicate $what $fname\n";
222+
return;
223+
}
224+
$suffix++;
225+
}
226+
$hash .= ".$crlmark$suffix";
227+
if ($symlink_exists) {
228+
print "link $fname -> $hash\n" if $verbose;
229+
symlink $fname, $hash || warn "Can't symlink, $!";
230+
} else {
231+
print "copy $fname -> $hash\n" if $verbose;
232+
copy_file($fname, $hash);
233+
}
234+
$hashlist{$hash} = $fprint;
230235
}
231236

0 commit comments

Comments
 (0)