summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2012-11-26 09:23:57 +1100
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2012-11-26 09:23:57 +1100
commit2a859ab07b6ab66f4134c4fffc341398bd3d328c (patch)
treec5e7eaf3bffbc18feb326940e39794328d98dc07 /scripts
parentcedddd812a79a4fda3885a15711aee3de78c4a24 (diff)
parente716e014384688d1a50d1aa5213ee74748c6d4e0 (diff)
Merge branch 'merge' into next
Merge my own merge branch to get various fixes from there and upstream, especially the hvc console tty refcouting fixes which which testing is quite a bit harder...
Diffstat (limited to 'scripts')
-rw-r--r--scripts/Makefile.asm-generic2
-rw-r--r--scripts/Makefile.modinst2
-rw-r--r--scripts/Makefile.modpost77
-rw-r--r--scripts/dtc/dtc.h44
-rwxr-xr-x[-rw-r--r--]scripts/sign-file498
-rwxr-xr-xscripts/x509keyid268
6 files changed, 419 insertions, 472 deletions
diff --git a/scripts/Makefile.asm-generic b/scripts/Makefile.asm-generic
index 40caf3c26cd5..d17e0ea911ed 100644
--- a/scripts/Makefile.asm-generic
+++ b/scripts/Makefile.asm-generic
@@ -5,7 +5,7 @@
# and for each file listed in this file with generic-y creates
# a small wrapper file in $(obj) (arch/$(SRCARCH)/include/generated/asm)
-kbuild-file := $(srctree)/arch/$(SRCARCH)/include/asm/Kbuild
+kbuild-file := $(srctree)/arch/$(SRCARCH)/include/$(src)/Kbuild
-include $(kbuild-file)
include scripts/Kbuild.include
diff --git a/scripts/Makefile.modinst b/scripts/Makefile.modinst
index 3d13d3a3edfe..dda4b2b61927 100644
--- a/scripts/Makefile.modinst
+++ b/scripts/Makefile.modinst
@@ -17,7 +17,7 @@ __modinst: $(modules)
@:
quiet_cmd_modules_install = INSTALL $@
- cmd_modules_install = mkdir -p $(2); cp $@ $(2) ; $(mod_strip_cmd) $(2)/$(notdir $@)
+ cmd_modules_install = mkdir -p $(2); cp $@ $(2) ; $(mod_strip_cmd) $(2)/$(notdir $@) ; $(mod_sign_cmd) $(2)/$(notdir $@)
# Modules built outside the kernel source tree go into extra by default
INSTALL_MOD_DIR ?= extra
diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost
index 002089141df4..a1cb0222ebe6 100644
--- a/scripts/Makefile.modpost
+++ b/scripts/Makefile.modpost
@@ -14,8 +14,7 @@
# 3) create one <module>.mod.c file pr. module
# 4) create one Module.symvers file with CRC for all exported symbols
# 5) compile all <module>.mod.c files
-# 6) final link of the module to a <module.ko> (or <module.unsigned>) file
-# 7) signs the modules to a <module.ko> file
+# 6) final link of the module to a <module.ko> file
# Step 3 is used to place certain information in the module's ELF
# section, including information such as:
@@ -33,8 +32,6 @@
# Step 4 is solely used to allow module versioning in external modules,
# where the CRC of each module is retrieved from the Module.symvers file.
-# Step 7 is dependent on CONFIG_MODULE_SIG being enabled.
-
# KBUILD_MODPOST_WARN can be set to avoid error out in case of undefined
# symbols in the final module linking stage
# KBUILD_MODPOST_NOFINAL can be set to skip the final link of modules.
@@ -119,7 +116,6 @@ $(modules:.ko=.mod.o): %.mod.o: %.mod.c FORCE
targets += $(modules:.ko=.mod.o)
# Step 6), final link of the modules
-ifneq ($(CONFIG_MODULE_SIG),y)
quiet_cmd_ld_ko_o = LD [M] $@
cmd_ld_ko_o = $(LD) -r $(LDFLAGS) \
$(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \
@@ -129,78 +125,7 @@ $(modules): %.ko :%.o %.mod.o FORCE
$(call if_changed,ld_ko_o)
targets += $(modules)
-else
-quiet_cmd_ld_ko_unsigned_o = LD [M] $@
- cmd_ld_ko_unsigned_o = \
- $(LD) -r $(LDFLAGS) \
- $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \
- -o $@ $(filter-out FORCE,$^) \
- $(if $(AFTER_LINK),; $(AFTER_LINK))
-
-$(modules:.ko=.ko.unsigned): %.ko.unsigned :%.o %.mod.o FORCE
- $(call if_changed,ld_ko_unsigned_o)
-
-targets += $(modules:.ko=.ko.unsigned)
-
-# Step 7), sign the modules
-MODSECKEY = ./signing_key.priv
-MODPUBKEY = ./signing_key.x509
-
-ifeq ($(wildcard $(MODSECKEY))+$(wildcard $(MODPUBKEY)),$(MODSECKEY)+$(MODPUBKEY))
-ifeq ($(KBUILD_SRC),)
- # no O= is being used
- SCRIPTS_DIR := scripts
-else
- SCRIPTS_DIR := $(KBUILD_SRC)/scripts
-endif
-SIGN_MODULES := 1
-else
-SIGN_MODULES := 0
-endif
-
-# only sign if it's an in-tree module
-ifneq ($(KBUILD_EXTMOD),)
-SIGN_MODULES := 0
-endif
-# We strip the module as best we can - note that using both strip and eu-strip
-# results in a smaller module than using either alone.
-EU_STRIP = $(shell which eu-strip || echo true)
-
-quiet_cmd_sign_ko_stripped_ko_unsigned = STRIP [M] $@
- cmd_sign_ko_stripped_ko_unsigned = \
- cp $< $@ && \
- strip -x -g $@ && \
- $(EU_STRIP) $@
-
-ifeq ($(SIGN_MODULES),1)
-
-quiet_cmd_genkeyid = GENKEYID $@
- cmd_genkeyid = \
- perl $(SCRIPTS_DIR)/x509keyid $< $<.signer $<.keyid
-
-%.signer %.keyid: %
- $(call if_changed,genkeyid)
-
-KEYRING_DEP := $(MODSECKEY) $(MODPUBKEY) $(MODPUBKEY).signer $(MODPUBKEY).keyid
-quiet_cmd_sign_ko_ko_stripped = SIGN [M] $@
- cmd_sign_ko_ko_stripped = \
- sh $(SCRIPTS_DIR)/sign-file $(MODSECKEY) $(MODPUBKEY) $< $@
-else
-KEYRING_DEP :=
-quiet_cmd_sign_ko_ko_unsigned = NO SIGN [M] $@
- cmd_sign_ko_ko_unsigned = \
- cp $< $@
-endif
-
-$(modules): %.ko :%.ko.stripped $(KEYRING_DEP) FORCE
- $(call if_changed,sign_ko_ko_stripped)
-
-$(patsubst %.ko,%.ko.stripped,$(modules)): %.ko.stripped :%.ko.unsigned FORCE
- $(call if_changed,sign_ko_stripped_ko_unsigned)
-
-targets += $(modules)
-endif
# Add FORCE to the prequisites of a target to force it to be always rebuilt.
# ---------------------------------------------------------------------------
diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h
index d501c8605f26..3e42a071070e 100644
--- a/scripts/dtc/dtc.h
+++ b/scripts/dtc/dtc.h
@@ -161,51 +161,27 @@ struct node {
struct label *labels;
};
-static inline struct label *for_each_label_next(struct label *l)
-{
- do {
- l = l->next;
- } while (l && l->deleted);
-
- return l;
-}
-
-#define for_each_label(l0, l) \
- for ((l) = (l0); (l); (l) = for_each_label_next(l))
-
#define for_each_label_withdel(l0, l) \
for ((l) = (l0); (l); (l) = (l)->next)
-static inline struct property *for_each_property_next(struct property *p)
-{
- do {
- p = p->next;
- } while (p && p->deleted);
-
- return p;
-}
-
-#define for_each_property(n, p) \
- for ((p) = (n)->proplist; (p); (p) = for_each_property_next(p))
+#define for_each_label(l0, l) \
+ for_each_label_withdel(l0, l) \
+ if (!(l)->deleted)
#define for_each_property_withdel(n, p) \
for ((p) = (n)->proplist; (p); (p) = (p)->next)
-static inline struct node *for_each_child_next(struct node *c)
-{
- do {
- c = c->next_sibling;
- } while (c && c->deleted);
-
- return c;
-}
-
-#define for_each_child(n, c) \
- for ((c) = (n)->children; (c); (c) = for_each_child_next(c))
+#define for_each_property(n, p) \
+ for_each_property_withdel(n, p) \
+ if (!(p)->deleted)
#define for_each_child_withdel(n, c) \
for ((c) = (n)->children; (c); (c) = (c)->next_sibling)
+#define for_each_child(n, c) \
+ for_each_child_withdel(n, c) \
+ if (!(c)->deleted)
+
void add_label(struct label **labels, char *label);
void delete_labels(struct label **labels);
diff --git a/scripts/sign-file b/scripts/sign-file
index e58e34e50ac5..87ca59d36e7e 100644..100755
--- a/scripts/sign-file
+++ b/scripts/sign-file
@@ -1,115 +1,429 @@
-#!/bin/sh
+#!/usr/bin/perl -w
#
# Sign a module file using the given key.
#
-# Format: sign-file <key> <x509> <src-file> <dst-file>
-#
-
-scripts=`dirname $0`
-
-CONFIG_MODULE_SIG_SHA512=y
-if [ -r .config ]
-then
- . ./.config
-fi
-
-key="$1"
-x509="$2"
-src="$3"
-dst="$4"
-
-if [ ! -r "$key" ]
-then
- echo "Can't read private key" >&2
- exit 2
-fi
-
-if [ ! -r "$x509" ]
-then
- echo "Can't read X.509 certificate" >&2
- exit 2
-fi
-if [ ! -r "$x509.signer" ]
-then
- echo "Can't read Signer name" >&2
- exit 2;
-fi
-if [ ! -r "$x509.keyid" ]
-then
- echo "Can't read Key identifier" >&2
- exit 2;
-fi
+# Format:
+#
+# ./scripts/sign-file [-v] <key> <x509> <module> [<dest>]
+#
+#
+use strict;
+use FileHandle;
+use IPC::Open2;
+
+my $verbose = 0;
+if ($#ARGV >= 0 && $ARGV[0] eq "-v") {
+ $verbose = 1;
+ shift;
+}
+
+die "Format: ./scripts/sign-file [-v] <key> <x509> <module> [<dest>]\n"
+ if ($#ARGV != 2 && $#ARGV != 3);
+
+my $private_key = $ARGV[0];
+my $x509 = $ARGV[1];
+my $module = $ARGV[2];
+my $dest = ($#ARGV == 3) ? $ARGV[3] : $ARGV[2] . "~";
+
+die "Can't read private key\n" unless (-r $private_key);
+die "Can't read X.509 certificate\n" unless (-r $x509);
+die "Can't read module\n" unless (-r $module);
+
+#
+# Read the kernel configuration
+#
+my %config = (
+ CONFIG_MODULE_SIG_SHA512 => 1
+ );
+
+if (-r ".config") {
+ open(FD, "<.config") || die ".config";
+ while (<FD>) {
+ if ($_ =~ /^(CONFIG_.*)=[ym]/) {
+ $config{$1} = 1;
+ }
+ }
+ close(FD);
+}
+
+#
+# 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;
+}
+
+###############################################################################
+#
+# First of all, we have to parse the X.509 certificate to find certain details
+# about it.
+#
+# We read the DER-encoded X509 certificate and parse it to extract the Subject
+# name and Subject Key Identifier. Theis provides the data we need to build
+# the certificate identifier.
+#
+# The signer's name part of the identifier is fabricated from the commonName,
+# the organizationName or the emailAddress components of the X.509 subject
+# name.
+#
+# The subject key ID is used to select which of that signer's certificates
+# we're intending to use to sign the module.
+#
+###############################################################################
+my $x509_certificate = read_file($x509);
+
+my $UNIV = 0 << 6;
+my $APPL = 1 << 6;
+my $CONT = 2 << 6;
+my $PRIV = 3 << 6;
+
+my $CONS = 0x20;
+
+my $BOOLEAN = 0x01;
+my $INTEGER = 0x02;
+my $BIT_STRING = 0x03;
+my $OCTET_STRING = 0x04;
+my $NULL = 0x05;
+my $OBJ_ID = 0x06;
+my $UTF8String = 0x0c;
+my $SEQUENCE = 0x10;
+my $SET = 0x11;
+my $UTCTime = 0x17;
+my $GeneralizedTime = 0x18;
+
+my %OIDs = (
+ pack("CCC", 85, 4, 3) => "commonName",
+ pack("CCC", 85, 4, 6) => "countryName",
+ pack("CCC", 85, 4, 10) => "organizationName",
+ pack("CCC", 85, 4, 11) => "organizationUnitName",
+ pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 1) => "rsaEncryption",
+ pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 5) => "sha1WithRSAEncryption",
+ pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 9, 1) => "emailAddress",
+ pack("CCC", 85, 29, 35) => "authorityKeyIdentifier",
+ pack("CCC", 85, 29, 14) => "subjectKeyIdentifier",
+ pack("CCC", 85, 29, 19) => "basicConstraints"
+);
+
+###############################################################################
+#
+# Extract an ASN.1 element from a string and return information about it.
+#
+###############################################################################
+sub asn1_extract($$@)
+{
+ my ($cursor, $expected_tag, $optional) = @_;
+
+ return [ -1 ]
+ if ($cursor->[1] == 0 && $optional);
+
+ die $x509, ": ", $cursor->[0], ": ASN.1 data underrun (elem ", $cursor->[1], ")\n"
+ if ($cursor->[1] < 2);
+
+ my ($tag, $len) = unpack("CC", substr(${$cursor->[2]}, $cursor->[0], 2));
+
+ if ($expected_tag != -1 && $tag != $expected_tag) {
+ return [ -1 ]
+ if ($optional);
+ die $x509, ": ", $cursor->[0], ": ASN.1 unexpected tag (", $tag,
+ " not ", $expected_tag, ")\n";
+ }
+
+ $cursor->[0] += 2;
+ $cursor->[1] -= 2;
+
+ die $x509, ": ", $cursor->[0], ": ASN.1 long tag\n"
+ if (($tag & 0x1f) == 0x1f);
+ die $x509, ": ", $cursor->[0], ": ASN.1 indefinite length\n"
+ if ($len == 0x80);
+
+ if ($len > 0x80) {
+ my $l = $len - 0x80;
+ die $x509, ": ", $cursor->[0], ": ASN.1 data underrun (len len $l)\n"
+ if ($cursor->[1] < $l);
+
+ if ($l == 0x1) {
+ $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1));
+ } elsif ($l = 0x2) {
+ $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0], 2));
+ } elsif ($l = 0x3) {
+ $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1)) << 16;
+ $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0] + 1, 2));
+ } elsif ($l = 0x4) {
+ $len = unpack("N", substr(${$cursor->[2]}, $cursor->[0], 4));
+ } else {
+ die $x509, ": ", $cursor->[0], ": ASN.1 element too long (", $l, ")\n";
+ }
+
+ $cursor->[0] += $l;
+ $cursor->[1] -= $l;
+ }
+
+ die $x509, ": ", $cursor->[0], ": ASN.1 data underrun (", $len, ")\n"
+ if ($cursor->[1] < $len);
+
+ my $ret = [ $tag, [ $cursor->[0], $len, $cursor->[2] ] ];
+ $cursor->[0] += $len;
+ $cursor->[1] -= $len;
+
+ return $ret;
+}
+
+###############################################################################
+#
+# Retrieve the data referred to by a cursor
+#
+###############################################################################
+sub asn1_retrieve($)
+{
+ my ($cursor) = @_;
+ my ($offset, $len, $data) = @$cursor;
+ return substr($$data, $offset, $len);
+}
+
+###############################################################################
+#
+# Roughly parse the X.509 certificate
+#
+###############################################################################
+my $cursor = [ 0, length($x509_certificate), \$x509_certificate ];
+
+my $cert = asn1_extract($cursor, $UNIV | $CONS | $SEQUENCE);
+my $tbs = asn1_extract($cert->[1], $UNIV | $CONS | $SEQUENCE);
+my $version = asn1_extract($tbs->[1], $CONT | $CONS | 0, 1);
+my $serial_number = asn1_extract($tbs->[1], $UNIV | $INTEGER);
+my $sig_type = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
+my $issuer = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
+my $validity = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
+my $subject = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
+my $key = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
+my $issuer_uid = asn1_extract($tbs->[1], $CONT | $CONS | 1, 1);
+my $subject_uid = asn1_extract($tbs->[1], $CONT | $CONS | 2, 1);
+my $extension_list = asn1_extract($tbs->[1], $CONT | $CONS | 3, 1);
+
+my $subject_key_id = ();
+my $authority_key_id = ();
+
+#
+# Parse the extension list
+#
+if ($extension_list->[0] != -1) {
+ my $extensions = asn1_extract($extension_list->[1], $UNIV | $CONS | $SEQUENCE);
+
+ while ($extensions->[1]->[1] > 0) {
+ my $ext = asn1_extract($extensions->[1], $UNIV | $CONS | $SEQUENCE);
+ my $x_oid = asn1_extract($ext->[1], $UNIV | $OBJ_ID);
+ my $x_crit = asn1_extract($ext->[1], $UNIV | $BOOLEAN, 1);
+ my $x_val = asn1_extract($ext->[1], $UNIV | $OCTET_STRING);
+
+ my $raw_oid = asn1_retrieve($x_oid->[1]);
+ next if (!exists($OIDs{$raw_oid}));
+ my $x_type = $OIDs{$raw_oid};
+
+ my $raw_value = asn1_retrieve($x_val->[1]);
+
+ if ($x_type eq "subjectKeyIdentifier") {
+ my $vcursor = [ 0, length($raw_value), \$raw_value ];
+
+ $subject_key_id = asn1_extract($vcursor, $UNIV | $OCTET_STRING);
+ }
+ }
+}
+
+###############################################################################
+#
+# Determine what we're going to use as the signer's name. In order of
+# preference, take one of: commonName, organizationName or emailAddress.
+#
+###############################################################################
+my $org = "";
+my $cn = "";
+my $email = "";
+
+while ($subject->[1]->[1] > 0) {
+ my $rdn = asn1_extract($subject->[1], $UNIV | $CONS | $SET);
+ my $attr = asn1_extract($rdn->[1], $UNIV | $CONS | $SEQUENCE);
+ my $n_oid = asn1_extract($attr->[1], $UNIV | $OBJ_ID);
+ my $n_val = asn1_extract($attr->[1], -1);
+
+ my $raw_oid = asn1_retrieve($n_oid->[1]);
+ next if (!exists($OIDs{$raw_oid}));
+ my $n_type = $OIDs{$raw_oid};
+
+ my $raw_value = asn1_retrieve($n_val->[1]);
+
+ if ($n_type eq "organizationName") {
+ $org = $raw_value;
+ } elsif ($n_type eq "commonName") {
+ $cn = $raw_value;
+ } elsif ($n_type eq "emailAddress") {
+ $email = $raw_value;
+ }
+}
+
+my $signers_name = $email;
+
+if ($org && $cn) {
+ # Don't use the organizationName if the commonName repeats it
+ if (length($org) <= length($cn) &&
+ substr($cn, 0, length($org)) eq $org) {
+ $signers_name = $cn;
+ goto got_id_name;
+ }
+
+ # Or a signifcant chunk of it
+ if (length($org) >= 7 &&
+ length($cn) >= 7 &&
+ substr($cn, 0, 7) eq substr($org, 0, 7)) {
+ $signers_name = $cn;
+ goto got_id_name;
+ }
+
+ $signers_name = $org . ": " . $cn;
+} elsif ($org) {
+ $signers_name = $org;
+} elsif ($cn) {
+ $signers_name = $cn;
+}
+
+got_id_name:
+
+die $x509, ": ", "X.509: Couldn't find the Subject Key Identifier extension\n"
+ if (!$subject_key_id);
+
+my $key_identifier = asn1_retrieve($subject_key_id->[1]);
+
+###############################################################################
+#
+# Create and attach the module signature
+#
+###############################################################################
#
# Signature parameters
#
-algo=1 # Public-key crypto algorithm: RSA
-hash= # Digest algorithm
-id_type=1 # Identifier type: X.509
+my $algo = 1; # Public-key crypto algorithm: RSA
+my $hash = 0; # Digest algorithm
+my $id_type = 1; # Identifier type: X.509
#
# Digest the data
#
-dgst=
-if [ "$CONFIG_MODULE_SIG_SHA1" = "y" ]
-then
- prologue="0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14"
- dgst=-sha1
- hash=2
-elif [ "$CONFIG_MODULE_SIG_SHA224" = "y" ]
-then
- prologue="0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1C"
- dgst=-sha224
- hash=7
-elif [ "$CONFIG_MODULE_SIG_SHA256" = "y" ]
-then
- prologue="0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20"
- dgst=-sha256
- hash=4
-elif [ "$CONFIG_MODULE_SIG_SHA384" = "y" ]
-then
- prologue="0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30"
- dgst=-sha384
- hash=5
-elif [ "$CONFIG_MODULE_SIG_SHA512" = "y" ]
-then
- prologue="0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40"
- dgst=-sha512
- hash=6
-else
- echo "$0: Can't determine hash algorithm" >&2
- exit 2
-fi
-
-(
-perl -e "binmode STDOUT; print pack(\"C*\", $prologue)" || exit $?
-openssl dgst $dgst -binary $src || exit $?
-) >$src.dig || exit $?
+my ($dgst, $prologue) = ();
+if (exists $config{"CONFIG_MODULE_SIG_SHA1"}) {
+ $prologue = pack("C*",
+ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
+ 0x2B, 0x0E, 0x03, 0x02, 0x1A,
+ 0x05, 0x00, 0x04, 0x14);
+ $dgst = "-sha1";
+ $hash = 2;
+} elsif (exists $config{"CONFIG_MODULE_SIG_SHA224"}) {
+ $prologue = pack("C*",
+ 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09,
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04,
+ 0x05, 0x00, 0x04, 0x1C);
+ $dgst = "-sha224";
+ $hash = 7;
+} elsif (exists $config{"CONFIG_MODULE_SIG_SHA256"}) {
+ $prologue = pack("C*",
+ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09,
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
+ 0x05, 0x00, 0x04, 0x20);
+ $dgst = "-sha256";
+ $hash = 4;
+} elsif (exists $config{"CONFIG_MODULE_SIG_SHA384"}) {
+ $prologue = pack("C*",
+ 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09,
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02,
+ 0x05, 0x00, 0x04, 0x30);
+ $dgst = "-sha384";
+ $hash = 5;
+} elsif (exists $config{"CONFIG_MODULE_SIG_SHA512"}) {
+ $prologue = pack("C*",
+ 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09,
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
+ 0x05, 0x00, 0x04, 0x40);
+ $dgst = "-sha512";
+ $hash = 6;
+} else {
+ die "Can't determine hash algorithm";
+}
+
+#
+# Generate the digest and read from openssl's stdout
+#
+my $digest;
+$digest = readpipe("openssl dgst $dgst -binary $module") || die "openssl dgst";
#
# Generate the binary signature, which will be just the integer that comprises
# the signature with no metadata attached.
#
-openssl rsautl -sign -inkey $key -keyform PEM -in $src.dig -out $src.sig || exit $?
-signerlen=`stat -c %s $x509.signer`
-keyidlen=`stat -c %s $x509.keyid`
-siglen=`stat -c %s $src.sig`
+my $pid;
+$pid = open2(*read_from, *write_to,
+ "openssl rsautl -sign -inkey $private_key -keyform PEM") ||
+ die "openssl rsautl";
+binmode write_to;
+print write_to $prologue . $digest || die "pipe to openssl rsautl";
+close(write_to) || die "pipe to openssl rsautl";
+
+binmode read_from;
+my $signature;
+read(read_from, $signature, 4096) || die "pipe from openssl rsautl";
+close(read_from) || die "pipe from openssl rsautl";
+$signature = pack("n", length($signature)) . $signature,
+
+waitpid($pid, 0) || die;
+die "openssl rsautl died: $?" if ($? >> 8);
#
# Build the signed binary
#
-(
- cat $src || exit $?
- echo '~Module signature appended~' || exit $?
- cat $x509.signer $x509.keyid || exit $?
+my $unsigned_module = read_file($module);
+
+my $magic_number = "~Module signature appended~\n";
+
+my $info = pack("CCCCCxxxN",
+ $algo, $hash, $id_type,
+ length($signers_name),
+ length($key_identifier),
+ length($signature));
- # Preface each signature integer with a 2-byte BE length
- perl -e "binmode STDOUT; print pack(\"n\", $siglen)" || exit $?
- cat $src.sig || exit $?
+if ($verbose) {
+ print "Size of unsigned module: ", length($unsigned_module), "\n";
+ print "Size of signer's name : ", length($signers_name), "\n";
+ print "Size of key identifier : ", length($key_identifier), "\n";
+ print "Size of signature : ", length($signature), "\n";
+ print "Size of informaton : ", length($info), "\n";
+ print "Size of magic number : ", length($magic_number), "\n";
+ print "Signer's name : '", $signers_name, "'\n";
+ print "Digest : $dgst\n";
+}
- # Generate the information block
- perl -e "binmode STDOUT; print pack(\"CCCCCxxxN\", $algo, $hash, $id_type, $signerlen, $keyidlen, $siglen + 2)" || exit $?
-) >$dst~ || exit $?
+open(FD, ">$dest") || die $dest;
+binmode FD;
+print FD
+ $unsigned_module,
+ $signers_name,
+ $key_identifier,
+ $signature,
+ $info,
+ $magic_number
+ ;
+close FD || die $dest;
-# Permit in-place signing
-mv $dst~ $dst || exit $?
+if ($#ARGV != 3) {
+ rename($dest, $module) || die $module;
+}
diff --git a/scripts/x509keyid b/scripts/x509keyid
deleted file mode 100755
index c8e91a4af385..000000000000
--- a/scripts/x509keyid
+++ /dev/null
@@ -1,268 +0,0 @@
-#!/usr/bin/perl -w
-#
-# Generate an identifier from an X.509 certificate that can be placed in a
-# module signature to indentify the key to use.
-#
-# Format:
-#
-# ./scripts/x509keyid <x509-cert> <signer's-name> <key-id>
-#
-# We read the DER-encoded X509 certificate and parse it to extract the Subject
-# name and Subject Key Identifier. The provide the data we need to build the
-# certificate identifier.
-#
-# The signer's name part of the identifier is fabricated from the commonName,
-# the organizationName or the emailAddress components of the X.509 subject
-# name and written to the second named file.
-#
-# The subject key ID to select which of that signer's certificates we're
-# intending to use to sign the module is written to the third named file.
-#
-use strict;
-
-my $raw_data;
-
-die "Need three filenames\n" if ($#ARGV != 2);
-
-my $src = $ARGV[0];
-
-open(FD, "<$src") || die $src;
-binmode FD;
-my @st = stat(FD);
-die $src if (!@st);
-read(FD, $raw_data, $st[7]) || die $src;
-close(FD);
-
-my $UNIV = 0 << 6;
-my $APPL = 1 << 6;
-my $CONT = 2 << 6;
-my $PRIV = 3 << 6;
-
-my $CONS = 0x20;
-
-my $BOOLEAN = 0x01;
-my $INTEGER = 0x02;
-my $BIT_STRING = 0x03;
-my $OCTET_STRING = 0x04;
-my $NULL = 0x05;
-my $OBJ_ID = 0x06;
-my $UTF8String = 0x0c;
-my $SEQUENCE = 0x10;
-my $SET = 0x11;
-my $UTCTime = 0x17;
-my $GeneralizedTime = 0x18;
-
-my %OIDs = (
- pack("CCC", 85, 4, 3) => "commonName",
- pack("CCC", 85, 4, 6) => "countryName",
- pack("CCC", 85, 4, 10) => "organizationName",
- pack("CCC", 85, 4, 11) => "organizationUnitName",
- pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 1) => "rsaEncryption",
- pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 1, 5) => "sha1WithRSAEncryption",
- pack("CCCCCCCCC", 42, 134, 72, 134, 247, 13, 1, 9, 1) => "emailAddress",
- pack("CCC", 85, 29, 35) => "authorityKeyIdentifier",
- pack("CCC", 85, 29, 14) => "subjectKeyIdentifier",
- pack("CCC", 85, 29, 19) => "basicConstraints"
-);
-
-###############################################################################
-#
-# Extract an ASN.1 element from a string and return information about it.
-#
-###############################################################################
-sub asn1_extract($$@)
-{
- my ($cursor, $expected_tag, $optional) = @_;
-
- return [ -1 ]
- if ($cursor->[1] == 0 && $optional);
-
- die $src, ": ", $cursor->[0], ": ASN.1 data underrun (elem ", $cursor->[1], ")\n"
- if ($cursor->[1] < 2);
-
- my ($tag, $len) = unpack("CC", substr(${$cursor->[2]}, $cursor->[0], 2));
-
- if ($expected_tag != -1 && $tag != $expected_tag) {
- return [ -1 ]
- if ($optional);
- die $src, ": ", $cursor->[0], ": ASN.1 unexpected tag (", $tag,
- " not ", $expected_tag, ")\n";
- }
-
- $cursor->[0] += 2;
- $cursor->[1] -= 2;
-
- die $src, ": ", $cursor->[0], ": ASN.1 long tag\n"
- if (($tag & 0x1f) == 0x1f);
- die $src, ": ", $cursor->[0], ": ASN.1 indefinite length\n"
- if ($len == 0x80);
-
- if ($len > 0x80) {
- my $l = $len - 0x80;
- die $src, ": ", $cursor->[0], ": ASN.1 data underrun (len len $l)\n"
- if ($cursor->[1] < $l);
-
- if ($l == 0x1) {
- $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1));
- } elsif ($l = 0x2) {
- $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0], 2));
- } elsif ($l = 0x3) {
- $len = unpack("C", substr(${$cursor->[2]}, $cursor->[0], 1)) << 16;
- $len = unpack("n", substr(${$cursor->[2]}, $cursor->[0] + 1, 2));
- } elsif ($l = 0x4) {
- $len = unpack("N", substr(${$cursor->[2]}, $cursor->[0], 4));
- } else {
- die $src, ": ", $cursor->[0], ": ASN.1 element too long (", $l, ")\n";
- }
-
- $cursor->[0] += $l;
- $cursor->[1] -= $l;
- }
-
- die $src, ": ", $cursor->[0], ": ASN.1 data underrun (", $len, ")\n"
- if ($cursor->[1] < $len);
-
- my $ret = [ $tag, [ $cursor->[0], $len, $cursor->[2] ] ];
- $cursor->[0] += $len;
- $cursor->[1] -= $len;
-
- return $ret;
-}
-
-###############################################################################
-#
-# Retrieve the data referred to by a cursor
-#
-###############################################################################
-sub asn1_retrieve($)
-{
- my ($cursor) = @_;
- my ($offset, $len, $data) = @$cursor;
- return substr($$data, $offset, $len);
-}
-
-###############################################################################
-#
-# Roughly parse the X.509 certificate
-#
-###############################################################################
-my $cursor = [ 0, length($raw_data), \$raw_data ];
-
-my $cert = asn1_extract($cursor, $UNIV | $CONS | $SEQUENCE);
-my $tbs = asn1_extract($cert->[1], $UNIV | $CONS | $SEQUENCE);
-my $version = asn1_extract($tbs->[1], $CONT | $CONS | 0, 1);
-my $serial_number = asn1_extract($tbs->[1], $UNIV | $INTEGER);
-my $sig_type = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
-my $issuer = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
-my $validity = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
-my $subject = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
-my $key = asn1_extract($tbs->[1], $UNIV | $CONS | $SEQUENCE);
-my $issuer_uid = asn1_extract($tbs->[1], $CONT | $CONS | 1, 1);
-my $subject_uid = asn1_extract($tbs->[1], $CONT | $CONS | 2, 1);
-my $extension_list = asn1_extract($tbs->[1], $CONT | $CONS | 3, 1);
-
-my $subject_key_id = ();
-my $authority_key_id = ();
-
-#
-# Parse the extension list
-#
-if ($extension_list->[0] != -1) {
- my $extensions = asn1_extract($extension_list->[1], $UNIV | $CONS | $SEQUENCE);
-
- while ($extensions->[1]->[1] > 0) {
- my $ext = asn1_extract($extensions->[1], $UNIV | $CONS | $SEQUENCE);
- my $x_oid = asn1_extract($ext->[1], $UNIV | $OBJ_ID);
- my $x_crit = asn1_extract($ext->[1], $UNIV | $BOOLEAN, 1);
- my $x_val = asn1_extract($ext->[1], $UNIV | $OCTET_STRING);
-
- my $raw_oid = asn1_retrieve($x_oid->[1]);
- next if (!exists($OIDs{$raw_oid}));
- my $x_type = $OIDs{$raw_oid};
-
- my $raw_value = asn1_retrieve($x_val->[1]);
-
- if ($x_type eq "subjectKeyIdentifier") {
- my $vcursor = [ 0, length($raw_value), \$raw_value ];
-
- $subject_key_id = asn1_extract($vcursor, $UNIV | $OCTET_STRING);
- }
- }
-}
-
-###############################################################################
-#
-# Determine what we're going to use as the signer's name. In order of
-# preference, take one of: commonName, organizationName or emailAddress.
-#
-###############################################################################
-my $org = "";
-my $cn = "";
-my $email = "";
-
-while ($subject->[1]->[1] > 0) {
- my $rdn = asn1_extract($subject->[1], $UNIV | $CONS | $SET);
- my $attr = asn1_extract($rdn->[1], $UNIV | $CONS | $SEQUENCE);
- my $n_oid = asn1_extract($attr->[1], $UNIV | $OBJ_ID);
- my $n_val = asn1_extract($attr->[1], -1);
-
- my $raw_oid = asn1_retrieve($n_oid->[1]);
- next if (!exists($OIDs{$raw_oid}));
- my $n_type = $OIDs{$raw_oid};
-
- my $raw_value = asn1_retrieve($n_val->[1]);
-
- if ($n_type eq "organizationName") {
- $org = $raw_value;
- } elsif ($n_type eq "commonName") {
- $cn = $raw_value;
- } elsif ($n_type eq "emailAddress") {
- $email = $raw_value;
- }
-}
-
-my $id_name = $email;
-
-if ($org && $cn) {
- # Don't use the organizationName if the commonName repeats it
- if (length($org) <= length($cn) &&
- substr($cn, 0, length($org)) eq $org) {
- $id_name = $cn;
- goto got_id_name;
- }
-
- # Or a signifcant chunk of it
- if (length($org) >= 7 &&
- length($cn) >= 7 &&
- substr($cn, 0, 7) eq substr($org, 0, 7)) {
- $id_name = $cn;
- goto got_id_name;
- }
-
- $id_name = $org . ": " . $cn;
-} elsif ($org) {
- $id_name = $org;
-} elsif ($cn) {
- $id_name = $cn;
-}
-
-got_id_name:
-
-###############################################################################
-#
-# Output the signer's name and the key identifier that we're going to include
-# in module signatures.
-#
-###############################################################################
-die $src, ": ", "X.509: Couldn't find the Subject Key Identifier extension\n"
- if (!$subject_key_id);
-
-my $id_key_id = asn1_retrieve($subject_key_id->[1]);
-
-open(OUTFD, ">$ARGV[1]") || die $ARGV[1];
-print OUTFD $id_name;
-close OUTFD || die $ARGV[1];
-
-open(OUTFD, ">$ARGV[2]") || die $ARGV[2];
-print OUTFD $id_key_id;
-close OUTFD || die $ARGV[2];