secureswitools/swisistools/source/createsis/createsis.pl
changeset 4 32704c33136d
child 75 2d2d25361590
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/secureswitools/swisistools/source/createsis/createsis.pl	Tue Jan 26 12:06:03 2010 +0200
@@ -0,0 +1,639 @@
+#
+# 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: 
+#
+
+
+use Getopt::Long;
+use strict;
+
+my %Options = ();
+my $num_options;
+my $key = '';
+my $cert = '';
+my $passphrase = '';
+my $pkgfile = '';
+my $sisfile_ip = '';
+my $sisfile_op = '';
+my @languages = ();
+my @package_components = ();
+my @vendor = ();
+my $commonName = '';
+my $vendorName = '';
+my $error_para;
+
+
+# THE MAIN PROGRAM SECTION
+##########################
+{
+  # process the command-line
+  $num_options = @ARGV;
+
+  unless (GetOptions(\%Options, 'key=s' => \$key, 'cert=s'=> \$cert, 
+		     'pass=s' => \$passphrase, 'help|h|?')) {
+    &Usage();
+    exit 1;
+  }
+    
+  if ($Options{help}) {
+    &Usage();
+  }
+  
+  $num_options = @ARGV;
+
+  my $action=uc shift @ARGV;
+
+  unless ($action=~/^(CREATE|SIGN|DUMP|STRIP)$/o) {
+    print STDERR "Unknown createsis's action: $action\n\n";
+    &Usage();
+    exit 1;
+  }
+    
+  if ($action eq 'CREATE') {
+    &createFunc();
+  }
+
+  if ($action eq 'SIGN') {
+    &signFunc();
+  }
+
+  if ($action eq 'DUMP') {
+    &dumpFunc();
+  }
+
+  if ($action eq 'STRIP') {
+    &stripFunc();
+  }
+    
+  exit 0;
+}
+
+
+# The implemetation of 'createsis create ...'
+sub createFunc() {
+  #
+  # Perform parameters check
+  #
+ my $has_key = ($key ne '');
+ my $has_cert = ($cert ne '');
+
+  if ($has_key && !$has_cert) {
+    print STDERR "Missing \'-cert\' option.\n";
+    exit 1;
+  }
+
+  if (!$has_key && $has_cert) {
+    print STDERR "Missing \'-key\' option.\n";
+    exit 1;
+  }
+
+  if (@ARGV == 0) {
+    print STDERR "Package file not found.\n";
+    exit 1;
+  }
+
+  $pkgfile = shift @ARGV;
+
+  unless (@ARGV == 0) {
+    $error_para = shift @ARGV;
+    print STDERR "Unknown parameter \"$error_para\" in the command line\n";
+    exit 1;
+  }
+
+  # subst .SIS for .pkg in the package file name
+  $sisfile_ip = $pkgfile;
+  $sisfile_ip =~ s/\.pkg$//i;
+  
+  (system "makesis \"$pkgfile\" \"$sisfile_ip-tmp.SIS\"") == 0 or
+    die "ERROR! Failed at makesis \"$pkgfile\"\n";
+
+  # if key/cert are not found in the command line, try to extract them from the pkgfile
+  # else generate DN and makekeys.
+  if (!$has_key && !$has_cert) {
+	
+    unless (&extractPackageInfo() == 0) {
+      print STDERR "Failed on extracting info from package file\n";
+      exit 1;
+    }
+	
+    # Let's generate cert/key
+    if (($key eq '') && ($cert eq '')) {
+
+      my $key_index = 0;
+
+      print "No key/cert found in $pkgfile.\n";
+
+      unless (&generateDN() == 0) {
+   	print STDERR "Failed to generate distinguished-name-string(DN)\n";
+   	exit 1;
+      }
+
+      # Specified the generated key/cert filenames
+      $key = "key-gen.key";
+      $cert = "cert-gen.cer";
+
+      # if $key file exist, we need to index the new files
+      while (-e $key) {
+	$key_index++;
+	$key = "key-gen".$key_index.".key";
+	$cert = "cert-gen".$key_index.".cer";
+      }
+
+      print "making $key, $cert ...\n";
+
+      if ($passphrase eq '') {
+	my $pwd_temp = '';
+	
+	print "\n Could not find passphrase in command-line or $pkgfile!\n";
+	
+	for (;;) {
+	  print " Please enter ENTER passphrase (at least 4 letters): ";
+	  
+	  $pwd_temp = <STDIN>;
+	  
+	  if (length ($pwd_temp) > 4) {
+	    last;
+	  }
+	}
+
+	chomp $pwd_temp;
+
+	$passphrase = $pwd_temp;
+      }
+
+      (system "makekeys \-cert \-password \"$passphrase\" \-dname \"CN=$commonName OR=$vendorName\" $key $cert") == 0 or
+	die "ERROR! Failed at makekeys... \n";
+    } else {
+      print "Found $key $cert from $pkgfile.\n"
+    }
+  }
+
+  # Construct the input sis filename and output sis filename
+  $sisfile_op = "$sisfile_ip.SIS";
+  $sisfile_ip = "$sisfile_ip-tmp.SIS";
+
+  print "Signing $sisfile_ip with $cert and $key -> $sisfile_op\n";
+
+  if (defined $passphrase) {
+    system ("signsis \-s \"$sisfile_ip\" \"$sisfile_op\" \"$cert\" \"$key\" \"$passphrase\"") == 0 or
+      die "ERROR! Failed at signsis \-s \"$sisfile_ip\" \"$sisfile_op\" \"$cert\" \"$key\" $passphrase\n";
+  } else {
+    system ("signsis \-s $sisfile_ip $sisfile_op \"$cert\" \"$key\"") == 0 or
+      die "ERROR! Failed at signsis \-s \"$sisfile_ip\" \"$sisfile_op\" \"$cert\" \"$key\"\n";
+  }
+  
+  # delete the temporary file
+  unlink $sisfile_ip;
+  
+}
+
+
+# The implemetation of 'createsis sign ...'
+sub signFunc() {
+
+  my $commandline;
+
+  $sisfile_ip=shift @ARGV;
+
+  unless (defined $sisfile_ip) {
+    print STDERR "Input SIS file not found.\n";
+    exit 1;
+  }
+
+  $sisfile_op=shift @ARGV;
+
+  unless (defined $sisfile_op) {
+    print STDERR "Output SIS file not found.\n";
+    exit 1;
+  }
+
+  unless (@ARGV == 0) {
+    $error_para = shift @ARGV;
+    print STDERR "Unknown parameter \"$error_para\" in the command line\n";
+    exit 1;
+  }
+
+  if ($cert eq '') {
+    print STDERR "certificate not found.\n";
+    exit 1;
+  }
+
+  if ($key eq '') {
+    print STDERR "key not found.\n";
+    exit 1;
+  }
+
+  $commandline = "signsis \-s \"$sisfile_ip\" \"$sisfile_op\" \"$cert\" \"$key\"";
+
+  print "signing input file $sisfile_ip -> $sisfile_op ...\n";
+
+  if ($passphrase ne '') {
+    $commandline .= " \"$passphrase\"";
+  }
+
+  (system $commandline) == 0 or
+    die "ERROR! Failed at signsis ... \n";
+
+  unless (@ARGV == 0) {
+    $error_para = shift @ARGV;
+    print STDERR "Unknown parameter \"$error_para\" in the command line\n";
+    exit 1;
+  }
+}
+
+
+# The implemetation of 'createsis dump ...'
+sub dumpFunc() {
+
+  if ($key ne '') {
+    print STDERR "\"-key $key\" not supported\n";
+    exit 1;
+  }
+
+  if ($cert ne '') {
+    print STDERR "\"-cert $cert\" not supported\n";
+    exit 1;
+  }
+
+  if ($passphrase ne '') {
+    print STDERR "\"-pass $passphrase\" not supported\n";
+    exit 1;
+  }
+
+  $sisfile_ip=shift @ARGV;
+
+  unless (defined $sisfile_ip) {
+    print STDERR "Input SIS file not found.\n";
+    exit 1;
+  }
+
+  unless (@ARGV == 0) {
+    $error_para = shift @ARGV;
+    print STDERR "Unknown parameter \"$error_para\" in the command line\n";
+    exit 1;	
+  }
+
+  (system "signsis -o \"$sisfile_ip\"")  == 0 or
+    die "ERROR! Failed at signsis ... \n";
+}
+
+
+# The implemetation of 'createsis strip ...'
+sub stripFunc() {
+
+  if ($key ne '') {
+    print STDERR "\"-key $key\" not supported\n";
+    exit 1;
+  }
+
+  if ($cert ne '') {
+    print STDERR "\"-cert $cert\" not supported\n";
+    exit 1;
+  }
+
+  if ($passphrase ne '') {
+    print STDERR "\"-pass $passphrase\" not supported\n";
+    exit 1;
+  }
+
+  $sisfile_ip=shift @ARGV;
+
+  unless (defined $sisfile_ip) {
+    print STDERR "Input SIS file not found.\n";
+    exit 1;
+  }
+
+  $sisfile_op=shift @ARGV;
+
+  unless (defined $sisfile_op) {
+    print STDERR "Output SIS file not found.\n";
+    exit 1;
+  }
+
+  unless (@ARGV == 0) {
+    $error_para = shift @ARGV;
+    print STDERR "Unknown parameter \"$error_para\" in the command line\n";
+    exit 1;	
+  }
+
+  (system "signsis -u \"$sisfile_ip\" \"$sisfile_op\"") == 0 or
+    die "ERROR! Failed at signsis ... \n";
+}
+
+
+# Extract info. from package file.
+sub extractPackageInfo() {
+  my @pkg_data;
+  my $process_line = '';
+  my $quote_open = 0;
+  my $pkg_component_temp = '';
+  my $vendor_temp = '';
+  my $signature_temp = '';
+  my @signature = ();
+
+  print "Extracting info. from $pkgfile ...\n";
+
+  open (PKGFILE, "$pkgfile") or 
+    die "ERROR! Can't open $pkgfile\n";
+
+  @pkg_data = <PKGFILE>;
+
+  PKG_LINE: foreach my $pkg_line (@pkg_data) {
+
+      # split the line into an array
+      my @line_char = split (//,$pkg_line);
+
+    CHAR: for (my $char_pos = 0; $char_pos < $#line_char; $char_pos++) {
+	
+	if ($line_char[$char_pos] eq '&' || $process_line eq 'lang') {
+
+	  ############## languages ##############
+	  $process_line = 'lang';
+	  
+	  if ($line_char[$char_pos] eq ';') {
+	    # comment line
+	    # ignore it
+	    $process_line = '';
+	    next PKG_LINE;
+
+	  } elsif ($line_char[$char_pos] =~ /[a-z|A-Z]/) {
+	    my $lang_temp = uc ($line_char[$char_pos++].$line_char[$char_pos]);
+		$char_pos++;
+			if($line_char[$char_pos] eq '(')
+				{
+				$char_pos++;
+				my $lang_temp = uc ($lang_temp.$line_char[$char_pos]);
+				$char_pos++;
+				}
+			else
+				{
+				$char_pos--;
+				}
+	    push (@languages, $lang_temp);
+	    
+	    if ($char_pos < $#line_char){
+	      next CHAR;
+	    }
+	  } elsif ($line_char[$char_pos] eq ' ' ||
+		   $line_char[$char_pos] eq '&' ||
+		   $line_char[$char_pos] eq ',') {
+	    next CHAR;
+	  } else {
+	    $process_line = '';
+	    
+	    # redo this last line, as there are unknown character in this languages line
+	    redo PKG_LINE;
+	  }
+	} #if ($line_char[$char_pos] eq '&' || $process_line eq 'lang')
+
+
+	if ($line_char[$char_pos] eq '*' || $process_line eq 'key_cert') {
+	  ############### package-signature ##############
+	
+	  $process_line = 'key_cert';
+
+	  if ($line_char[$char_pos] eq '"') {
+	    if ($quote_open == 1) {
+	      # set to false (0)
+	      $quote_open = 0;
+
+	      push (@signature, $signature_temp);
+	      
+	      # clear the content
+	      $signature_temp = '';
+	    } else {
+	      # set to true (1)
+	      $quote_open = 1;
+	    }
+
+	    next CHAR;
+
+	  } elsif ($quote_open == 1) {
+	    # append the signature
+	    $signature_temp .= $line_char[$char_pos];
+	    next CHAR;
+
+	  } elsif ($line_char[$char_pos] eq ' ' ||
+		   $line_char[$char_pos] eq '*' ||
+		   $line_char[$char_pos] eq ',' ||
+		   $line_char[$char_pos] eq '=' ||
+		   uc ($line_char[$char_pos]) eq 'K' ||
+		   uc ($line_char[$char_pos]) eq 'E' ||
+		   uc ($line_char[$char_pos]) eq 'Y') {
+	    next CHAR;
+	    
+	  } else {
+	    # Exit extracting key/cert
+	    
+	    $key = $signature[0];
+	    $cert = $signature[1];
+	    
+	    if ($#signature == 2 ) {
+	      if ($passphrase eq '') {
+		$passphrase = $signature[2];
+	      }
+	    }
+
+	    $process_line = '';
+
+	    # redo this last line, as there are unknown character in the signature line
+	    redo PKG_LINE;
+	  }
+
+	  last;
+	} # if ($line_char[$char_pos] eq '*' || $process_line eq 'key_cert')
+	
+	
+	if ($line_char[$char_pos] eq '#' || $process_line eq 'pkg_hdr') {
+
+	  ############## package-header ##############
+	  $process_line = 'pkg_hdr';
+	  
+	  if ($line_char[$char_pos] eq '"') {
+	    if ($quote_open == 1) {
+	      # set to false (0)
+	      $quote_open = 0;
+
+	      push (@package_components, $pkg_component_temp);
+	      
+	      # clear the content
+	      $pkg_component_temp = '';
+	    } else {
+	      # set to true (1)
+	      $quote_open = 1;
+	    }
+
+	    next CHAR;
+
+	  } elsif ($quote_open == 1) {
+	    # append the package component
+	    $pkg_component_temp .= $line_char[$char_pos];
+	    next CHAR;
+
+	  } elsif ($line_char[$char_pos] eq '}') {
+	    # Exit package-hearder processes
+	    $process_line = '';
+	    next PKG_LINE;
+
+	  } elsif ($line_char[$char_pos] eq ' ' ||
+		   $line_char[$char_pos] eq '#' ||
+		   $line_char[$char_pos] eq ',' ||
+		   $line_char[$char_pos] eq '{') {
+	    next CHAR;
+
+	  }
+	} # if ($line_char[$char_pos] eq '#' || $process_line eq 'pkg_hdr')
+	
+	
+	if ($line_char[$char_pos] eq '%' || $process_line eq 'vendor') {
+	  
+	  ############### vendor ##############
+	  $process_line = 'vendor';
+	  
+	  if ($line_char[$char_pos] eq '"') {
+	    if ($quote_open == 1) {
+	      # set to false (0)
+	      $quote_open = 0;
+	      
+	      push (@vendor, $vendor_temp);
+	      
+	      # clear the content
+	      $vendor_temp = '';
+	    } else {
+	      # set to true (1)
+	      $quote_open = 1;
+	    }
+
+	    next CHAR;
+
+	  } elsif ($quote_open == 1) {
+	    # append the vendor
+	    $vendor_temp .= $line_char[$char_pos];
+	    next CHAR;
+
+	  } elsif ($line_char[$char_pos] eq '}') {
+	    # Exit the vendor processes
+	    $process_line = '';
+	    next PKG_LINE;
+
+	  } elsif ($line_char[$char_pos] eq ' ' ||
+		   $line_char[$char_pos] eq '%' ||
+		   $line_char[$char_pos] eq ',' ||
+		   $line_char[$char_pos] eq '{') {
+	    next CHAR;
+	  }
+
+	  last;
+	} # if ($line_char[$char_pos] eq '%') {
+
+      if ($line_char[$char_pos] eq ';') {
+	# comment line
+	# ignore it
+	last;
+      }
+
+      last;
+    }
+  }
+    
+  close(PKGFILE);
+  return 0;
+}
+
+# Generate the distinguished-name-string for the self-signed public key certificate file.
+sub generateDN() {
+  my @pkg_data;
+  my $en_pos = 0;
+  my $lang_pos = 0;
+  
+  # Find out the position of English in the list (if present)
+  for(; $lang_pos <= $#languages; $lang_pos++) {
+    
+    if ($languages[$lang_pos] eq 'EN') {
+      $en_pos = $lang_pos;
+      
+      last;
+    }
+  }
+
+  $commonName = $package_components[$en_pos];
+  $vendorName = $vendor[$en_pos];
+  
+  # Patch the $commonName upto 64 byte of random hex
+  for (my $count = length ($commonName); $count<65; $count++) {
+    $commonName .= sprintf "%.2x", int rand(255);
+  }
+  
+  return 0;
+}
+
+
+# Print the Usage descriptions
+sub Usage () {
+  print <<ENDUSAGESTRING;
+
+createsis, version 1.0
+Copyright (c) 2005 Symbian Software Ltd. All rights reserved.
+
+Mandatory SIS file signing for SYMBIAN OS v9.1 onwards. It supports
+creating new SIS files from package files, signs existing package files and
+generates new key/certificate pairs for purposes of signing. If neither
+certificate or key are specified as outlined in the usage scenarios below,
+a self-signed certificate will be generated and used to sign the resulting
+SIS file. In addition, createsis may be used to dump details of signatures
+and certificate chains in a pre-existing SIS file.
+
+Usage : createsis [-h | -?] <action>
+
+ Options:
+    -h Show this help page
+    -? Show this help page
+
+ action: 
+    create
+    Description : Create and sign the generated sisfile.
+    Usage : createsis create [-key <key>] [-cert <cert>] [-pass <pass>] pkgfile
+            -key        [optional]The certificate's private key file
+            -cert       [optional]The certificate file used for signing
+            -pass       [depend on how key/cert was generated OR 
+                         can use this option to specify the passphase for the new key/cert]
+                         The certificate's private key file's passphrase
+            pkgfile     The input package file.
+
+    sign
+    Description : Sign the sisfile.
+    Usage : createsis sign -key <key> -cert <cert> [-pass <pass>] sis_input sis_output
+            -key        The certificate's private key file
+            -cert       The certificate file used for signing
+            -pass       [depend on how key/cert was generated]The certificate's private 
+                         key file's passphrase
+	    -sis_input  The SIS file to be signed
+	    -sis_output The SIS file generated by signing
+
+    dump
+    Description : Display details of all valid signatures and the associated certificates
+    in the sisfile.
+    Usage : createsis dump sis_input
+	    -sis_input  The investigated SIS file
+ 
+    strip
+    Description : Remove most recent signature from SIS file
+    Usage : createsis strip sis_input sis_output
+	    -sis_input  The SIS file whose recent signature will be removed
+	    -sis_output The SIS file after signature removed
+
+ENDUSAGESTRING
+
+  exit 0;
+}