summaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rw-r--r--scripts/Makefile.asm-generic2
-rw-r--r--scripts/Makefile.fwinst4
-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
7 files changed, 421 insertions, 474 deletions
diff --git a/scripts/Makefile.asm-generic b/scripts/Makefile.asm-generic
index 40caf3c..d17e0ea 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.fwinst b/scripts/Makefile.fwinst
index c3f69ae2..4d908d1 100644
--- a/scripts/Makefile.fwinst
+++ b/scripts/Makefile.fwinst
@@ -27,7 +27,7 @@ endif
installed-mod-fw := $(addprefix $(INSTALL_FW_PATH)/,$(mod-fw))
installed-fw := $(addprefix $(INSTALL_FW_PATH)/,$(fw-shipped-all))
-installed-fw-dirs := $(sort $(dir $(installed-fw))) $(INSTALL_FW_PATH)/.
+installed-fw-dirs := $(sort $(dir $(installed-fw))) $(INSTALL_FW_PATH)/./
# Workaround for make < 3.81, where .SECONDEXPANSION doesn't work.
PHONY += $(INSTALL_FW_PATH)/$$(%) install-all-dirs
@@ -42,7 +42,7 @@ quiet_cmd_install = INSTALL $(subst $(srctree)/,,$@)
$(installed-fw-dirs):
$(call cmd,mkdir)
-$(installed-fw): $(INSTALL_FW_PATH)/%: $(obj)/% | $$(dir $(INSTALL_FW_PATH)/%)
+$(installed-fw): $(INSTALL_FW_PATH)/%: $(obj)/% | $(INSTALL_FW_PATH)/$$(dir %)
$(call cmd,install)
PHONY += __fw_install __fw_modinst FORCE
diff --git a/scripts/Makefile.modinst b/scripts/Makefile.modinst
index 3d13d3a..dda4b2b 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 0020891..a1cb022 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 d501c86..3e42a07 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 e58e34e..87ca59d 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 c8e91a4..0000000
--- 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];
OpenPOWER on IntegriCloud