#!/usr/bin/env perl -w my $package = caller; if (!(defined $package)) { my $retval = check_hashes(@ARGV); exit $retval; } 1; sub check_hashes { my @args = @_; my $change_dir = ""; my $check_program = "sha/fips_standalone_sha1"; my $verbose = 0; my $badfiles = 0; my $rebuild = 0; my $force_rewrite = 0; my $hash_file = "fipshashes.c"; my $recurse = 0; my @fingerprint_files; while (@args) { my $arg = $args[0]; if ($arg eq "-chdir") { shift @args; $change_dir = shift @args; } elsif ($arg eq "-rebuild") { shift @args; $rebuild = 1; } elsif ($arg eq "-verbose") { shift @args; $verbose = 1; } elsif ($arg eq "-force-rewrite") { shift @args; $force_rewrite = 1; } elsif ($arg eq "-hash_file") { shift @args; $hash_file = shift @args; } elsif ($arg eq "-recurse") { shift @args; $recurse = 1; } elsif ($arg eq "-program_path") { shift @args; $check_program = shift @args; } else { print STDERR "Unknown Option $arg"; return 1; } } chdir $change_dir if $change_dir ne ""; if ($recurse) { @fingerprint_files = ("fingerprint.sha1", <*/fingerprint.sha1>); } else { push @fingerprint_files, $hash_file; } foreach $fp (@fingerprint_files) { if (!open(IN, "$fp")) { print STDERR "Can't open file $fp"; return 1; } print STDERR "Opening Fingerprint file $fp\n" if $verbose; my $dir = $fp; $dir =~ s/[^\/]*$//; while () { chomp; if (!(($file, $hash) = /^\"HMAC-SHA1\((.*)\)\s*=\s*(\w*)\",$/)) { /^\"/ || next; print STDERR "FATAL: Invalid syntax in file $fp\n"; print STDERR "Line:\n$_\n"; fatal_error(); return 1; } if (!$rebuild && length($hash) != 40) { print STDERR "FATAL: Invalid hash length in $fp for file $file\n"; fatal_error(); return 1; } push @hashed_files, "$dir$file"; if (exists $hashes{"$dir$file"}) { print STDERR "FATAL: Duplicate Hash file $dir$file\n"; fatal_error(); return 1; } if (! -r "$dir$file") { print STDERR "FATAL: Can't access $dir$file\n"; fatal_error(); return 1; } $hashes{"$dir$file"} = $hash; } close IN; } @checked_hashes = `$check_program @hashed_files`; if ($? != 0) { print STDERR "Error running hash program $check_program\n"; fatal_error(); return 1; } if (@checked_hashes != @hashed_files) { print STDERR "FATAL: hash count incorrect\n"; fatal_error(); return 1; } foreach (@checked_hashes) { chomp; if (!(($file, $hash) = /^HMAC-SHA1\((.*)\)\s*=\s*(\w*)$/)) { print STDERR "FATAL: Invalid syntax in file $fp\n"; print STDERR "Line:\n$_\n"; fatal_error(); return 1; } if (length($hash) != 40) { print STDERR "FATAL: Invalid hash length for file $file\n"; fatal_error(); return 1; } if ($hash ne $hashes{$file}) { if ($rebuild) { print STDERR "Updating hash on file $file\n"; $hashes{$file} = $hash; } else { print STDERR "Hash check failed for file $file\n"; } $badfiles++; } elsif ($verbose) { print "Hash Check OK for $file\n";} } if ($badfiles && !$rebuild) { print STDERR "FATAL: hash mismatch on $badfiles files\n"; fatal_error(); return 1; } if ($badfiles || $force_rewrite) { print "Updating Hash file $hash_file\n"; if (!open(OUT, ">$hash_file")) { print STDERR "Error rewriting $hash_file"; return 1; } print OUT "const char * const FIPS_source_hashes[] = {\n"; foreach (@hashed_files) { print OUT "\"HMAC-SHA1($_)= $hashes{$_}\",\n"; } print OUT "};\n"; close OUT; } if (!$badfiles) { print "FIPS hash check successful\n"; } return 0; } sub fatal_error { print STDERR "*** Your source code does not match the FIPS validated source ***\n"; }