osc copypac from project:home:michal-m:modsign package:pesign-obs-integration revision:2
OBS-URL: https://build.opensuse.org/package/show/Base:System/pesign-obs-integration?expand=0&rev=1
This commit is contained in:
commit
184dbd8a83
23
.gitattributes
vendored
Normal file
23
.gitattributes
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
## Default LFS
|
||||
*.7z filter=lfs diff=lfs merge=lfs -text
|
||||
*.bsp filter=lfs diff=lfs merge=lfs -text
|
||||
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
||||
*.gem filter=lfs diff=lfs merge=lfs -text
|
||||
*.gz filter=lfs diff=lfs merge=lfs -text
|
||||
*.jar filter=lfs diff=lfs merge=lfs -text
|
||||
*.lz filter=lfs diff=lfs merge=lfs -text
|
||||
*.lzma filter=lfs diff=lfs merge=lfs -text
|
||||
*.obscpio filter=lfs diff=lfs merge=lfs -text
|
||||
*.oxt filter=lfs diff=lfs merge=lfs -text
|
||||
*.pdf filter=lfs diff=lfs merge=lfs -text
|
||||
*.png filter=lfs diff=lfs merge=lfs -text
|
||||
*.rpm filter=lfs diff=lfs merge=lfs -text
|
||||
*.tbz filter=lfs diff=lfs merge=lfs -text
|
||||
*.tbz2 filter=lfs diff=lfs merge=lfs -text
|
||||
*.tgz filter=lfs diff=lfs merge=lfs -text
|
||||
*.ttf filter=lfs diff=lfs merge=lfs -text
|
||||
*.txz filter=lfs diff=lfs merge=lfs -text
|
||||
*.whl filter=lfs diff=lfs merge=lfs -text
|
||||
*.xz filter=lfs diff=lfs merge=lfs -text
|
||||
*.zip filter=lfs diff=lfs merge=lfs -text
|
||||
*.zst filter=lfs diff=lfs merge=lfs -text
|
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
.osc
|
339
COPYING
Normal file
339
COPYING
Normal file
@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
27
README
Normal file
27
README
Normal file
@ -0,0 +1,27 @@
|
||||
Signing kernel modules and EFI binaries in the Open Build Service
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Note: Not everything that is described here is actually implemented. Even
|
||||
those parts that are implemented can change slightly.
|
||||
|
||||
Packages that need to sign files during build should add the following lines
|
||||
to the specfile
|
||||
|
||||
# needssslcertforbuild
|
||||
%define sign_files pattern...
|
||||
BuildRequires: pesign-obs-integration
|
||||
|
||||
The "# needssslcertforbuild" comment tells the buildservice to store the
|
||||
signing certificate in %_sourcedir/_projectcert.crt. At the end of the
|
||||
install phase, the pesign-install-post script computes hashes of all
|
||||
files matching the patterns in %sign_files. The sha256 hashes are stored
|
||||
in %_topdir/OTHER/%name.cpio.rsasign, plus the script places a
|
||||
pesign-repackage.spec file there. When the first rpmbuild finishes, the
|
||||
buildservice sends the cpio archive to the signing server, which returns
|
||||
a rsasigned.cio archive with RSA signatures of the sha256 hashes.
|
||||
|
||||
The pesign-repackage.spec takes the original RPMs, unpacks them and
|
||||
appends the signatures to the files (TODO: only implemented for firmware
|
||||
files). It then uses the pesign-gen-repackage-spec script to generate
|
||||
another specfile, which builds new RPMs with signed files.
|
||||
|
441
kernel-sign-file
Normal file
441
kernel-sign-file
Normal file
@ -0,0 +1,441 @@
|
||||
#!/usr/bin/perl -w
|
||||
#
|
||||
# Sign a module file using the given key.
|
||||
#
|
||||
|
||||
my $USAGE =
|
||||
"Usage: scripts/sign-file [-v] [-f] <hash algo> <key> <x509> <module> [<dest>]\n" .
|
||||
" scripts/sign-file [-v] [-f] -s <raw sig> <hash algo> <x509> <module> [<dest>]\n" .
|
||||
" -v verbose output\n" .
|
||||
" -f create a firmware signature file\n";
|
||||
|
||||
|
||||
use strict;
|
||||
use FileHandle;
|
||||
use IPC::Open2;
|
||||
use Getopt::Std;
|
||||
|
||||
my %opts;
|
||||
getopts('vfs:', \%opts) or die $USAGE;
|
||||
my $verbose = $opts{'v'};
|
||||
my $signature_file = $opts{'s'};
|
||||
my $sign_fw = $opts{'f'};
|
||||
|
||||
die $USAGE if ($#ARGV > 4);
|
||||
die $USAGE if (!$signature_file && $#ARGV < 3 || $signature_file && $#ARGV < 2);
|
||||
|
||||
my $dgst = shift @ARGV;
|
||||
my $private_key;
|
||||
if (!$signature_file) {
|
||||
$private_key = shift @ARGV;
|
||||
}
|
||||
my $x509 = shift @ARGV;
|
||||
my $module = shift @ARGV;
|
||||
my ($dest, $keep_orig);
|
||||
if (@ARGV) {
|
||||
$dest = $ARGV[0];
|
||||
$keep_orig = 1;
|
||||
} elsif ($sign_fw) {
|
||||
$dest = $module . ".sig";
|
||||
$keep_orig = 1;
|
||||
} else {
|
||||
$dest = $module . "~";
|
||||
}
|
||||
my $mode_name = $sign_fw ? "firmware" : "module";
|
||||
|
||||
die "Can't read private key\n" if (!$signature_file && !-r $private_key);
|
||||
die "Can't read signature file\n" if ($signature_file && !-r $signature_file);
|
||||
die "Can't read X.509 certificate\n" unless (-r $x509);
|
||||
die "Can't read $mode_name\n" unless (-r $module);
|
||||
|
||||
#
|
||||
# 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
|
||||
#
|
||||
my $algo = 1; # Public-key crypto algorithm: RSA
|
||||
my $hash = 0; # Digest algorithm
|
||||
my $id_type = 1; # Identifier type: X.509
|
||||
|
||||
#
|
||||
# Digest the data
|
||||
#
|
||||
my $prologue;
|
||||
if ($dgst eq "sha1") {
|
||||
$prologue = pack("C*",
|
||||
0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
|
||||
0x2B, 0x0E, 0x03, 0x02, 0x1A,
|
||||
0x05, 0x00, 0x04, 0x14);
|
||||
$hash = 2;
|
||||
} elsif ($dgst eq "sha224") {
|
||||
$prologue = pack("C*",
|
||||
0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09,
|
||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04,
|
||||
0x05, 0x00, 0x04, 0x1C);
|
||||
$hash = 7;
|
||||
} elsif ($dgst eq "sha256") {
|
||||
$prologue = pack("C*",
|
||||
0x30, 0x31, 0x30, 0x0d, 0x06, 0x09,
|
||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
|
||||
0x05, 0x00, 0x04, 0x20);
|
||||
$hash = 4;
|
||||
} elsif ($dgst eq "sha384") {
|
||||
$prologue = pack("C*",
|
||||
0x30, 0x41, 0x30, 0x0d, 0x06, 0x09,
|
||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02,
|
||||
0x05, 0x00, 0x04, 0x30);
|
||||
$hash = 5;
|
||||
} elsif ($dgst eq "sha512") {
|
||||
$prologue = pack("C*",
|
||||
0x30, 0x51, 0x30, 0x0d, 0x06, 0x09,
|
||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
|
||||
0x05, 0x00, 0x04, 0x40);
|
||||
$hash = 6;
|
||||
} else {
|
||||
die "Unknown hash algorithm: $dgst\n";
|
||||
}
|
||||
|
||||
my $signature;
|
||||
if ($signature_file) {
|
||||
$signature = read_file($signature_file);
|
||||
} else {
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
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 = 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));
|
||||
|
||||
if ($verbose) {
|
||||
print "Size of unsigned $mode_name: ", 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";
|
||||
}
|
||||
|
||||
open(FD, ">$dest") || die $dest;
|
||||
binmode FD;
|
||||
if ($sign_fw) {
|
||||
print FD
|
||||
$magic_number,
|
||||
$info,
|
||||
$signers_name,
|
||||
$key_identifier,
|
||||
$signature
|
||||
;
|
||||
} else {
|
||||
print FD
|
||||
$unsigned_module,
|
||||
$signers_name,
|
||||
$key_identifier,
|
||||
$signature,
|
||||
$info,
|
||||
$magic_number
|
||||
;
|
||||
}
|
||||
close FD || die $dest;
|
||||
|
||||
if (!$keep_orig) {
|
||||
rename($dest, $module) || die $module;
|
||||
}
|
5
macros.pesign-obs
Normal file
5
macros.pesign-obs
Normal file
@ -0,0 +1,5 @@
|
||||
# Macros for pesign / modsign OBS integration
|
||||
|
||||
# The spec file should define %sign_files to a space-separated list of patterns
|
||||
# of files to be signed, e.g. %define sign_files /lib/firmware *.ko
|
||||
%__os_install_post /usr/lib/rpm/pesign-install-post --files "%{?sign_files}" --output %_topdir/OTHER
|
369
pesign-gen-repackage-spec
Normal file
369
pesign-gen-repackage-spec
Normal file
@ -0,0 +1,369 @@
|
||||
#!/usr/bin/perl
|
||||
# Given a set of rpm packages and directory with their new content,
|
||||
# generate a specfile that generates new packages
|
||||
#
|
||||
# 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
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
my $USAGE = "Usage: $0 --directory <payload directory> rpm...\n";
|
||||
|
||||
use Getopt::Long;
|
||||
use Fcntl qw(:mode :seek);
|
||||
|
||||
my $directory;
|
||||
my $output = ".";
|
||||
my @rpms;
|
||||
|
||||
$ENV{LC_ALL} = "en_US.UTF-8";
|
||||
|
||||
GetOptions(
|
||||
"help|h" => sub { print $USAGE; exit; },
|
||||
"directory|d=s" => \$directory,
|
||||
"output|o=s" => \$output,
|
||||
) or die $USAGE;
|
||||
@rpms = @ARGV;
|
||||
if (!@rpms) {
|
||||
print STDERR "$0: No packages given\n";
|
||||
die $USAGE;
|
||||
}
|
||||
if (!$directory || substr($directory, 0, 1) ne '/' || ! -d $directory) {
|
||||
print STDERR "$0: --directory must be an absolute path\n";
|
||||
die $USAGE;
|
||||
}
|
||||
|
||||
sub query_array {
|
||||
my ($rpm, @tags) = @_;
|
||||
my @res;
|
||||
|
||||
my $format = "[" . join("|", map { "\%{$_}" } @tags) . "\\n]";
|
||||
open(my $fh, '-|', "rpm", "-qp", "--qf", $format, $rpm)
|
||||
or die "rpm: $!\n";
|
||||
while (<$fh>) {
|
||||
chomp;
|
||||
my @t = split(/\|/, $_, -1);
|
||||
push(@res, \@t);
|
||||
}
|
||||
close($fh);
|
||||
return @res;
|
||||
}
|
||||
|
||||
sub query_single {
|
||||
my ($rpm, $tag) = @_;
|
||||
my $res;
|
||||
|
||||
open(my $fh, '-|', "rpm", "-qp", "--qf", "\%{$tag}\\n", $rpm)
|
||||
or die "rpm: $!\n";
|
||||
{
|
||||
local $/ = undef;
|
||||
$res = <$fh>;
|
||||
}
|
||||
chomp $res;
|
||||
close($fh);
|
||||
return $res;
|
||||
|
||||
}
|
||||
|
||||
# specfile dependency => rpm tag name
|
||||
my %dep2tag = (
|
||||
conflicts => "conflict",
|
||||
obsoletes => "obsolete",
|
||||
provides => "provide",
|
||||
requires => "require",
|
||||
suggests => "suggests",
|
||||
enhances => "enhances",
|
||||
);
|
||||
|
||||
# strong version of suggests and enhances
|
||||
my %dep2strong = (
|
||||
suggests => "recommends",
|
||||
enhances => "supplements",
|
||||
);
|
||||
|
||||
# specfile scriptlet => rpm tag name
|
||||
my %script2tag = (
|
||||
pre => "prein",
|
||||
post => "postin",
|
||||
preun => "preun",
|
||||
postun => "postun",
|
||||
pretrans => "pretrans",
|
||||
posttrans => "posttrans",
|
||||
verifyscript => "verifyscript",
|
||||
# FIXME: triggers
|
||||
);
|
||||
|
||||
# tags which are printed verbatim in the specfile
|
||||
my @simple_tags = qw(version release license group summary packager vendor
|
||||
url distribution);
|
||||
|
||||
sub load_package {
|
||||
my $rpm = shift;
|
||||
my %res;
|
||||
|
||||
for my $tag (qw(name arch sourcerpm description), @simple_tags) {
|
||||
$res{$tag} = query_single($rpm, $tag);
|
||||
}
|
||||
my @files;
|
||||
my @list = query_array($rpm, qw(filenames fileflags filemodes fileusername filegroupname filesizes filemtimes filelinktos));
|
||||
for my $file (@list) {
|
||||
push(@files, {
|
||||
name => $file->[0],
|
||||
flags => $file->[1],
|
||||
mode => $file->[2],
|
||||
owner => $file->[3],
|
||||
group => $file->[4],
|
||||
size => $file->[5],
|
||||
mtime => $file->[6],
|
||||
target => $file->[7],
|
||||
});
|
||||
}
|
||||
$res{files} = \@files;
|
||||
while (my ($dep, $tag) = each(%dep2tag)) {
|
||||
my @deps;
|
||||
my @list = query_array($rpm, "${tag}name", "${tag}flags", "${tag}version");
|
||||
for my $d (@list) {
|
||||
next if $d->[0] eq "(none)";
|
||||
push(@deps, {
|
||||
name => $d->[0],
|
||||
flags => $d->[1],
|
||||
version => $d->[2],
|
||||
});
|
||||
}
|
||||
$res{$dep} = \@deps;
|
||||
}
|
||||
|
||||
while (my ($script, $tag) = each(%script2tag)) {
|
||||
my $s = query_single($rpm, $tag);
|
||||
next unless $s && $s ne "(none)";
|
||||
my $interp = query_single($rpm, "${tag}prog");
|
||||
$res{$script} = {
|
||||
interp => $interp,
|
||||
script => $s,
|
||||
};
|
||||
}
|
||||
open(my $fh, '-|', "rpm", "-qp", "--changelog", $rpm) or die "rpm: $!\n";
|
||||
{
|
||||
local $/ = undef;
|
||||
my $changelog = <$fh>;
|
||||
close($fh);
|
||||
$res{changelog} = $changelog;
|
||||
}
|
||||
|
||||
return \%res;
|
||||
}
|
||||
|
||||
# quote percent signs in text
|
||||
sub quote {
|
||||
my $text = shift;
|
||||
|
||||
$text =~ s/%/%%/g;
|
||||
return $text;
|
||||
}
|
||||
|
||||
sub print_package {
|
||||
my ($p, $is_main) = @_;
|
||||
|
||||
if ($is_main) {
|
||||
print SPEC "Name: $p->{name}\n";
|
||||
print SPEC "Buildroot: $directory\n";
|
||||
print SPEC "\%define _use_internal_dependency_generator 0\n";
|
||||
print SPEC "\%define __find_provides %{nil}\n";
|
||||
print SPEC "\%define __find_requires %{nil}\n";
|
||||
print SPEC "\%define __find_supplements %{nil}\n";
|
||||
if ($p->{nosource}) {
|
||||
# We do not generate any no(src).rpm, but we want the
|
||||
# %{sourcerpm} tag in the binary packages to match.
|
||||
# So we add a dummy source and mark it as nosource.
|
||||
print SPEC "Source0: repackage.spec\n";
|
||||
print SPEC "NoSource: 0\n";
|
||||
}
|
||||
} else {
|
||||
print SPEC "\%package -n $p->{name}\n";
|
||||
}
|
||||
for my $tag (@simple_tags) {
|
||||
print SPEC "$tag: " . quote($p->{$tag}) . "\n";
|
||||
}
|
||||
print SPEC "BuildArch: noarch\n" if $p->{arch} eq "noarch";
|
||||
for my $dep (keys(%dep2tag)) {
|
||||
print_deps($dep, $p->{$dep});
|
||||
}
|
||||
print SPEC "\%description -n $p->{name}\n";
|
||||
print SPEC quote($p->{description}) . "\n\n";
|
||||
|
||||
for my $script (keys(%script2tag)) {
|
||||
next unless $p->{$script};
|
||||
my $file = "$script-$p->{name}";
|
||||
open(my $fh, '>', "$output/$file") or die "$output/$file: $!\n";
|
||||
print SPEC "\%$script -p $p->{$script}{interp} -n $p->{name} -f $file\n";
|
||||
print $fh $p->{$script}{script};
|
||||
close($fh);
|
||||
|
||||
}
|
||||
if ($p->{files}) {
|
||||
print SPEC "\%files -n $p->{name}\n";
|
||||
print_files($p->{files});
|
||||
}
|
||||
print SPEC "\n";
|
||||
}
|
||||
|
||||
# /usr/include/rpm/rpmds.h
|
||||
my %deptypes = (
|
||||
pre => (1 << 9),
|
||||
post => (1 << 10),
|
||||
preun => (1 << 11),
|
||||
postun => (1 << 12),
|
||||
verify => (1 << 13),
|
||||
);
|
||||
my %depflags = (
|
||||
"<" => (1 << 1),
|
||||
">" => (1 << 2),
|
||||
"=" => (1 << 3),
|
||||
rpmlib => (1 << 24),
|
||||
strong => (1 << 27),
|
||||
);
|
||||
|
||||
sub print_deps {
|
||||
my ($depname, $list) = @_;
|
||||
|
||||
foreach my $d (@$list) {
|
||||
next if ($d->{flags} & $depflags{rpmlib});
|
||||
|
||||
if ($d->{flags} & $depflags{strong}) {
|
||||
print SPEC $dep2strong{$depname};
|
||||
} else {
|
||||
print SPEC $depname;
|
||||
}
|
||||
my @deptypes;
|
||||
while (my ($type, $bit) = each(%deptypes)) {
|
||||
push(@deptypes, $type) if $d->{flags} & $bit;
|
||||
}
|
||||
print SPEC "(", join(",", @deptypes), ")" if @deptypes;
|
||||
print SPEC ": ";
|
||||
|
||||
print SPEC quote($d->{name});
|
||||
if ($d->{version}) {
|
||||
print SPEC " ";
|
||||
for my $op (qw(< > =)) {
|
||||
print SPEC $op if $d->{flags} & $depflags{$op};
|
||||
}
|
||||
print SPEC " " . quote($d->{version});
|
||||
}
|
||||
print SPEC "\n";
|
||||
}
|
||||
}
|
||||
|
||||
# /usr/include/rpm/rpmfi.h
|
||||
my %filetypes = (
|
||||
config => (1 << 0),
|
||||
doc => (1 << 1),
|
||||
missingok => (1 << 3),
|
||||
noreplace => (1 << 4),
|
||||
ghost => (1 << 6),
|
||||
);
|
||||
|
||||
sub print_files {
|
||||
my $files = shift;
|
||||
|
||||
for my $f (@$files) {
|
||||
my $path = "$directory/$f->{name}";
|
||||
my $attrs = "";
|
||||
# Fix mtime of directories, which cpio -idm fails to preserve
|
||||
if (S_ISDIR($f->{mode})) {
|
||||
$attrs .= "\%dir ";
|
||||
utime($f->{mtime}, $f->{mtime}, $path);
|
||||
}
|
||||
$attrs .= sprintf('%%attr(%04o, %s, %s) ', ($f->{mode} & 0777),
|
||||
$f->{owner}, $f->{group});
|
||||
if ($f->{flags} & $filetypes{config}) {
|
||||
$attrs .= "%config ";
|
||||
my @cfg_attrs;
|
||||
for my $attr (qw(missingok noreplace)) {
|
||||
next unless $f->{flags} & $filetypes{$attr};
|
||||
push(@cfg_attrs, $attr);
|
||||
}
|
||||
$attrs .= "(" . join(",", @cfg_attrs) . ")" if @cfg_attrs;
|
||||
}
|
||||
$attrs .= "%doc " if $f->{flags} & $filetypes{doc};
|
||||
if ($f->{flags} & $filetypes{ghost}) {
|
||||
$attrs .= "%ghost ";
|
||||
if (S_ISREG($f->{mode})) {
|
||||
open(my $fh, '>', $path) or die "$path: $!\n";
|
||||
if ($f->{size} > 0) {
|
||||
sysseek($fh, $f->{size} - 1, SEEK_SET);
|
||||
syswrite($fh, ' ', 1);
|
||||
}
|
||||
close($fh);
|
||||
utime($f->{mtime}, $f->{mtime}, $path);
|
||||
} elsif (S_ISLNK($f->{mode})) {
|
||||
symlink($f->{target}, $path);
|
||||
}
|
||||
}
|
||||
# mtime of symlinks is also not preserved by cpio
|
||||
if (S_ISLNK($f->{mode})) {
|
||||
# perl core does not provide lutimes()/utimensat()
|
||||
system("touch", "-h", "-d\@$f->{mtime}", $path);
|
||||
}
|
||||
|
||||
print SPEC "$attrs " . quote($f->{name}) . "\n";
|
||||
if (-e "$path.sig") {
|
||||
print SPEC "$attrs " . quote($f->{name}) . ".sig\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my %packages;
|
||||
for my $rpm (@rpms) {
|
||||
my $p = load_package($rpm);
|
||||
$packages{$p->{name}} = $p;
|
||||
}
|
||||
|
||||
my $sourcerpm;
|
||||
for my $p (values(%packages)) {
|
||||
$sourcerpm = $p->{sourcerpm} unless $sourcerpm;
|
||||
if ($p->{sourcerpm} ne $sourcerpm) {
|
||||
die "Error: packages built from different source rpm: $sourcerpm vs $p->{sourcerpm}\n";
|
||||
}
|
||||
}
|
||||
if ($sourcerpm !~ /^(.+)-([^-]+)-([^-]+)\.(no)?src\.rpm$/) {
|
||||
die "Error: malformed %{sourcerpm} tag: $sourcerpm\n";
|
||||
}
|
||||
my ($main_name, $main_ver, $main_rel, $nosrc) = ($1, $2, $3, $4);
|
||||
if (!exists($packages{$main_name})) {
|
||||
# create an empty main package
|
||||
my $first = (values(%packages))[0];
|
||||
$packages{$main_name} = {
|
||||
name => $main_name,
|
||||
version => $main_ver,
|
||||
release => $main_rel,
|
||||
};
|
||||
for my $tag (qw(description changelog arch), @simple_tags) {
|
||||
next if $packages{$main_name}->{$tag};
|
||||
$packages{$main_name}->{$tag} = $first->{$tag};
|
||||
}
|
||||
}
|
||||
$packages{$main_name}->{nosource} = $nosrc ? 1 : 0;
|
||||
|
||||
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);
|
||||
}
|
||||
print SPEC "\%changelog\n";
|
||||
print SPEC quote($packages{$main_name}->{changelog});
|
||||
close(SPEC);
|
110
pesign-install-post
Normal file
110
pesign-install-post
Normal file
@ -0,0 +1,110 @@
|
||||
#!/bin/bash
|
||||
# This script is run by rpmbuild at the end of install section. It computes
|
||||
# hashes of files listed in the %sign_files macro and stores them in
|
||||
# %_topdir/OTHER/%name.cpio.rsasign. It also puts a specfile there, that
|
||||
# is later used to repackage the RPMs.
|
||||
#
|
||||
# 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
|
||||
|
||||
set -e
|
||||
|
||||
files=
|
||||
output=
|
||||
while test $# -gt 0; do
|
||||
case "$1" in
|
||||
--files)
|
||||
files=$2
|
||||
shift 2
|
||||
;;
|
||||
--output)
|
||||
output=$2
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
echo "$0: Unknown option: $1" >&2
|
||||
exit 1
|
||||
esac
|
||||
done
|
||||
if test -z "$files"; then
|
||||
exit 0
|
||||
fi
|
||||
if test -z "$output"; then
|
||||
echo "$0: --output not specified" >&2
|
||||
exit 1
|
||||
fi
|
||||
if test -z "$RPM_BUILD_ROOT"; then
|
||||
echo "$0: warning: \$RPM_BUILD_ROOT not set, using the root directory" >&2
|
||||
RPM_BUILD_ROOT=/
|
||||
fi
|
||||
|
||||
mkdir -p "$output"
|
||||
cert=$RPM_SOURCE_DIR/_projectcert.crt
|
||||
if test -e "$cert"; then
|
||||
echo "Using signing certificate $cert"
|
||||
else
|
||||
echo "No buildservice signing certificate"
|
||||
cert=/dev/null
|
||||
fi
|
||||
sed "
|
||||
s:@NAME@:$RPM_PACKAGE_NAME:g
|
||||
/@CERT@/ {
|
||||
r $cert
|
||||
d
|
||||
}
|
||||
" /usr/lib/rpm/pesign-repackage.spec.in >"$output/pesign-repackage.spec"
|
||||
|
||||
cd "$RPM_BUILD_ROOT"
|
||||
args=()
|
||||
for pattern in $files; do
|
||||
pattern=${pattern#/}
|
||||
if test "${pattern:0:2}" != "./"; then
|
||||
pattern="./$pattern"
|
||||
fi
|
||||
if test -d "$pattern"; then
|
||||
pattern="$pattern/*"
|
||||
fi
|
||||
args=("${args[@]}" -o -path "$pattern")
|
||||
done
|
||||
# delete the leading -o
|
||||
unset args[0]
|
||||
|
||||
archive=$output/$RPM_PACKAGE_NAME.cpio.rsasign
|
||||
archive_dir=$output/$RPM_PACKAGE_NAME
|
||||
mkdir -p "$archive_dir"
|
||||
# create an empty nss database to make pesign happy
|
||||
nss_db=$(mktemp -d)
|
||||
trap 'rm -rf "$nss_db"' EXIT
|
||||
echo >"$nss_db/password"
|
||||
certutil -N -f "$nss_db/password" -d "$nss_db"
|
||||
|
||||
echo "Creating $archive"
|
||||
files=($(find . -type f \( "${args[@]}" \)))
|
||||
for f in "${files[@]}"; do
|
||||
dest="$archive_dir/$f"
|
||||
mkdir -p "${dest%/*}"
|
||||
case "$f" in
|
||||
./boot/* | *.efi)
|
||||
pesign --certdir="$nss_db" -i "$f" --digestdata "$dest"
|
||||
;;
|
||||
*)
|
||||
cp "$f" "$dest"
|
||||
esac
|
||||
done
|
||||
cd "$archive_dir"
|
||||
find . -type f | cpio -H newc -o >"$archive"
|
||||
rm -rf "$archive_dir"
|
||||
|
45
pesign-obs-integration.changes
Normal file
45
pesign-obs-integration.changes
Normal file
@ -0,0 +1,45 @@
|
||||
-------------------------------------------------------------------
|
||||
Wed Jan 30 09:47:25 UTC 2013 - mmarek@suse.cz
|
||||
|
||||
- Version 6
|
||||
- Fix handling packages with NoSource
|
||||
- Fix for multiple patterns in %sign_files
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Tue Jan 29 13:44:43 UTC 2013 - mmarek@suse.cz
|
||||
|
||||
- Version 5
|
||||
- Use newc-style cpio archives, as required by the buildservice.
|
||||
- Use signing certificates provided by the buildservice.
|
||||
- Minor fixes.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Mon Jan 28 15:01:17 UTC 2013 - mmarek@suse.cz
|
||||
|
||||
- Version 4
|
||||
- Support for firmware signatures.
|
||||
- Expect the correct archive with signatures (<name>.cpio.rsasign.sig).
|
||||
- Minor fixes.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Wed Jan 23 22:01:40 UTC 2013 - mmarek@suse.cz
|
||||
|
||||
- Version 3
|
||||
- Switch to storing whole files in the *.cpio.rsasign archive.
|
||||
- Append the signatures to kernel modules.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Fri Jan 18 12:51:17 UTC 2013 - mmarek@suse.cz
|
||||
|
||||
- Version 2
|
||||
- Generates another specfile in pesign-repackage.spec to
|
||||
be able to copy nearly all RPM tags from the original packages.
|
||||
- Changed to only store sha256 hashes in the *.cpio.rsasign file,
|
||||
instead of whole files.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Thu Dec 13 12:06:00 UTC 2012 - mmarek@suse.com
|
||||
|
||||
- Created package with macros and scripts to integrate kernel and
|
||||
bootloader signing into OBS (fate#314552).
|
||||
|
77
pesign-obs-integration.spec
Normal file
77
pesign-obs-integration.spec
Normal file
@ -0,0 +1,77 @@
|
||||
#
|
||||
# spec file for package pesign-obs-integration (Version 1.0)
|
||||
#
|
||||
# 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
|
||||
#
|
||||
# Please submit bugfixes or comments via http://bugs.opensuse.org/
|
||||
#
|
||||
|
||||
# norootforbuild
|
||||
# needssslcertforbuild
|
||||
|
||||
Name: pesign-obs-integration
|
||||
Summary: Macros and scripts to sign the kernel and bootloader
|
||||
Version: 6.0
|
||||
Release: 1
|
||||
Requires: openssl mozilla-nss-tools
|
||||
%ifarch %ix86 x86_64 ia64
|
||||
Requires: pesign
|
||||
%endif
|
||||
BuildRequires: openssl
|
||||
License: GPL v2 only
|
||||
Group: Development/Tools/Other
|
||||
URL: http://en.opensuse.org/openSUSE:UEFI_Image_File_Sign_Tools
|
||||
Source1: macros.pesign-obs
|
||||
Source2: pesign-repackage.spec.in
|
||||
Source3: pesign-gen-repackage-spec
|
||||
Source4: pesign-install-post
|
||||
Source5: COPYING
|
||||
Source6: README
|
||||
Source7: kernel-sign-file
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-build
|
||||
%description
|
||||
This package provides scripts and rpm macros to automate signing of the
|
||||
boot loader, kernel and kernel modules in the openSUSE Buildservice.
|
||||
|
||||
%prep
|
||||
%setup -cT
|
||||
cp %_sourcedir/{COPYING,README} .
|
||||
|
||||
%build
|
||||
|
||||
%install
|
||||
|
||||
mkdir -p %buildroot/usr/lib/rpm %buildroot/etc/rpm
|
||||
cd %_sourcedir
|
||||
install -m644 macros.pesign-obs %buildroot/etc/rpm
|
||||
install pesign-gen-repackage-spec pesign-install-post kernel-sign-file %buildroot/usr/lib/rpm
|
||||
install -m644 pesign-repackage.spec.in %buildroot/usr/lib/rpm
|
||||
if test -e _projectcert.crt; then
|
||||
openssl x509 -inform PEM -in _projectcert.crt \
|
||||
-outform DER -out %buildroot/usr/lib/rpm/pesign-cert.x509
|
||||
else
|
||||
echo "No buildservice project certificate available"
|
||||
fi
|
||||
|
||||
%files
|
||||
%defattr(-,root,root)
|
||||
%doc COPYING README
|
||||
/usr/lib/rpm/*
|
||||
/etc/rpm/*
|
||||
|
||||
%changelog
|
||||
|
109
pesign-repackage.spec.in
Normal file
109
pesign-repackage.spec.in
Normal file
@ -0,0 +1,109 @@
|
||||
#!/bin/bash
|
||||
# This specfile unpacks the original RPMs, runs pesign-gen-repackage-spec
|
||||
# to create a second repackage specfile, and runs another rpmbuild to
|
||||
# actually do 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
|
||||
|
||||
# Do not generate any debug packages from the repackage specfile
|
||||
%undefine _build_create_debug
|
||||
|
||||
Name: pesign-repackage
|
||||
Version: 1.0
|
||||
Release: 1
|
||||
BuildRequires: openssl mozilla-nss-tools
|
||||
%ifarch %ix86 x86_64 ia64
|
||||
BuildRequires: pesign
|
||||
%endif
|
||||
License: GPLv
|
||||
Group: Development/Tools/Other
|
||||
Summary: Spec file to rebuild RPMs with signatures
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-build
|
||||
%description
|
||||
Rebuilds RPMs with signatures
|
||||
|
||||
%prep
|
||||
%setup -c -T
|
||||
|
||||
%build
|
||||
|
||||
%install
|
||||
|
||||
pushd %buildroot
|
||||
disturl=
|
||||
rpms=()
|
||||
for rpm in %_sourcedir/*.rpm; do
|
||||
case "$rpm" in
|
||||
*.src.rpm | *.nosrc.rpm)
|
||||
cp "$rpm" %_srcrpmdir/
|
||||
continue
|
||||
esac
|
||||
rpm2cpio "$rpm" | cpio -idm
|
||||
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
|
||||
popd
|
||||
mkdir rsasigned
|
||||
pushd rsasigned
|
||||
cpio -idm <%_sourcedir/@NAME@.cpio.rsasign.sig
|
||||
cat >cert.crt <<EOF
|
||||
@CERT@
|
||||
EOF
|
||||
if test "$(wc -l <cert.crt)" -gt 1; then
|
||||
openssl x509 -inform PEM -in cert.crt -outform DER -out cert.x509
|
||||
cert=cert.x509
|
||||
else
|
||||
echo "warning: No buildservice project certificate found, add"
|
||||
echo "warning: # needssslcertforbuild to the specfile"
|
||||
echo "warning: Using /usr/lib/rpm/pesign-cert.x509 as fallback"
|
||||
cert=/usr/lib/rpm/pesign-cert.x509
|
||||
fi
|
||||
sigs=($(find -type f -name '*.sig'))
|
||||
for sig in "${sigs[@]}"; do
|
||||
f=%buildroot/${sig%.sig}
|
||||
case "$sig" in
|
||||
*.ko.sig)
|
||||
/usr/lib/rpm/kernel-sign-file -s "$sig" sha256 "$cert" "$f"
|
||||
;;
|
||||
./lib/firmware/*.sig)
|
||||
/usr/lib/rpm/kernel-sign-file -f -s "$sig" sha256 "$cert" "$f"
|
||||
;;
|
||||
*)
|
||||
echo "Warning: unhandled signature: $sig" >&2
|
||||
esac
|
||||
done
|
||||
popd
|
||||
/usr/lib/rpm/pesign-gen-repackage-spec --directory=%buildroot "${rpms[@]}"
|
||||
rpmbuild --define "%%buildroot %buildroot" --define "%%disturl $disturl" \
|
||||
--define "%%_builddir $PWD" \
|
||||
--define "%_suse_insert_debug_package %%{nil}" -bb repackage.spec
|
||||
|
||||
# This is needed by the kernel packages. Ideally, we should not run _any_ brp
|
||||
# checks, because the RPMs passed them once already
|
||||
export NO_BRP_STALE_LINK_ERROR=yes
|
||||
|
||||
# Make sure that our rpmbuild does not complain about unpackaged files
|
||||
rm -rf %buildroot
|
||||
mkdir %buildroot
|
||||
|
Loading…
x
Reference in New Issue
Block a user