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