Skip to content

Commit 9639817

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 20af01d commit 9639817

File tree

1 file changed

+107
-109
lines changed

1 file changed

+107
-109
lines changed

tools/c_rehash.in

Lines changed: 107 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -104,52 +104,78 @@ foreach (@dirlist) {
104104
}
105105
exit($errorcount);
106106

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

135160
sub check_file {
136-
my ($is_cert, $is_crl) = (0,0);
137-
my $fname = $_[0];
138-
open IN, $fname;
139-
while(<IN>) {
140-
if (/^-----BEGIN (.*)-----/) {
141-
my $hdr = $1;
142-
if ($hdr =~ /^(X509 |TRUSTED |)CERTIFICATE$/) {
143-
$is_cert = 1;
144-
last if ($is_crl);
145-
} elsif ($hdr eq "X509 CRL") {
146-
$is_crl = 1;
147-
last if ($is_cert);
148-
}
149-
}
150-
}
151-
close IN;
152-
return ($is_cert, $is_crl);
161+
my ($is_cert, $is_crl) = (0,0);
162+
my $fname = $_[0];
163+
164+
open(my $in, "<", $fname);
165+
while(<$in>) {
166+
if (/^-----BEGIN (.*)-----/) {
167+
my $hdr = $1;
168+
if ($hdr =~ /^(X509 |TRUSTED |)CERTIFICATE$/) {
169+
$is_cert = 1;
170+
last if ($is_crl);
171+
} elsif ($hdr eq "X509 CRL") {
172+
$is_crl = 1;
173+
last if ($is_cert);
174+
}
175+
}
176+
}
177+
close $in;
178+
return ($is_cert, $is_crl);
153179
}
154180

155181
sub compute_hash {
@@ -177,76 +203,48 @@ sub compute_hash {
177203
# certificate fingerprints
178204

179205
sub link_hash_cert {
180-
my $fname = $_[0];
181-
my ($hash, $fprint) = compute_hash($openssl, "x509", $x509hash,
182-
"-fingerprint", "-noout",
183-
"-in", $fname);
184-
chomp $hash;
185-
chomp $fprint;
186-
return if !$hash;
187-
$fprint =~ s/^.*=//;
188-
$fprint =~ tr/://d;
189-
my $suffix = 0;
190-
# Search for an unused hash filename
191-
while(exists $hashlist{"$hash.$suffix"}) {
192-
# Hash matches: if fingerprint matches its a duplicate cert
193-
if ($hashlist{"$hash.$suffix"} eq $fprint) {
194-
print STDERR "WARNING: Skipping duplicate certificate $fname\n";
195-
return;
196-
}
197-
$suffix++;
198-
}
199-
$hash .= ".$suffix";
200-
if ($symlink_exists) {
201-
print "link $fname -> $hash\n" if $verbose;
202-
symlink $fname, $hash || warn "Can't symlink, $!";
203-
} else {
204-
print "copy $fname -> $hash\n" if $verbose;
205-
if (open($in, "<", $fname)) {
206-
if (open($out,">", $hash)) {
207-
print $out $_ while (<$in>);
208-
close $out;
209-
} else {
210-
warn "can't open $hash for write, $!";
211-
}
212-
close $in;
213-
} else {
214-
warn "can't open $fname for read, $!";
215-
}
216-
}
217-
$hashlist{$hash} = $fprint;
206+
link_hash($_[0], 'cert');
218207
}
219208

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

222211
sub link_hash_crl {
223-
my $fname = $_[0];
224-
my ($hash, $fprint) = compute_hash($openssl, "crl", $crlhash,
225-
"-fingerprint", "-noout",
226-
"-in", $fname);
227-
chomp $hash;
228-
chomp $fprint;
229-
return if !$hash;
230-
$fprint =~ s/^.*=//;
231-
$fprint =~ tr/://d;
232-
my $suffix = 0;
233-
# Search for an unused hash filename
234-
while(exists $hashlist{"$hash.r$suffix"}) {
235-
# Hash matches: if fingerprint matches its a duplicate cert
236-
if ($hashlist{"$hash.r$suffix"} eq $fprint) {
237-
print STDERR "WARNING: Skipping duplicate CRL $fname\n";
238-
return;
239-
}
240-
$suffix++;
241-
}
242-
$hash .= ".r$suffix";
243-
if ($symlink_exists) {
244-
print "link $fname -> $hash\n" if $verbose;
245-
symlink $fname, $hash || warn "Can't symlink, $!";
246-
} else {
247-
print "cp $fname -> $hash\n" if $verbose;
248-
system ("cp", $fname, $hash);
249-
warn "Can't copy, $!" if ($? >> 8) != 0;
250-
}
251-
$hashlist{$hash} = $fprint;
212+
link_hash($_[0], 'crl');
213+
}
214+
215+
sub link_hash {
216+
my ($fname, $type) = @_;
217+
my $is_cert = $type eq 'cert';
218+
219+
my ($hash, $fprint) = compute_hash($openssl,
220+
$is_cert ? "x509" : "crl",
221+
$is_cert ? $x509hash : $crlhash,
222+
"-fingerprint", "-noout",
223+
"-in", $fname);
224+
chomp $hash;
225+
chomp $fprint;
226+
return if !$hash;
227+
$fprint =~ s/^.*=//;
228+
$fprint =~ tr/://d;
229+
my $suffix = 0;
230+
# Search for an unused hash filename
231+
my $crlmark = $is_cert ? "" : "r";
232+
while(exists $hashlist{"$hash.$crlmark$suffix"}) {
233+
# Hash matches: if fingerprint matches its a duplicate cert
234+
if ($hashlist{"$hash.$crlmark$suffix"} eq $fprint) {
235+
my $what = $is_cert ? 'certificate' : 'CRL';
236+
print STDERR "WARNING: Skipping duplicate $what $fname\n";
237+
return;
238+
}
239+
$suffix++;
240+
}
241+
$hash .= ".$crlmark$suffix";
242+
if ($symlink_exists) {
243+
print "link $fname -> $hash\n" if $verbose;
244+
symlink $fname, $hash || warn "Can't symlink, $!";
245+
} else {
246+
print "copy $fname -> $hash\n" if $verbose;
247+
copy_file($fname, $hash);
248+
}
249+
$hashlist{$hash} = $fprint;
252250
}

0 commit comments

Comments
 (0)