extract-module-sig.pl 3.7 KB

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