--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/installationservices/swi/test/trevocation/buildsis.pl Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,436 @@
+#
+# Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
+# All rights reserved.
+# This component and the accompanying materials are made available
+# under the terms of the License "Eclipse Public License v1.0"
+# which accompanies this distribution, and is available
+# at the URL "http://www.eclipse.org/legal/epl-v10.html".
+#
+# Initial Contributors:
+# Nokia Corporation - initial contribution.
+#
+# Contributors:
+#
+# Description:
+# Test tool used to make and sign SISX files signed by certificate
+# chains of aribtrary lengths as defiend by a template file.
+#
+
+use warnings;
+use strict;
+use Getopt::Long;
+
+my $CA_DIR='..\\tsisfile\\data\\signedsis';
+my $CERTS_DIR="certs";
+my $REQS_DIR="reqs";
+my $KEYS_DIR="keys";
+my $PKG_DIR="pkg";
+my $SIS_DIR="sis";
+my $TEMPLATE_DIR="templates";
+my $UID_FILE="uid.txt";
+my $INI_DIR="ini";
+my $SCRIPT_DIR="c:\\tswi\\trevocation\\scripts";
+my $DATA_DIR="c:\\tswi\\trevocation\\data";
+my $TMP_DIR="tmp";
+my $DAYS="3650";
+
+my $PLATFORM = '';
+my $CONFIGURATION = '';
+
+my $CA_TEXT=
+'
+subjectKeyIdentifier=hash
+#authorityKeyIdentifier=keyid:always,issuer:always
+basicConstraints=critical,CA:TRUE, pathlen:5
+keyUsage=critical,keyCertSign
+
+';
+
+
+&main;
+exit(0);
+
+sub main() {
+ my $section = '';
+ my $packageTemplate = '';
+ my @chains = ();
+ my @files = ();
+ my $installText = '';
+ my $uninstallText = '';
+ my $iniFile = '';
+ my $name = '';
+
+ GetOptions('platform=s' => \$PLATFORM,
+ 'configuration=s' => \$CONFIGURATION,
+ 'sis-dir=s' => \$SIS_DIR,
+ 'days=s', \$DAYS);
+
+ if ($#ARGV < 0) {
+ &usage;
+ }
+ my ($config) = @ARGV;
+ open IN, $config or die "Cannot open $config\n";
+
+ while (<IN>) {
+ chomp;
+
+ s/<DATA_DIR>/${DATA_DIR}/g;
+ s/<SCRIPT_DIR>/${SCRIPT_DIR}/g;
+ s/<PLATFORM>/$PLATFORM/g;
+ s/<CONFIGURATION>/$CONFIGURATION/g;
+
+ # Extract section name
+ if (/^\s*\[\w+\]/) {
+ s/.*\[\s*(.*)\s*].*/$1/g;
+ $section = lc;
+ }
+ elsif ($section eq "install") {
+ $installText .= "$_\n";
+ }
+ elsif ($section eq "uninstall") {
+ $uninstallText .= "$_\n";
+ }
+ # Skip comments
+ elsif (/^\s*\#/) {
+ next;
+ }
+ elsif (/\s*\w+\s*=.*/) { # Parse key/value pair
+
+ my ($key, $value) = split /=/;
+
+ $key =~ s/\s//g;
+ $key = lc($key);
+ if ($section eq "chains") {
+ if ($key =~ /chain\d+/) {
+ parseChain($value, \@chains);
+ }
+ }
+ elsif ($section eq "main") {
+ if ($key eq 'template') {
+ $packageTemplate = $value;
+ }
+ elsif ($key eq 'name') {
+ $name = $value;
+ }
+ elsif ($key eq 'inifile') {
+ $iniFile = $value;
+ }
+ }
+ elsif ($section eq "files") {
+ if ($key =~ /^\s*sis.*/) {
+ my $componentUID = embeddedSIS($value);
+ my $sisText = "\@\"${SIS_DIR}\\${PLATFORM}\\$value\",(${componentUID})\n";
+ push @files, $sisText;
+ }
+ else {
+ push @files, "$value\n";
+ }
+ }
+ }
+ }
+ close IN;
+
+ die "\'iniFile\' not defined in main section" unless $iniFile ne '';
+ die "\'name\' not defined in main section" unless $name ne '';
+
+ my @chainFiles; # The combined chain files
+ my @chainKeys; # The keys for the leaf of each chain
+
+ my $chainNum = 0;
+ foreach my $chain (@chains) {
+ print "\tProcessing chain $chainNum\n";
+ buildChain($name,
+ $chainNum,
+ \@chainFiles,
+ \@chainKeys,
+ @$chain);
+ $chainNum++;
+ }
+
+ my $temp = $packageTemplate;
+ $temp =~ s/.*\\(\w+).*/$1/;
+
+ my $packageFile = "${PKG_DIR}\\${name}.pkg";
+ my $uid = getUID();
+ buildPackage($PLATFORM,
+ $CONFIGURATION,
+ $uid,
+ "${TEMPLATE_DIR}\\$packageTemplate",
+ $packageFile,
+ @files);
+
+ # Create unsigned SIS file
+ mkdir("${SIS_DIR}\\${PLATFORM}");
+ my $sisFile = "${SIS_DIR}\\${PLATFORM}\\${name}.sis";
+ makesis($packageFile, $sisFile);
+
+ for (my $i = 0; $i <= $#chainFiles; $i++) {
+ signsis("${sisFile}", "${sisFile}.tmp", $chainFiles[$i], $chainKeys[$i]);
+ unlink $sisFile;
+ rename "${sisFile}.tmp", "${sisFile}";
+ }
+
+ # Add install/uninstall script entries for this package
+ addIniEntries($iniFile, $uid, $name, $installText, $uninstallText);
+}
+
+sub buildChain(\$\$\$\$\@) {
+ my ($name, $chainNum, $chainFiles, $chainKeys, @extensions) = @_;
+
+ my $root = shift @extensions;
+ my $certNum = 0;
+ my $signingCert = "${CA_DIR}\\$root\\ca.pem";
+ my $signingKey = "${CA_DIR}\\$root\\ca.key.pem";
+ my @chainElements = (); # List of cert filenames in the current chain
+
+ # For each extension create a request for a certificate and
+ # sign that request with the previous certificate, or the root
+ # certificate for the first element
+ foreach my $extension (@extensions) {
+ my $isCA = $certNum < $#extensions;
+
+ die "Cannot open extension file ext\\$extension.cfg\n"
+ unless -e "ext/$extension.cfg";
+
+ my $file = "${name}_${extension}.${chainNum}.${certNum}";
+ my $subject = "/C=UK/O=Symbian/CN=Entity Cert ${name} ${extension} ${chainNum} ${certNum}";
+ createRequest($isCA,
+ "${REQS_DIR}\\${file}.req.pem",
+ $subject,
+ "${KEYS_DIR}\\${file}.key.pem",
+ 'openssl.cfg');
+
+ signRequest($isCA,
+ "${REQS_DIR}\\${file}.req.pem",
+ "${CERTS_DIR}\\${file}.cert.pem",
+ $signingCert,
+ $signingKey,
+ "ext\\$extension.cfg");
+
+ $signingCert = "${CERTS_DIR}\\${file}.cert.pem";
+ $signingKey = "${KEYS_DIR}\\${file}.key.pem";
+
+ push @chainElements, "${CERTS_DIR}\\${file}.cert.pem";
+ $certNum++;
+ }
+ # Record the filename of the leaf signing key. This is needed by sisgnsis
+ push @$chainKeys, $signingKey;
+
+ # Concatenate all the certificates for signsis
+ my $chainFile = "${CERTS_DIR}\\${name}_chain_${chainNum}.pem";
+ push @$chainFiles, $chainFile;
+
+ open OUT, ">$chainFile" or
+ die "Cannot write to $chainFile\n";
+ foreach (@chainElements) {
+ open IN, $_ or
+ die "Cannot open $_\n";
+ while (<IN>) {
+ print OUT;
+ }
+ close IN;
+ }
+ close OUT;
+}
+
+sub buildPackage(\$\$\$\$\$\@) {
+ my ($PLATFORM, $CONFIGURATION, $packageUID, $packageTemplate, $packageFile, @files) = @_;
+ my $packageUIDText = sprintf "0x%8.8x", $packageUID;
+
+ print "\tCreating package $packageFile\n";
+
+ open(IN, "${packageTemplate}") or
+ die "Cannot open package file template $packageTemplate\n";
+
+ open(OUT, ">$packageFile") or
+ die "Cannot write to package file $packageFile\n";
+
+ # Substitute the list of files for the place holder in the template
+ # package file.
+ while (<IN>) {
+ s/\#\#PACKAGE_UID\#\#/${packageUIDText}/g;
+
+ if (/\#\#FILES\#\#/) {
+ foreach (@files) {
+ # The SISX files have to be built for every supported
+ # platform and configuration
+ print OUT;
+ }
+ }
+ else {
+ print OUT;
+ }
+ }
+ close IN;
+ close OUT;
+}
+
+sub parseChain(\$\$) {
+ my ($chainDesc, $chains) = @_;
+ my @elements = split(/,/, $chainDesc);
+ push @$chains, \@elements;
+}
+
+sub createRequest(\$,\$\$\$\$) {
+ my ($isCA, $requestFile, $subject, $keyFile, $config) = @_;
+
+ my @args = ('openssl',
+ 'req',
+ '-newkey',
+ 'rsa:512',
+ '-nodes',
+ '-out',
+ $requestFile,
+ '-keyout',
+ $keyFile,
+ '-subj',
+ $subject,
+ '-config',
+ $config,
+ '-days',
+ '3650');
+
+ system (@args) == 0 or
+ die "Cannot create certificate request $requestFile\n";
+}
+
+sub signRequest(\$\$\$\$\$) {
+ my ($isCA, $requestFile, $certFile, $CAcert, $CAkey, $extfile) = @_;
+ my $tmpFile = "${extfile}.tmp";
+
+ my @args = ('openssl',
+ 'x509',
+ '-req',
+ '-in',
+ $requestFile,
+ '-out',
+ $certFile,
+ '-CA',
+ $CAcert,
+ '-CAkey',
+ $CAkey,
+ '-extfile',
+ $tmpFile,
+ '-days',
+ "${DAYS}");
+
+ # Workaround to insert CA extensions
+ # Open SSL expects all the extensions to be kept together so we
+ # can't just specify the CA bits in the request because otherwise
+ # it will overwrite them
+ system 'copy', $extfile, $tmpFile;
+ system 'attrib', '-r', $tmpFile;
+
+ if ($isCA) {
+ open OUT, ">>$tmpFile" or die "Cannot open temporary file $tmpFile\n";
+ print OUT $CA_TEXT;
+ close OUT;
+ }
+
+ system (@args) == 0 or
+ die "Cannot sign certificate request $requestFile\n";
+ unlink $tmpFile;
+}
+
+sub makesis(\$\$) {
+ my ($packageFile, $sisFile) = @_;
+ print "\tCreating SIS file $sisFile\n";
+ system 'makesis', $packageFile, $sisFile;
+}
+
+sub signsis(\$\$\$\$) {
+ my ($input, $output, $certificate, $key) = @_;
+
+ print "\tSigning $input with certchain=${certificate} key=${key}\n";
+
+ system('signsis',
+ $input,
+ $output,
+ $certificate,
+ $key) == 0 or
+ die "Cannot sign SIS file $input $output $certificate $key\n";
+}
+
+sub usage {
+ print STDERR "Usage: buildsis.pl --platform <platform> --configuration <udeb|urel> --sis-dir <sis dir> <test spec>\n";
+ exit -1;
+}
+
+# Make sure each package has a unique UID by repeatedly adding one
+# from a pre-determined base.
+sub getUID {
+
+ if (! -e "uid.txt.tmp") {
+ system 'copy','uid.txt','uid.txt.tmp';
+ system 'attrib','-r','uid.txt.tmp';
+ }
+
+ open IN, "uid.txt.tmp" or die "Cannot open uid.txt.tmp\n";
+ my $uidText = <IN>;
+ my $uid = hex($uidText);
+ close IN;
+
+ die "Invalid uid = $uidText\n" unless $uid != 0;
+
+ open OUT, ">uid.txt.tmp" or die "Cannot write to uid.txt.tmp\n";
+ print OUT sprintf("0x%8.8x", $uid + 1);
+ close OUT;
+ return $uid;
+}
+
+# Add install & uninstall entries
+sub addIniEntries(\$\$\$\$\$) {
+ my ($iniFile, $uid, $name, $installText, $uninstallText) = @_;
+
+ print "\tAdding install entry to ${INI_DIR}\\${iniFile}\n";
+
+ open OUT, ">>${INI_DIR}\\${iniFile}" or die "Cannot write to ${iniFile}\n";
+
+ print OUT "[${name}]\n";
+ print OUT "sis=${DATA_DIR}\\${name}.sis\n";
+ print OUT "${installText}\n";
+
+ print "\tAdding uninstall entry to ${INI_DIR}\\${iniFile}\n";
+
+ print OUT "[u_${name}]\n";
+ print OUT "uid=${uid}\n";
+ print OUT "${uninstallText}\n";
+
+ close OUT;
+}
+
+# Takes the name of an embedded SIS file and returns the text required
+# by the package body to embed this file.
+# In addition, this function calculates the component uid of the package file
+# by searching the package directory for a file which matches the name of the SIS
+# file.
+sub embeddedSIS(\$) {
+ my ($sisfile) = @_;
+
+ my $absSISfile = "${SIS_DIR}\\${PLATFORM}\\$sisfile";
+
+ die "Cannot find embedded sis file $absSISfile\n"
+ unless (-e $absSISfile);
+
+ my $packageFile = $sisfile;
+ $packageFile =~ s/\.sis/.pkg/g;
+
+ my $absPackageFile = "${PKG_DIR}\\${packageFile}";
+ open PKG, "${absPackageFile}" or die "Cannot open ${absPackageFile}\n";
+
+ my $componentUID = '';
+ while (<PKG>) {
+ chomp;
+
+ # Extract the component uid
+ if (s/\s*\#.*\(([0-9A-Fa-fx]+)\).*/$1/) {
+ $componentUID = $_;
+ }
+ }
+ close PKG;
+
+ if ($componentUID eq "") {
+ die "Cannot extract UID from package ${absPackageFile}\n";
+ }
+ return $componentUID;
+}