File modhash of Package mokutil.16584

#!/usr/bin/perl
# 
# Calculate the digest of the kernel module
# It will strip kernel modules signature before calculation.
# 
# Based on modsign-verify, written by Michal Marek
# Authors:
#	Gary Lin <GLin@suse.com>
#	Joey Lee <JLee@suse.com>
#

my $USAGE = "Usage: modhash [-v] [-q] [-d <digest algorithm>] <module>\n";

use strict;
use warnings;
use IPC::Open2;
use Getopt::Long;
use File::Temp qw(tempfile);

my $verbose = 1;
my $dgst = "sha256";
GetOptions(
	"d=s" => \$dgst,
	"q|quiet" => sub { $verbose-- if $verbose; },
	"v|verbose" => sub { $verbose++; },
	"h|help" => sub {
		print $USAGE;
		exit(0);
	}
) or die($USAGE);

sub _verbose {
	my $level = shift;

	return if $verbose < $level;
	print STDERR @_;
}

sub info    { _verbose(1, @_); }
sub verbose { _verbose(2, @_); }
sub debug   { _verbose(3, @_); }

if (@ARGV > 1) {
	print STDERR "Excess arguments\n";
	die($USAGE);
} elsif (@ARGV < 1) {
	print STDERR "No module supplied\n";
	die($USAGE);
}
my $module_name = shift(@ARGV);

if ($dgst ne "sha"    and $dgst ne "sha1"   and $dgst ne "sha256" and
    $dgst ne "sha384" and $dgst ne "sha512") {
	die("unsupported algorithm: $dgst");
}

#
# Function to read the contents of a file into a variable.
#
sub read_file($)
{
    my ($file) = @_;
    my $contents;
    my $len;

    open(FD, "<$file") || die $file;
    binmode FD;
    my @st = stat(FD);
    die $file if (!@st);
    $len = read(FD, $contents, $st[7]) || die $file;
    close(FD) || die $file;
    die "$file: Wanted length ", $st[7], ", got ", $len, "\n"
	if ($len != $st[7]);
    return $contents;
}

sub openssl_pipe($$) {
	my ($input, $cmd) = @_;
	my ($pid, $res);

	$pid = open2(*read_from, *write_to, $cmd) || die $cmd;
	binmode write_to;
	if (defined($input) && $input ne "") {
		print write_to $input || die "$cmd: $!";
	}
	close(write_to) || die "$cmd: $!";

	binmode read_from;
	read(read_from, $res, 4096) || die "$cmd: $!";
	close(read_from) || die "$cmd: $!";
	waitpid($pid, 0) || die;
	die "$cmd died: $?" if ($? >> 8);
	return $res;
}

my $module = read_file($module_name);
my $module_len = length($module);
my $magic_number = "~Module signature appended~\n";
my $magic_len = length($magic_number);
my $info_len = 12;

if ($module_len < $magic_len) {
	die "Module size too short\n";
}

sub eat
{
	my $length = shift;
	if ($module_len < $length) {
		die "Module size too short\n";
	}
	my $res = substr($module, -$length);
	$module = substr($module, 0, $module_len - $length);
	$module_len -= $length;
	return $res;
}

if (substr($module, -$magic_len) eq $magic_number) {
	$module = substr($module, 0, $module_len - $magic_len);
	$module_len -= $magic_len;
	my $info = eat($info_len);
	my ($algo, $hash, $id_type, $name_len, $key_len, $sig_len) =
		unpack("CCCCCxxxN", $info);
	my $signature = eat($sig_len);
	if ($id_type == 1) {
		if (unpack("n", $signature) == $sig_len - 2) {
			verbose ("signed module (X.509)\n");
		} else {
			die "Invalid signature format\n";
		}
		if ($algo != 1) {
			die "Unsupported signature algorithm\n";
		}
		$signature = substr($signature, 2);
		my $key_id = eat($key_len);
		my $name = eat($name_len);
	} elsif ($id_type == 2) {
		verbose ("signed module (PKCS#7)\n");
	}
} else {
	verbose ("unsigned module\n");
}

verbose("Hash algorithm: $dgst\n");

my $digest = openssl_pipe($module, "openssl dgst -$dgst");
$digest =~ s/\(stdin\)= //;

print "$module_name: $digest"
openSUSE Build Service is sponsored by