secureswitools/swisistools/source/createsis/createsis.pl
changeset 0 ba25891c3a9e
child 75 2d2d25361590
equal deleted inserted replaced
-1:000000000000 0:ba25891c3a9e
       
     1 #
       
     2 # Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 # All rights reserved.
       
     4 # This component and the accompanying materials are made available
       
     5 # under the terms of the License "Eclipse Public License v1.0"
       
     6 # which accompanies this distribution, and is available
       
     7 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 #
       
     9 # Initial Contributors:
       
    10 # Nokia Corporation - initial contribution.
       
    11 #
       
    12 # Contributors:
       
    13 #
       
    14 # Description: 
       
    15 #
       
    16 
       
    17 
       
    18 use Getopt::Long;
       
    19 use strict;
       
    20 
       
    21 my %Options = ();
       
    22 my $num_options;
       
    23 my $key = '';
       
    24 my $cert = '';
       
    25 my $passphrase = '';
       
    26 my $pkgfile = '';
       
    27 my $sisfile_ip = '';
       
    28 my $sisfile_op = '';
       
    29 my @languages = ();
       
    30 my @package_components = ();
       
    31 my @vendor = ();
       
    32 my $commonName = '';
       
    33 my $vendorName = '';
       
    34 my $error_para;
       
    35 
       
    36 
       
    37 # THE MAIN PROGRAM SECTION
       
    38 ##########################
       
    39 {
       
    40   # process the command-line
       
    41   $num_options = @ARGV;
       
    42 
       
    43   unless (GetOptions(\%Options, 'key=s' => \$key, 'cert=s'=> \$cert, 
       
    44 		     'pass=s' => \$passphrase, 'help|h|?')) {
       
    45     &Usage();
       
    46     exit 1;
       
    47   }
       
    48     
       
    49   if ($Options{help}) {
       
    50     &Usage();
       
    51   }
       
    52   
       
    53   $num_options = @ARGV;
       
    54 
       
    55   my $action=uc shift @ARGV;
       
    56 
       
    57   unless ($action=~/^(CREATE|SIGN|DUMP|STRIP)$/o) {
       
    58     print STDERR "Unknown createsis's action: $action\n\n";
       
    59     &Usage();
       
    60     exit 1;
       
    61   }
       
    62     
       
    63   if ($action eq 'CREATE') {
       
    64     &createFunc();
       
    65   }
       
    66 
       
    67   if ($action eq 'SIGN') {
       
    68     &signFunc();
       
    69   }
       
    70 
       
    71   if ($action eq 'DUMP') {
       
    72     &dumpFunc();
       
    73   }
       
    74 
       
    75   if ($action eq 'STRIP') {
       
    76     &stripFunc();
       
    77   }
       
    78     
       
    79   exit 0;
       
    80 }
       
    81 
       
    82 
       
    83 # The implemetation of 'createsis create ...'
       
    84 sub createFunc() {
       
    85   #
       
    86   # Perform parameters check
       
    87   #
       
    88  my $has_key = ($key ne '');
       
    89  my $has_cert = ($cert ne '');
       
    90 
       
    91   if ($has_key && !$has_cert) {
       
    92     print STDERR "Missing \'-cert\' option.\n";
       
    93     exit 1;
       
    94   }
       
    95 
       
    96   if (!$has_key && $has_cert) {
       
    97     print STDERR "Missing \'-key\' option.\n";
       
    98     exit 1;
       
    99   }
       
   100 
       
   101   if (@ARGV == 0) {
       
   102     print STDERR "Package file not found.\n";
       
   103     exit 1;
       
   104   }
       
   105 
       
   106   $pkgfile = shift @ARGV;
       
   107 
       
   108   unless (@ARGV == 0) {
       
   109     $error_para = shift @ARGV;
       
   110     print STDERR "Unknown parameter \"$error_para\" in the command line\n";
       
   111     exit 1;
       
   112   }
       
   113 
       
   114   # subst .SIS for .pkg in the package file name
       
   115   $sisfile_ip = $pkgfile;
       
   116   $sisfile_ip =~ s/\.pkg$//i;
       
   117   
       
   118   (system "makesis \"$pkgfile\" \"$sisfile_ip-tmp.SIS\"") == 0 or
       
   119     die "ERROR! Failed at makesis \"$pkgfile\"\n";
       
   120 
       
   121   # if key/cert are not found in the command line, try to extract them from the pkgfile
       
   122   # else generate DN and makekeys.
       
   123   if (!$has_key && !$has_cert) {
       
   124 	
       
   125     unless (&extractPackageInfo() == 0) {
       
   126       print STDERR "Failed on extracting info from package file\n";
       
   127       exit 1;
       
   128     }
       
   129 	
       
   130     # Let's generate cert/key
       
   131     if (($key eq '') && ($cert eq '')) {
       
   132 
       
   133       my $key_index = 0;
       
   134 
       
   135       print "No key/cert found in $pkgfile.\n";
       
   136 
       
   137       unless (&generateDN() == 0) {
       
   138    	print STDERR "Failed to generate distinguished-name-string(DN)\n";
       
   139    	exit 1;
       
   140       }
       
   141 
       
   142       # Specified the generated key/cert filenames
       
   143       $key = "key-gen.key";
       
   144       $cert = "cert-gen.cer";
       
   145 
       
   146       # if $key file exist, we need to index the new files
       
   147       while (-e $key) {
       
   148 	$key_index++;
       
   149 	$key = "key-gen".$key_index.".key";
       
   150 	$cert = "cert-gen".$key_index.".cer";
       
   151       }
       
   152 
       
   153       print "making $key, $cert ...\n";
       
   154 
       
   155       if ($passphrase eq '') {
       
   156 	my $pwd_temp = '';
       
   157 	
       
   158 	print "\n Could not find passphrase in command-line or $pkgfile!\n";
       
   159 	
       
   160 	for (;;) {
       
   161 	  print " Please enter ENTER passphrase (at least 4 letters): ";
       
   162 	  
       
   163 	  $pwd_temp = <STDIN>;
       
   164 	  
       
   165 	  if (length ($pwd_temp) > 4) {
       
   166 	    last;
       
   167 	  }
       
   168 	}
       
   169 
       
   170 	chomp $pwd_temp;
       
   171 
       
   172 	$passphrase = $pwd_temp;
       
   173       }
       
   174 
       
   175       (system "makekeys \-cert \-password \"$passphrase\" \-dname \"CN=$commonName OR=$vendorName\" $key $cert") == 0 or
       
   176 	die "ERROR! Failed at makekeys... \n";
       
   177     } else {
       
   178       print "Found $key $cert from $pkgfile.\n"
       
   179     }
       
   180   }
       
   181 
       
   182   # Construct the input sis filename and output sis filename
       
   183   $sisfile_op = "$sisfile_ip.SIS";
       
   184   $sisfile_ip = "$sisfile_ip-tmp.SIS";
       
   185 
       
   186   print "Signing $sisfile_ip with $cert and $key -> $sisfile_op\n";
       
   187 
       
   188   if (defined $passphrase) {
       
   189     system ("signsis \-s \"$sisfile_ip\" \"$sisfile_op\" \"$cert\" \"$key\" \"$passphrase\"") == 0 or
       
   190       die "ERROR! Failed at signsis \-s \"$sisfile_ip\" \"$sisfile_op\" \"$cert\" \"$key\" $passphrase\n";
       
   191   } else {
       
   192     system ("signsis \-s $sisfile_ip $sisfile_op \"$cert\" \"$key\"") == 0 or
       
   193       die "ERROR! Failed at signsis \-s \"$sisfile_ip\" \"$sisfile_op\" \"$cert\" \"$key\"\n";
       
   194   }
       
   195   
       
   196   # delete the temporary file
       
   197   unlink $sisfile_ip;
       
   198   
       
   199 }
       
   200 
       
   201 
       
   202 # The implemetation of 'createsis sign ...'
       
   203 sub signFunc() {
       
   204 
       
   205   my $commandline;
       
   206 
       
   207   $sisfile_ip=shift @ARGV;
       
   208 
       
   209   unless (defined $sisfile_ip) {
       
   210     print STDERR "Input SIS file not found.\n";
       
   211     exit 1;
       
   212   }
       
   213 
       
   214   $sisfile_op=shift @ARGV;
       
   215 
       
   216   unless (defined $sisfile_op) {
       
   217     print STDERR "Output SIS file not found.\n";
       
   218     exit 1;
       
   219   }
       
   220 
       
   221   unless (@ARGV == 0) {
       
   222     $error_para = shift @ARGV;
       
   223     print STDERR "Unknown parameter \"$error_para\" in the command line\n";
       
   224     exit 1;
       
   225   }
       
   226 
       
   227   if ($cert eq '') {
       
   228     print STDERR "certificate not found.\n";
       
   229     exit 1;
       
   230   }
       
   231 
       
   232   if ($key eq '') {
       
   233     print STDERR "key not found.\n";
       
   234     exit 1;
       
   235   }
       
   236 
       
   237   $commandline = "signsis \-s \"$sisfile_ip\" \"$sisfile_op\" \"$cert\" \"$key\"";
       
   238 
       
   239   print "signing input file $sisfile_ip -> $sisfile_op ...\n";
       
   240 
       
   241   if ($passphrase ne '') {
       
   242     $commandline .= " \"$passphrase\"";
       
   243   }
       
   244 
       
   245   (system $commandline) == 0 or
       
   246     die "ERROR! Failed at signsis ... \n";
       
   247 
       
   248   unless (@ARGV == 0) {
       
   249     $error_para = shift @ARGV;
       
   250     print STDERR "Unknown parameter \"$error_para\" in the command line\n";
       
   251     exit 1;
       
   252   }
       
   253 }
       
   254 
       
   255 
       
   256 # The implemetation of 'createsis dump ...'
       
   257 sub dumpFunc() {
       
   258 
       
   259   if ($key ne '') {
       
   260     print STDERR "\"-key $key\" not supported\n";
       
   261     exit 1;
       
   262   }
       
   263 
       
   264   if ($cert ne '') {
       
   265     print STDERR "\"-cert $cert\" not supported\n";
       
   266     exit 1;
       
   267   }
       
   268 
       
   269   if ($passphrase ne '') {
       
   270     print STDERR "\"-pass $passphrase\" not supported\n";
       
   271     exit 1;
       
   272   }
       
   273 
       
   274   $sisfile_ip=shift @ARGV;
       
   275 
       
   276   unless (defined $sisfile_ip) {
       
   277     print STDERR "Input SIS file not found.\n";
       
   278     exit 1;
       
   279   }
       
   280 
       
   281   unless (@ARGV == 0) {
       
   282     $error_para = shift @ARGV;
       
   283     print STDERR "Unknown parameter \"$error_para\" in the command line\n";
       
   284     exit 1;	
       
   285   }
       
   286 
       
   287   (system "signsis -o \"$sisfile_ip\"")  == 0 or
       
   288     die "ERROR! Failed at signsis ... \n";
       
   289 }
       
   290 
       
   291 
       
   292 # The implemetation of 'createsis strip ...'
       
   293 sub stripFunc() {
       
   294 
       
   295   if ($key ne '') {
       
   296     print STDERR "\"-key $key\" not supported\n";
       
   297     exit 1;
       
   298   }
       
   299 
       
   300   if ($cert ne '') {
       
   301     print STDERR "\"-cert $cert\" not supported\n";
       
   302     exit 1;
       
   303   }
       
   304 
       
   305   if ($passphrase ne '') {
       
   306     print STDERR "\"-pass $passphrase\" not supported\n";
       
   307     exit 1;
       
   308   }
       
   309 
       
   310   $sisfile_ip=shift @ARGV;
       
   311 
       
   312   unless (defined $sisfile_ip) {
       
   313     print STDERR "Input SIS file not found.\n";
       
   314     exit 1;
       
   315   }
       
   316 
       
   317   $sisfile_op=shift @ARGV;
       
   318 
       
   319   unless (defined $sisfile_op) {
       
   320     print STDERR "Output SIS file not found.\n";
       
   321     exit 1;
       
   322   }
       
   323 
       
   324   unless (@ARGV == 0) {
       
   325     $error_para = shift @ARGV;
       
   326     print STDERR "Unknown parameter \"$error_para\" in the command line\n";
       
   327     exit 1;	
       
   328   }
       
   329 
       
   330   (system "signsis -u \"$sisfile_ip\" \"$sisfile_op\"") == 0 or
       
   331     die "ERROR! Failed at signsis ... \n";
       
   332 }
       
   333 
       
   334 
       
   335 # Extract info. from package file.
       
   336 sub extractPackageInfo() {
       
   337   my @pkg_data;
       
   338   my $process_line = '';
       
   339   my $quote_open = 0;
       
   340   my $pkg_component_temp = '';
       
   341   my $vendor_temp = '';
       
   342   my $signature_temp = '';
       
   343   my @signature = ();
       
   344 
       
   345   print "Extracting info. from $pkgfile ...\n";
       
   346 
       
   347   open (PKGFILE, "$pkgfile") or 
       
   348     die "ERROR! Can't open $pkgfile\n";
       
   349 
       
   350   @pkg_data = <PKGFILE>;
       
   351 
       
   352   PKG_LINE: foreach my $pkg_line (@pkg_data) {
       
   353 
       
   354       # split the line into an array
       
   355       my @line_char = split (//,$pkg_line);
       
   356 
       
   357     CHAR: for (my $char_pos = 0; $char_pos < $#line_char; $char_pos++) {
       
   358 	
       
   359 	if ($line_char[$char_pos] eq '&' || $process_line eq 'lang') {
       
   360 
       
   361 	  ############## languages ##############
       
   362 	  $process_line = 'lang';
       
   363 	  
       
   364 	  if ($line_char[$char_pos] eq ';') {
       
   365 	    # comment line
       
   366 	    # ignore it
       
   367 	    $process_line = '';
       
   368 	    next PKG_LINE;
       
   369 
       
   370 	  } elsif ($line_char[$char_pos] =~ /[a-z|A-Z]/) {
       
   371 	    my $lang_temp = uc ($line_char[$char_pos++].$line_char[$char_pos]);
       
   372 		$char_pos++;
       
   373 			if($line_char[$char_pos] eq '(')
       
   374 				{
       
   375 				$char_pos++;
       
   376 				my $lang_temp = uc ($lang_temp.$line_char[$char_pos]);
       
   377 				$char_pos++;
       
   378 				}
       
   379 			else
       
   380 				{
       
   381 				$char_pos--;
       
   382 				}
       
   383 	    push (@languages, $lang_temp);
       
   384 	    
       
   385 	    if ($char_pos < $#line_char){
       
   386 	      next CHAR;
       
   387 	    }
       
   388 	  } elsif ($line_char[$char_pos] eq ' ' ||
       
   389 		   $line_char[$char_pos] eq '&' ||
       
   390 		   $line_char[$char_pos] eq ',') {
       
   391 	    next CHAR;
       
   392 	  } else {
       
   393 	    $process_line = '';
       
   394 	    
       
   395 	    # redo this last line, as there are unknown character in this languages line
       
   396 	    redo PKG_LINE;
       
   397 	  }
       
   398 	} #if ($line_char[$char_pos] eq '&' || $process_line eq 'lang')
       
   399 
       
   400 
       
   401 	if ($line_char[$char_pos] eq '*' || $process_line eq 'key_cert') {
       
   402 	  ############### package-signature ##############
       
   403 	
       
   404 	  $process_line = 'key_cert';
       
   405 
       
   406 	  if ($line_char[$char_pos] eq '"') {
       
   407 	    if ($quote_open == 1) {
       
   408 	      # set to false (0)
       
   409 	      $quote_open = 0;
       
   410 
       
   411 	      push (@signature, $signature_temp);
       
   412 	      
       
   413 	      # clear the content
       
   414 	      $signature_temp = '';
       
   415 	    } else {
       
   416 	      # set to true (1)
       
   417 	      $quote_open = 1;
       
   418 	    }
       
   419 
       
   420 	    next CHAR;
       
   421 
       
   422 	  } elsif ($quote_open == 1) {
       
   423 	    # append the signature
       
   424 	    $signature_temp .= $line_char[$char_pos];
       
   425 	    next CHAR;
       
   426 
       
   427 	  } elsif ($line_char[$char_pos] eq ' ' ||
       
   428 		   $line_char[$char_pos] eq '*' ||
       
   429 		   $line_char[$char_pos] eq ',' ||
       
   430 		   $line_char[$char_pos] eq '=' ||
       
   431 		   uc ($line_char[$char_pos]) eq 'K' ||
       
   432 		   uc ($line_char[$char_pos]) eq 'E' ||
       
   433 		   uc ($line_char[$char_pos]) eq 'Y') {
       
   434 	    next CHAR;
       
   435 	    
       
   436 	  } else {
       
   437 	    # Exit extracting key/cert
       
   438 	    
       
   439 	    $key = $signature[0];
       
   440 	    $cert = $signature[1];
       
   441 	    
       
   442 	    if ($#signature == 2 ) {
       
   443 	      if ($passphrase eq '') {
       
   444 		$passphrase = $signature[2];
       
   445 	      }
       
   446 	    }
       
   447 
       
   448 	    $process_line = '';
       
   449 
       
   450 	    # redo this last line, as there are unknown character in the signature line
       
   451 	    redo PKG_LINE;
       
   452 	  }
       
   453 
       
   454 	  last;
       
   455 	} # if ($line_char[$char_pos] eq '*' || $process_line eq 'key_cert')
       
   456 	
       
   457 	
       
   458 	if ($line_char[$char_pos] eq '#' || $process_line eq 'pkg_hdr') {
       
   459 
       
   460 	  ############## package-header ##############
       
   461 	  $process_line = 'pkg_hdr';
       
   462 	  
       
   463 	  if ($line_char[$char_pos] eq '"') {
       
   464 	    if ($quote_open == 1) {
       
   465 	      # set to false (0)
       
   466 	      $quote_open = 0;
       
   467 
       
   468 	      push (@package_components, $pkg_component_temp);
       
   469 	      
       
   470 	      # clear the content
       
   471 	      $pkg_component_temp = '';
       
   472 	    } else {
       
   473 	      # set to true (1)
       
   474 	      $quote_open = 1;
       
   475 	    }
       
   476 
       
   477 	    next CHAR;
       
   478 
       
   479 	  } elsif ($quote_open == 1) {
       
   480 	    # append the package component
       
   481 	    $pkg_component_temp .= $line_char[$char_pos];
       
   482 	    next CHAR;
       
   483 
       
   484 	  } elsif ($line_char[$char_pos] eq '}') {
       
   485 	    # Exit package-hearder processes
       
   486 	    $process_line = '';
       
   487 	    next PKG_LINE;
       
   488 
       
   489 	  } elsif ($line_char[$char_pos] eq ' ' ||
       
   490 		   $line_char[$char_pos] eq '#' ||
       
   491 		   $line_char[$char_pos] eq ',' ||
       
   492 		   $line_char[$char_pos] eq '{') {
       
   493 	    next CHAR;
       
   494 
       
   495 	  }
       
   496 	} # if ($line_char[$char_pos] eq '#' || $process_line eq 'pkg_hdr')
       
   497 	
       
   498 	
       
   499 	if ($line_char[$char_pos] eq '%' || $process_line eq 'vendor') {
       
   500 	  
       
   501 	  ############### vendor ##############
       
   502 	  $process_line = 'vendor';
       
   503 	  
       
   504 	  if ($line_char[$char_pos] eq '"') {
       
   505 	    if ($quote_open == 1) {
       
   506 	      # set to false (0)
       
   507 	      $quote_open = 0;
       
   508 	      
       
   509 	      push (@vendor, $vendor_temp);
       
   510 	      
       
   511 	      # clear the content
       
   512 	      $vendor_temp = '';
       
   513 	    } else {
       
   514 	      # set to true (1)
       
   515 	      $quote_open = 1;
       
   516 	    }
       
   517 
       
   518 	    next CHAR;
       
   519 
       
   520 	  } elsif ($quote_open == 1) {
       
   521 	    # append the vendor
       
   522 	    $vendor_temp .= $line_char[$char_pos];
       
   523 	    next CHAR;
       
   524 
       
   525 	  } elsif ($line_char[$char_pos] eq '}') {
       
   526 	    # Exit the vendor processes
       
   527 	    $process_line = '';
       
   528 	    next PKG_LINE;
       
   529 
       
   530 	  } elsif ($line_char[$char_pos] eq ' ' ||
       
   531 		   $line_char[$char_pos] eq '%' ||
       
   532 		   $line_char[$char_pos] eq ',' ||
       
   533 		   $line_char[$char_pos] eq '{') {
       
   534 	    next CHAR;
       
   535 	  }
       
   536 
       
   537 	  last;
       
   538 	} # if ($line_char[$char_pos] eq '%') {
       
   539 
       
   540       if ($line_char[$char_pos] eq ';') {
       
   541 	# comment line
       
   542 	# ignore it
       
   543 	last;
       
   544       }
       
   545 
       
   546       last;
       
   547     }
       
   548   }
       
   549     
       
   550   close(PKGFILE);
       
   551   return 0;
       
   552 }
       
   553 
       
   554 # Generate the distinguished-name-string for the self-signed public key certificate file.
       
   555 sub generateDN() {
       
   556   my @pkg_data;
       
   557   my $en_pos = 0;
       
   558   my $lang_pos = 0;
       
   559   
       
   560   # Find out the position of English in the list (if present)
       
   561   for(; $lang_pos <= $#languages; $lang_pos++) {
       
   562     
       
   563     if ($languages[$lang_pos] eq 'EN') {
       
   564       $en_pos = $lang_pos;
       
   565       
       
   566       last;
       
   567     }
       
   568   }
       
   569 
       
   570   $commonName = $package_components[$en_pos];
       
   571   $vendorName = $vendor[$en_pos];
       
   572   
       
   573   # Patch the $commonName upto 64 byte of random hex
       
   574   for (my $count = length ($commonName); $count<65; $count++) {
       
   575     $commonName .= sprintf "%.2x", int rand(255);
       
   576   }
       
   577   
       
   578   return 0;
       
   579 }
       
   580 
       
   581 
       
   582 # Print the Usage descriptions
       
   583 sub Usage () {
       
   584   print <<ENDUSAGESTRING;
       
   585 
       
   586 createsis, version 1.0
       
   587 Copyright (c) 2005 Symbian Software Ltd. All rights reserved.
       
   588 
       
   589 Mandatory SIS file signing for SYMBIAN OS v9.1 onwards. It supports
       
   590 creating new SIS files from package files, signs existing package files and
       
   591 generates new key/certificate pairs for purposes of signing. If neither
       
   592 certificate or key are specified as outlined in the usage scenarios below,
       
   593 a self-signed certificate will be generated and used to sign the resulting
       
   594 SIS file. In addition, createsis may be used to dump details of signatures
       
   595 and certificate chains in a pre-existing SIS file.
       
   596 
       
   597 Usage : createsis [-h | -?] <action>
       
   598 
       
   599  Options:
       
   600     -h Show this help page
       
   601     -? Show this help page
       
   602 
       
   603  action: 
       
   604     create
       
   605     Description : Create and sign the generated sisfile.
       
   606     Usage : createsis create [-key <key>] [-cert <cert>] [-pass <pass>] pkgfile
       
   607             -key        [optional]The certificate's private key file
       
   608             -cert       [optional]The certificate file used for signing
       
   609             -pass       [depend on how key/cert was generated OR 
       
   610                          can use this option to specify the passphase for the new key/cert]
       
   611                          The certificate's private key file's passphrase
       
   612             pkgfile     The input package file.
       
   613 
       
   614     sign
       
   615     Description : Sign the sisfile.
       
   616     Usage : createsis sign -key <key> -cert <cert> [-pass <pass>] sis_input sis_output
       
   617             -key        The certificate's private key file
       
   618             -cert       The certificate file used for signing
       
   619             -pass       [depend on how key/cert was generated]The certificate's private 
       
   620                          key file's passphrase
       
   621 	    -sis_input  The SIS file to be signed
       
   622 	    -sis_output The SIS file generated by signing
       
   623 
       
   624     dump
       
   625     Description : Display details of all valid signatures and the associated certificates
       
   626     in the sisfile.
       
   627     Usage : createsis dump sis_input
       
   628 	    -sis_input  The investigated SIS file
       
   629  
       
   630     strip
       
   631     Description : Remove most recent signature from SIS file
       
   632     Usage : createsis strip sis_input sis_output
       
   633 	    -sis_input  The SIS file whose recent signature will be removed
       
   634 	    -sis_output The SIS file after signature removed
       
   635 
       
   636 ENDUSAGESTRING
       
   637 
       
   638   exit 0;
       
   639 }