From c9543f88db49a8b9c9b51701a136785568b559bca7bd395f9791a4bd7779764a Mon Sep 17 00:00:00 2001 From: Marcus Meissner Date: Fri, 14 Jun 2013 21:59:33 +0000 Subject: [PATCH] Accepting request 178980 from home:michal-m:branches:Base:System - Put debuginfo packages to %_topdir/OTHER (bnc#824971). - Version 10 - Add modsign-repackage tool to repackage RPMs outside the buildservice OBS-URL: https://build.opensuse.org/request/show/178980 OBS-URL: https://build.opensuse.org/package/show/Base:System/pesign-obs-integration?expand=0&rev=18 --- kernel-sign-file | 66 ++++++++++----- modsign-repackage | 142 +++++++++++++++++++++++++++++++++ pesign-gen-repackage-spec | 52 +++++++++++- pesign-obs-integration.changes | 11 +++ pesign-obs-integration.spec | 6 +- pesign-repackage.spec.in | 5 +- 6 files changed, 255 insertions(+), 27 deletions(-) create mode 100644 modsign-repackage diff --git a/kernel-sign-file b/kernel-sign-file index ce705e2..2c78c9a 100644 --- a/kernel-sign-file +++ b/kernel-sign-file @@ -68,6 +68,23 @@ sub read_file($) return $contents; } +sub openssl_pipe($$) { + my ($input, $cmd) = @_; + my ($pid, $res); + + $pid = open2(*read_from, *write_to, $cmd) || die $cmd; + binmode write_to; + print write_to $input || die "pipe to $cmd"; + close(write_to) || die "pipe to $cmd"; + + binmode read_from; + read(read_from, $res, 4096) || die "pipe from $cmd"; + close(read_from) || die "pipe from $cmd"; + waitpid($pid, 0) || die; + die "$cmd died: $?" if ($? >> 8); + return $res; +} + ############################################################################### # # First of all, we have to parse the X.509 certificate to find certain details @@ -358,6 +375,26 @@ if ($dgst eq "sha1") { die "Unknown hash algorithm: $dgst\n"; } +my $unsigned_module = read_file($module); + +my $magic_number = $sign_fw ? + "~Linux firmware signature~\n" : + "~Module signature appended~\n"; +my $magic_len = length($magic_number); +my $info_len = 12; + +# Truncate existing signarure, if any +if (!$sign_fw && substr($unsigned_module, -$magic_len) eq $magic_number) { + my $info = substr($unsigned_module, -$magic_len - $info_len, $info_len); + my ($name_len, $key_len, $sig_len) = unpack("xxxCCxxxN", $info); + my $subtract = $name_len + $key_len + $sig_len + $info_len + $magic_len; + if ($subtract > length($unsigned_module)) { + die "$module: Existing signature is malformed\n"; + } + $unsigned_module = substr($unsigned_module, 0, + length($unsigned_module) - $subtract); +} + my $signature; if ($signature_file) { $signature = read_file($signature_file); @@ -365,43 +402,30 @@ if ($signature_file) { # # Generate the digest and read from openssl's stdout # - my $digest; - $digest = readpipe("openssl dgst -$dgst -binary $module") || die "openssl dgst"; + my $digest = openssl_pipe($unsigned_module, + "openssl dgst -$dgst -binary"); # # Generate the binary signature, which will be just the integer that # comprises the signature with no metadata attached. # - 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; - read(read_from, $signature, 4096) || die "pipe from openssl rsautl"; - close(read_from) || die "pipe from openssl rsautl"; - waitpid($pid, 0) || die; - die "openssl rsautl died: $?" if ($? >> 8); + $signature = openssl_pipe($prologue . $digest, + "openssl rsautl -sign -inkey $private_key -keyform PEM"); } $signature = pack("n", length($signature)) . $signature, # # Build the signed binary # -my $unsigned_module = read_file($module); - -my $magic_number = $sign_fw ? - "~Linux firmware signature~\n" : - "~Module signature appended~\n"; - my $info = pack("CCCCCxxxN", $algo, $hash, $id_type, length($signers_name), length($key_identifier), length($signature)); +# Make sure that $info_len value used above matches reality +if (length($info) != $info_len) { + die "Signature info size changed ($info_len -> @{[length($info)]}"; +} if ($verbose) { print "Size of unsigned $mode_name: ", length($unsigned_module), "\n"; diff --git a/modsign-repackage b/modsign-repackage new file mode 100644 index 0000000..e28d6d6 --- /dev/null +++ b/modsign-repackage @@ -0,0 +1,142 @@ +#!/bin/bash +# Script to sign kernel modules and create new RPM packages with these +# modules. Uses pesign-gen-repackage-spec for the repackaging. +# +# Copyright (c) 2013 SUSE Linux Products GmbH, Nuernberg, Germany. +# +# 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. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + +USAGE="$0 --key --certificate rpm ..." + +options=`getopt -o hk:c: --long help,key:,certificate: -- "$@"` +if test $? -ne 0; then + echo "$USAGE" >&2 + exit 1 +fi +eval set -- "$options" +key= +cert= +while :; do + case "$1" in + -k|--key) + key=$2 + shift 2 + ;; + -c|--certificate) + cert=$2 + shift 2 + ;; + -h|--help) + echo "$USAGE" + exit + ;; + --) + shift + break + esac +done +if test -z "$key" -o -z "$cert"; then + echo "$0: The --key and --certificate options are mandatory" >&2 + echo "$USAGE" >&2 + exit 1 +fi +if test "$#" -eq 0; then + echo "$0: No packages specified" >&2 + echo "$USAGE" >&2 + exit 1 +fi + +workdir="$PWD/rpm-files.$$" +buildroot="$workdir/buildroot" +rpmdir=RPMS +srpmdir=SRPMS +disturl= +rpms=() +rm -rf "$workdir" +mkdir "$workdir" || exit +mkdir -p "$rpmdir" "$srpmdir" || exit +mkdir "$buildroot" +echo "Unpacking original RPMs..." +for rpm; do + # XXX: Use a common script in pesign-repackage.spec.in and here + case "$rpm" in + *.src.rpm | *.nosrc.rpm) + cp "$rpm" "$srpmdir/" + continue + ;; + # Do not repackage debuginfo packages (bnc#806637) + *-debuginfo-*.rpm | *-debugsource-*.rpm) + dir="$rpmdir/$(rpm -qp --qf '%{arch}' "$rpm")" + mkdir -p "$dir" + cp "$rpm" "$dir" + continue + ;; + esac + # do not repackage baselibs packages + # FIXME: needs more generic test (if architecture has different + # bitness => skip) + case "$(rpm -qp --qf '%{name}/%{arch}' "$rpm")" in + *-32bit/x86_64 | *-32bit/s390x | *-32bit/ppc64 | \ + *-64bit/ppc | *-x86/ia64) + mkdir -p "$rpmdir/$(rpm -qp --qf '%{arch}')/" + cp "$rpm" "$_" + continue + esac + rpm2cpio "$rpm" | (cd "$buildroot"; cpio -idm --quiet) || exit + d=$(rpm -qp --qf '%{disturl}' "$rpm") + if test -z "$disturl"; then + disturl=$d + fi + if test "$disturl" != "$d"; then + echo "Error: packages have different disturl: $d vs $disturl" + exit 1 + fi + rpms=("${rpms[@]}" "$rpm") +done +set -e +echo "Signing kernel modules..." +for module in $(find "$buildroot" -type f -name '*.ko'); do + /usr/lib/rpm/pesign/kernel-sign-file \ + sha256 "$key" "$cert" "$module" +done +# Add the certificate +mkdir -p "$buildroot/etc/uefi/certs" +h=$(openssl x509 -inform DER -fingerprint -noout -in "$cert") +filename=/etc/uefi/certs/$(echo "$h" | \ + sed -rn 's/^SHA1 Fingerprint=//; T; s/://g; s/(.{8}).*/\1/p').crt +cp "$cert" "$buildroot/$filename" + +echo "Generating new specfile..." +if ! test -e /usr/lib/rpm/kernel-cert-subpackage; then + echo "/usr/lib/rpm/kernel-cert-subpackage missing" >&2 + echo "please install the kernel-source package" >&2 + exit 1 +fi +/usr/lib/rpm/pesign/pesign-gen-repackage-spec \ + --cert-subpackage=/usr/lib/rpm/kernel-cert-subpackage \ + --directory="$buildroot" --output="$workdir" "${rpms[@]}" +echo "Running rpmbuild..." +rpmbuild --define "buildroot $buildroot" --define "disturl $disturl" \ + --define "_builddir $workdir" \ + --define "_suse_insert_debug_package %{nil}" \ + --define "_rpmdir $rpmdir" \ + -bb "$workdir/repackage.spec" >"$workdir/log" 2>&1 +grep 'RPMS/.*\.rpm$' "$workdir/log" +echo "Cleaning up $workdir..." +rm -r "$workdir" +echo "Done." +exit 0 + + diff --git a/pesign-gen-repackage-spec b/pesign-gen-repackage-spec index 2d25818..f1e558f 100644 --- a/pesign-gen-repackage-spec +++ b/pesign-gen-repackage-spec @@ -28,6 +28,8 @@ use Fcntl qw(:mode :seek); my $directory; my $output = "."; +my $cert_subpackage; +my $kmp_basename; my @rpms; $ENV{LC_ALL} = "en_US.UTF-8"; @@ -36,6 +38,7 @@ GetOptions( "help|h" => sub { print $USAGE; exit; }, "directory|d=s" => \$directory, "output|o=s" => \$output, + "cert-subpackage|c=s" => \$cert_subpackage, ) or die $USAGE; @rpms = @ARGV; if (!@rpms) { @@ -155,7 +158,7 @@ sub load_package { my @files; my @list = query_array($rpm, qw(filenames fileflags filemodes fileusername filegroupname filesizes filemtimes filelinktos)); for my $file (@list) { - push(@files, { + my $new = { name => $file->[0], flags => $file->[1], mode => $file->[2], @@ -164,7 +167,11 @@ sub load_package { size => $file->[5], mtime => $file->[6], target => $file->[7], - }); + }; + push(@files, $new); + if ($new->{name} =~ /\.ko$/ && S_ISREG($new->{mode})) { + $res{is_kmp} = 1; + } } $res{files} = \@files; while (my ($dep, $tag) = each(%dep2tag)) { @@ -264,6 +271,9 @@ sub print_package { for my $dep (keys(%dep2tag)) { print_deps($dep, $p->{$dep}); } + if ($cert_subpackage && $p->{is_kmp}) { + print SPEC "Requires: $kmp_basename-ueficert\n"; + } print SPEC "\%description -n $p->{name}\n"; print SPEC quote($p->{description}) . "\n\n"; @@ -424,12 +434,50 @@ if (!exists($packages{$main_name})) { } $packages{$main_name}->{nosource} = $nosrc ? 1 : 0; +# Find out the basename of -kmp-, falling back to the +# main package name +for my $p (values(%packages)) { + next unless $p->{is_kmp}; + (my $n = $p->{name}) =~ s/-kmp-.*//; + $kmp_basename = $n unless $kmp_basename; + if ($n ne $kmp_basename) { + $kmp_basename = undef; + last; + } +} +$kmp_basename = $main_name unless $kmp_basename; + open(SPEC, '>', "$output/repackage.spec") or die "$output/repackage.spec: $!\n"; print_package($packages{$main_name}, 1); for my $p (values(%packages)) { next if $p->{name} eq $main_name; print_package($p, 0); } +if ($cert_subpackage) { + my $certdir = "/etc/uefi/certs"; + my $certs = ""; + if (-d "$directory/$certdir") { + opendir(my $dh, "$directory/$certdir") or die "$directory/$certdir"; + while (my $cert = readdir($dh)) { + next if $cert =~ /^\.\.?$/; + if ($cert !~ /\.crt$/) { + print STDERR "warning: Ignoring $directory/$certdir/$cert (no .crt suffix)\n"; + next; + } + $certs .= " $certdir/$cert"; + } + } + if (!$certs) { + print STDERR "warning: --cert-subpackage specified, but no certs found in $directory/$certdir\n"; + } + local $/ = undef; + open(my $fh, '<', $cert_subpackage) or die "$cert_subpackage: $!\n"; + my $template = <$fh>; + close($fh); + $template =~ s/\%{-n\*}/$kmp_basename/g; + $template =~ s/\@CERTS\@/$certs/g; + print SPEC $template; +} print SPEC "\%changelog\n"; print SPEC quote($packages{$main_name}->{changelog}); close(SPEC); diff --git a/pesign-obs-integration.changes b/pesign-obs-integration.changes index 313f9b4..1ca636f 100644 --- a/pesign-obs-integration.changes +++ b/pesign-obs-integration.changes @@ -1,3 +1,14 @@ +------------------------------------------------------------------- +Fri Jun 14 12:19:47 UTC 2013 - mmarek@suse.cz + +- Put debuginfo packages to %_topdir/OTHER (bnc#824971). + +------------------------------------------------------------------- +Thu Mar 28 15:55:10 UTC 2013 - mmarek@suse.cz + +- Version 10 +- Add modsign-repackage tool to repackage RPMs outside the buildservice + ------------------------------------------------------------------- Tue Mar 26 06:19:45 UTC 2013 - glin@suse.com diff --git a/pesign-obs-integration.spec b/pesign-obs-integration.spec index ad3de54..0b1a302 100644 --- a/pesign-obs-integration.spec +++ b/pesign-obs-integration.spec @@ -22,7 +22,7 @@ Name: pesign-obs-integration Summary: Macros and scripts to sign the kernel and bootloader License: GPL-2.0 Group: Development/Tools/Other -Version: 9.0 +Version: 10.0 Release: 0. Requires: mozilla-nss-tools Requires: openssl @@ -37,6 +37,7 @@ Source4: brp-99-pesign Source5: COPYING Source6: README Source7: kernel-sign-file +Source8: modsign-repackage BuildRoot: %{_tmppath}/%{name}-%{version}-build %description @@ -56,6 +57,8 @@ cd %_sourcedir install pesign-gen-repackage-spec kernel-sign-file %buildroot/usr/lib/rpm/pesign install brp-99-pesign %buildroot/usr/lib/rpm/brp-suse.d install -m644 pesign-repackage.spec.in %buildroot/usr/lib/rpm/pesign +mkdir -p %buildroot/usr/bin +install modsign-repackage %buildroot/usr/bin/ if test -e _projectcert.crt; then openssl x509 -inform PEM -in _projectcert.crt \ -outform DER -out %buildroot/usr/lib/rpm/pesign/pesign-cert.x509 @@ -66,6 +69,7 @@ fi %files %defattr(-,root,root) %doc COPYING README +/usr/bin/modsign-repackage /usr/lib/rpm/* %changelog diff --git a/pesign-repackage.spec.in b/pesign-repackage.spec.in index f4743c6..3c6de6b 100644 --- a/pesign-repackage.spec.in +++ b/pesign-repackage.spec.in @@ -54,9 +54,8 @@ for rpm in %_sourcedir/*.rpm; do ;; # Do not repackage debuginfo packages (bnc#806637) *-debuginfo-*.rpm | *-debugsource-*.rpm) - dir=%_rpmdir/$(rpm -qp --qf '%%{arch}' "$rpm") - mkdir -p "$dir" - cp "$rpm" "$dir" + mkdir -p "%_topdir/OTHER" + cp "$rpm" "$_" continue ;; esac