1#!/usr/bin/env perl 2# 3# extract-mod-sig <part> <module-file> 4# 5# Reads the module file and writes out some or all of the signature 6# section to stdout. Part is the bit to be written and is one of: 7# 8# -0: The unsigned module, no signature data at all 9# -a: All of the signature data, including magic number 10# -d: Just the descriptor values as a sequence of numbers 11# -n: Just the signer's name 12# -k: Just the key ID 13# -s: Just the crypto signature or PKCS#7 message 14# 15use warnings; 16use strict; 17 18die "Format: $0 -[0adnks] module-file >out\n" 19 if ($#ARGV != 1); 20 21my $part = $ARGV[0]; 22my $modfile = $ARGV[1]; 23 24my $magic_number = "~Module signature appended~\n"; 25 26# 27# Read the module contents 28# 29open FD, "<$modfile" || die $modfile; 30binmode(FD); 31my @st = stat(FD); 32die "$modfile" unless (@st); 33my $buf = ""; 34my $len = sysread(FD, $buf, $st[7]); 35die "$modfile" unless (defined($len)); 36die "Short read on $modfile\n" unless ($len == $st[7]); 37close(FD) || die $modfile; 38 39print STDERR "Read ", $len, " bytes from module file\n"; 40 41die "The file is too short to have a sig magic number and descriptor\n" 42 if ($len < 12 + length($magic_number)); 43 44# 45# Check for the magic number and extract the information block 46# 47my $p = $len - length($magic_number); 48my $raw_magic = substr($buf, $p); 49 50die "Magic number not found at $len\n" 51 if ($raw_magic ne $magic_number); 52print STDERR "Found magic number at $len\n"; 53 54$p -= 12; 55my $raw_info = substr($buf, $p, 12); 56 57my @info = unpack("CCCCCxxxN", $raw_info); 58my ($algo, $hash, $id_type, $name_len, $kid_len, $sig_len) = @info; 59 60if ($id_type == 0) { 61 print STDERR "Found PGP key identifier\n"; 62} elsif ($id_type == 1) { 63 print STDERR "Found X.509 cert identifier\n"; 64} elsif ($id_type == 2) { 65 print STDERR "Found PKCS#7/CMS encapsulation\n"; 66} else { 67 print STDERR "Found unsupported identifier type $id_type\n"; 68} 69 70# 71# Extract the three pieces of info data 72# 73die "Insufficient name+kid+sig data in file\n" 74 unless ($p >= $name_len + $kid_len + $sig_len); 75 76$p -= $sig_len; 77my $raw_sig = substr($buf, $p, $sig_len); 78$p -= $kid_len; 79my $raw_kid = substr($buf, $p, $kid_len); 80$p -= $name_len; 81my $raw_name = substr($buf, $p, $name_len); 82 83my $module_len = $p; 84 85if ($sig_len > 0) { 86 print STDERR "Found $sig_len bytes of signature ["; 87 my $n = $sig_len > 16 ? 16 : $sig_len; 88 foreach my $i (unpack("C" x $n, substr($raw_sig, 0, $n))) { 89 printf STDERR "%02x", $i; 90 } 91 print STDERR "]\n"; 92} 93 94if ($kid_len > 0) { 95 print STDERR "Found $kid_len bytes of key identifier ["; 96 my $n = $kid_len > 16 ? 16 : $kid_len; 97 foreach my $i (unpack("C" x $n, substr($raw_kid, 0, $n))) { 98 printf STDERR "%02x", $i; 99 } 100 print STDERR "]\n"; 101} 102 103if ($name_len > 0) { 104 print STDERR "Found $name_len bytes of signer's name [$raw_name]\n"; 105} 106 107# 108# Produce the requested output 109# 110if ($part eq "-0") { 111 # The unsigned module, no signature data at all 112 binmode(STDOUT); 113 print substr($buf, 0, $module_len); 114} elsif ($part eq "-a") { 115 # All of the signature data, including magic number 116 binmode(STDOUT); 117 print substr($buf, $module_len); 118} elsif ($part eq "-d") { 119 # Just the descriptor values as a sequence of numbers 120 print join(" ", @info), "\n"; 121} elsif ($part eq "-n") { 122 # Just the signer's name 123 print STDERR "No signer's name for PKCS#7 message type sig\n" 124 if ($id_type == 2); 125 binmode(STDOUT); 126 print $raw_name; 127} elsif ($part eq "-k") { 128 # Just the key identifier 129 print STDERR "No key ID for PKCS#7 message type sig\n" 130 if ($id_type == 2); 131 binmode(STDOUT); 132 print $raw_kid; 133} elsif ($part eq "-s") { 134 # Just the crypto signature or PKCS#7 message 135 binmode(STDOUT); 136 print $raw_sig; 137} 138