extract-module-sig.pl 3.6 KB

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