Name: Module Signature Signing Script Signed-off-by: Rusty Russell Status: Booted on 2.6.9-rc3 Depends: Module/module-signing-core.patch.gz Simple script to actually sign the modules. Index: linux-2.6.10-rc1-bk10-Module/scripts/modsign.sh =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.10-rc1-bk10-Module/scripts/modsign.sh 2004-11-01 22:34:22.158190968 +1100 @@ -0,0 +1,21 @@ +#! /bin/sh + +set -x + +set -e +SIGNATURE_LEN=`scripts/modsig --size` +OBJDUMP=$1 +shift + +for f; do + dd if=/dev/zero of=$f.signature bs=1 count=$SIGNATURE_LEN 2>/dev/null + objcopy --add-section module_sig=$f.signature $f $f.presigned + gpg --no-greeting -o - -b $f.presigned | scripts/modsig > $f.signature + # Use dd: objcopy might change something else which effects the sig. + OFFSET=0x`$OBJDUMP -h $f.presigned | awk '/module_sig/ { print $6 }'` + dd if=$f.presigned bs=1 count=$(($OFFSET)) > $f.signed + cat $f.signature >> $f.signed + dd if=$f.presigned bs=1 skip=$(($OFFSET + $SIGNATURE_LEN)) >> $f.signed + rm -f $f.presigned $f.signature + mv $f.signed $f +done Index: linux-2.6.10-rc1-bk10-Module/scripts/Makefile =================================================================== --- linux-2.6.10-rc1-bk10-Module.orig/scripts/Makefile 2004-10-19 14:34:27.000000000 +1000 +++ linux-2.6.10-rc1-bk10-Module/scripts/Makefile 2004-11-01 22:34:22.130195224 +1100 @@ -12,6 +12,7 @@ hostprogs-$(CONFIG_VT) += conmakehash hostprogs-$(CONFIG_PROM_CONSOLE) += conmakehash hostprogs-$(CONFIG_IKCONFIG) += bin2c +hostprogs-$(CONFIG_MODULE_SIG) += modsig always := $(hostprogs-y) Index: linux-2.6.10-rc1-bk10-Module/Makefile =================================================================== --- linux-2.6.10-rc1-bk10-Module.orig/Makefile 2004-11-01 10:17:58.000000000 +1100 +++ linux-2.6.10-rc1-bk10-Module/Makefile 2004-11-01 22:34:22.102199480 +1100 @@ -854,6 +854,11 @@ .PHONY: modules_prepare modules_prepare: prepare-all scripts +# Target to sign modules +.PHONY: modules_sign +modules_sign: + $(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.modinst modules_sign + # Target to install modules .PHONY: modules_install modules_install: _modinst_ _modinst_post Index: linux-2.6.10-rc1-bk10-Module/scripts/modsig.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-2.6.10-rc1-bk10-Module/scripts/modsig.c 2004-11-01 22:34:22.157191120 +1100 @@ -0,0 +1,256 @@ +/* Given a gpg DSA signature, extract the core and output it in the + * format the kernel expects. + * + * Copyright (C) 2004 Rusty Russell IBM Corporation. + * + * Crypto code (ie. most of this): + * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#define DSA_BITS 160 +#define PUBKEY_ALGO_DSA 17 +#define DIGEST_ALGO_SHA1 2 +#define PKT_SIGNATURE 2 + +#define BYTES(bits) (((bits)+CHAR_BIT-1)/CHAR_BIT) + +struct signature +{ + char version[4]; /* 0x00 00 00 01 */ + char r[BYTES(DSA_BITS)]; + char s[BYTES(DSA_BITS)]; +} __attribute__((packed)); + +static void parse_err(const uint8_t *datap, const uint8_t *endp, + const char *fmt, ...) +__attribute__((noreturn, format(printf, 3, 4))); + +static void parse_err(const uint8_t *datap, const uint8_t *endp, + const char *fmt, ...) +{ + char *str; + + if (datap >= endp) + str = strdup("signature too short"); + else { + va_list arglist; + va_start(arglist, fmt); + vasprintf(&str, fmt, arglist); + va_end(arglist); + } + + fprintf(stderr, "modsig: FATAL: %s\n", str); + free(str); + exit(1); +} + +/* Morally equivalent to mpi_read_from_buffer */ +static const uint8_t *read_sig_bits(const uint8_t *datap, const uint8_t *endp, + char bits[20]) +{ + unsigned int nbits, i; + + nbits = datap[0] << 8 | datap[1]; + if (nbits > DSA_BITS) + parse_err(datap, endp, "Too many bits (%u) in signature\n", + nbits); + + datap += 2; + + for (i = 0; i < BYTES(nbits); i++) + bits[i] = datap[i]; + datap += i; + + /* Leading zeroes would have been truncated. */ + if (i < BYTES(DSA_BITS)) { + unsigned int extra = BYTES(DSA_BITS) - i; + memmove(bits + extra, bits, i); + memset(bits, 0, extra); + } + return datap; +} + +static void ksign_parse_signature(const uint8_t *datap, const uint8_t *endp, + struct signature *sig) +{ + int version, is_v4 = 0; + + version = *datap++; + switch (version) { + case 4: + is_v4 = 1; + case 3: + case 2: + break; + default: + parse_err(datap, endp, + "signature packet with unknown version %d\n", + version); + } + + if (!is_v4) + datap++; /* ignore md5 length */ + + /* Ignore sig_class */ + datap++; + if (!is_v4) { + /* Ignore timestamp, keyid */ + datap += 4; + datap += 8; + } + + if (*datap++ != PUBKEY_ALGO_DSA) + parse_err(datap, endp, "non-DSA signature\n"); + + if (*datap++ != DIGEST_ALGO_SHA1) + parse_err(datap, endp, "non-SHA1 signature\n"); + + if (is_v4) { /* read subpackets */ + unsigned int n; + + n = (datap[0] << 8) | datap[1]; + datap += 2; + if (n > 10000) + parse_err(datap, endp, "hashed data too long\n"); + + if (n) { + /* Explicit check here, since could be huge. */ + if ((size_t)(endp - datap) < n) + parse_err(datap, endp, "\n"); + + datap += n; + } + } + + /* Skip digest_start */ + datap += 2; + + if (is_v4) { + /* Ignore keyid */ + datap += 8; + } + + datap = read_sig_bits(datap, endp, sig->r); + datap = read_sig_bits(datap, endp, sig->s); + + if (datap != endp) + parse_err(datap, endp, "Signature %zi longer then expected\n", + endp - datap); +} + +static void ksign_parse(const uint8_t *datap, const uint8_t *endp, + struct signature *sig) +{ + int ctb, pkttype, lenuint8_ts; + unsigned long pktlen; + uint8_t hdr[8]; + int hdrlen; + + ctb = *datap++; + + hdrlen = 0; + hdr[hdrlen++] = ctb; + if (!(ctb & 0x80)) + parse_err(datap, endp, + "invalid packet (ctb=%02x)\n", ctb); + + pktlen = 0; + if (ctb & 0x40) { + int c; + pkttype = ctb & 0x3f; + c = *datap++; + hdr[hdrlen++] = c; + + if (c < 192) + pktlen = c; + else if (c < 224) { + pktlen = (c - 192) * 256; + c = *datap++; + hdr[hdrlen++] = c; + pktlen += c + 192; + } else if (c == 255) { + pktlen = (hdr[hdrlen++] = *datap++ << 24 ); + pktlen |= (hdr[hdrlen++] = *datap++ << 16 ); + pktlen |= (hdr[hdrlen++] = *datap++ << 8 ); + pktlen |= (hdr[hdrlen++] = *datap++ << 0 ); + } else + pktlen = 0;/* to indicate partial length */ + } else { + pkttype = (ctb >> 2) & 0xf; + lenuint8_ts = ((ctb & 3) == 3) ? 0 : (1 << (ctb & 3)); + if (!lenuint8_ts) + pktlen = 0; /* don't know the value */ + else { + for( ; lenuint8_ts; lenuint8_ts-- ) { + pktlen <<= 8; + pktlen |= hdr[hdrlen++] = *datap++; + } + } + } + + /* deal with the next packet appropriately */ + if (pkttype != PKT_SIGNATURE) + parse_err(datap, endp, "Unknown packet type %i\n", pkttype); + + if (datap + pktlen != endp) + parse_err(datap, endp, "Packet length %zi expected %li\n", + endp - datap, pktlen); + ksign_parse_signature(datap, datap + pktlen, sig); +} + +int main(int argc, char *argv[]) +{ + char *gpgsig; + int gpg_size = 0, gpg_max = 1024, ret; + struct signature sig; + + if (argc == 2 && strcmp(argv[1], "--size") == 0) { + printf("%zu\n", sizeof(struct signature)); + exit(0); + } + + if (argc != 1) { + fprintf(stderr, + "Usage: modsig [--size]\n" + " modsig\n" + "First usage prints out the size of the signature.\n" + "Second usage filters a gpg signature into what the" + " kernel uses.\n"); + exit(1); + } + + gpgsig = malloc(gpg_max); + + while ((ret = read(0, gpgsig + gpg_size, gpg_max - gpg_size)) > 0) { + gpg_size += ret; + if (gpg_size == gpg_max) { + gpg_max *= 2; + gpgsig = realloc(gpgsig, gpg_max); + } + } + + sig.version[0] = 0; + sig.version[1] = 0; + sig.version[2] = 0; + sig.version[3] = 1; + + ksign_parse(gpgsig, gpgsig + gpg_size, &sig); + + write(1, &sig, sizeof(sig)); + exit(0); +} Index: linux-2.6.10-rc1-bk10-Module/scripts/Makefile.modinst =================================================================== --- linux-2.6.10-rc1-bk10-Module.orig/scripts/Makefile.modinst 2004-11-01 10:18:15.000000000 +1100 +++ linux-2.6.10-rc1-bk10-Module/scripts/Makefile.modinst 2004-11-01 22:34:22.156191272 +1100 @@ -26,3 +26,6 @@ $(modules): $(call cmd,modules_install,$(modinst_dir)) + +modules_sign: + sh scripts/modsign.sh $(OBJDUMP) $(modules)