os/security/cryptoservices/certificateandkeymgmt/tx509/Data/extensions/certextbuilder.pl
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/security/cryptoservices/certificateandkeymgmt/tx509/Data/extensions/certextbuilder.pl	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,470 @@
     1.4 +#
     1.5 +# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
     1.6 +# All rights reserved.
     1.7 +# This component and the accompanying materials are made available
     1.8 +# under the terms of the License "Eclipse Public License v1.0"
     1.9 +# which accompanies this distribution, and is available
    1.10 +# at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.11 +#
    1.12 +# Initial Contributors:
    1.13 +# Nokia Corporation - initial contribution.
    1.14 +#
    1.15 +# Contributors:
    1.16 +#
    1.17 +# Description: 
    1.18 +#
    1.19 +#!/bin/perl -w
    1.20 +
    1.21 +use strict;
    1.22 +use Getopt::Long;
    1.23 +
    1.24 +my $OID_DEVICE_ID_LIST="1.2.826.0.1.1796587.1.1.1.1";
    1.25 +my $OID_SID_LIST="1.2.826.0.1.1796587.1.1.1.4";
    1.26 +my $OID_VID_LIST="1.2.826.0.1.1796587.1.1.1.5";
    1.27 +my $OID_CAPABILITIES="1.2.826.0.1.1796587.1.1.1.6";
    1.28 +
    1.29 +# Reserved for future use
    1.30 +#my $OID_SUBSCRIBER_ID_LIST="1.2.826.0.1.1796587.1.1.2.2"; 
    1.31 +#my $OID_ICC_ID_LIST="1.2.826.0.1.1796587.1.1.1.3";
    1.32 +
    1.33 +my $DER_UTF8STRING_TAG="0C";
    1.34 +my $DER_PRINTABLESTRING_TAG="13";
    1.35 +my $DER_SEQUENCE_TAG="30";
    1.36 +my $DER_INTEGER_TAG="02";
    1.37 +my $DER_BITSTRING_TAG="03";
    1.38 +my $DER_OCTET_TAG="04";
    1.39 +
    1.40 +my %CAPABILITY_SET = (
    1.41 +	"TCB" => 0,
    1.42 +	"COMMDD" => 1,
    1.43 +	"POWERMGMT" => 2,
    1.44 +	"MULTIMEDIADD" => 3,
    1.45 +	"READDEVICEDATA" => 4,
    1.46 +	"WRITEDEVICEDATA" => 5,
    1.47 +	"DRM" => 6,
    1.48 +	"TRUSTEDUI" => 7,
    1.49 +	"PROTSERV" => 8,
    1.50 +	"DISKADMIN" => 9,
    1.51 +	"NETWORKCONTROL" => 10,
    1.52 +	"ALLFILES" => 11,
    1.53 +	"SWEVENT" => 12,
    1.54 +	"NETWORKSERVICES" => 13,
    1.55 +	"LOCALSERVICES" => 14,
    1.56 +	"READUSERDATA" => 15,
    1.57 +	"WRITEUSERDATA" => 16,
    1.58 +	"LOCATION" => 17,
    1.59 +	"SURROUNDINGSDD" => 18,
    1.60 +	"USERENVIRONMENT" => 19	
    1.61 +	);
    1.62 +
    1.63 +# Sections encountered
    1.64 +my %sections;
    1.65 +
    1.66 +# Fields within sectins
    1.67 +my @device_id_list = ();
    1.68 +my @sid_list = ();
    1.69 +my @vid_list = ();
    1.70 +my $capabilities = '';
    1.71 +
    1.72 +main();
    1.73 +exit(0);
    1.74 +
    1.75 +# Main function.
    1.76 +# Loops through the input file and creates lists of items for each section.
    1.77 +sub main {
    1.78 +	my $section = "";
    1.79 +	my $output_binary = 0;
    1.80 +
    1.81 +	GetOptions('binary' => \$output_binary);			   
    1.82 +	my ($infile, $outfile) = @ARGV;
    1.83 +	
    1.84 +	if (defined $infile) {
    1.85 +		open IN, "$infile" || die "Cannot open input file $infile";
    1.86 +	}
    1.87 +	else {
    1.88 +		*IN = *STDIN;
    1.89 +	}
    1.90 +
    1.91 +	if (defined $outfile) {
    1.92 +		open OUT,  ">$outfile" || die "Cannot open input file $outfile";
    1.93 +	}
    1.94 +	else {
    1.95 +		*OUT = *STDOUT;
    1.96 +	}
    1.97 +	
    1.98 +	while (<IN>) {
    1.99 +		chomp;
   1.100 +		if (/^\s*\[\w*\]/) {
   1.101 +			# Process the new section name
   1.102 +			
   1.103 +			s/.*\[\s*(.*)\s*].*/$1/g;
   1.104 +			$section = lc($_);
   1.105 +    		$sections{$section} = 1;
   1.106 +	    }
   1.107 +	    elsif (/^\s*\#/) {
   1.108 +			# Comment - ignore
   1.109 +		}
   1.110 +	    elsif (/.*=.*/ ) {
   1.111 +			# Process element within section
   1.112 +			s/.*=//g;
   1.113 +			if ($section eq "device_id_list") {
   1.114 +				push @device_id_list, $_;
   1.115 +			}
   1.116 +            elsif ($section eq "sid_list") {
   1.117 +                push @sid_list, $_;
   1.118 +			}
   1.119 +			elsif ($section eq "vid_list") {
   1.120 +				push @vid_list, $_;
   1.121 +			}
   1.122 +			elsif ($section eq "cert_capabilities") {
   1.123 +
   1.124 +				if (! $capabilities eq "") {
   1.125 +					die "Error: Multiple capability constraints defined.";
   1.126 +				}
   1.127 +
   1.128 +				$capabilities = $_;
   1.129 +				if ($capabilities eq "" || $capabilities =~ /^\s*[01]+\s*$/)  {
   1.130 +					# Handle explicit bit strings
   1.131 +					$capabilities =~ s/\s//g;
   1.132 +				}
   1.133 +				else {
   1.134 +					# Convert MMP syntax into an explicit bit string
   1.135 +					$capabilities = &encode_capabilities($capabilities);					
   1.136 +				}
   1.137 +			}
   1.138 +			else {
   1.139 +				# Not in a section so ignore text
   1.140 +			}
   1.141 +		}   
   1.142 +   }   
   1.143 + 
   1.144 +   if ($output_binary) {
   1.145 +	   print_to_der();  
   1.146 +   }
   1.147 +   else {
   1.148 +       print_to_cnf();
   1.149 +   }
   1.150 +   close IN;
   1.151 +   close OUT;
   1.152 +}
   1.153 +
   1.154 +# Test function which outputs the binary DER encoding. This can be vieweed using an
   1.155 +# ASN.1 viewer.
   1.156 +# This is really a debug function.
   1.157 +sub print_to_der {
   1.158 +	my $seq_octets = 0; 
   1.159 +	my $seq_content = "";
   1.160 +
   1.161 +	if (defined $sections{"device_id_list"}) { 
   1.162 +		$seq_content .= ":" . &encode_string_list(\@device_id_list, \$seq_octets);
   1.163 +	}
   1.164 +	
   1.165 +	if (defined $sections{"sid_list"}) {
   1.166 +		$seq_content .= ":" . &encode_integer_list(\@sid_list, \$seq_octets);
   1.167 +	}
   1.168 +
   1.169 +	if (defined $sections{"vid_list"}) {
   1.170 +		$seq_content .= ":" . &encode_integer_list(\@vid_list, \$seq_octets);
   1.171 +	}
   1.172 +
   1.173 +	if (defined $sections{"cert_capabilities"}) {
   1.174 +		$seq_content .= ":" . &encode_bit_string($capabilities, \$seq_octets);
   1.175 +	}
   1.176 +	# Tidy up repreated colons
   1.177 +	$seq_content =~ s/::/:/;
   1.178 +	$seq_content =~ s/^://g;
   1.179 +	
   1.180 +	my $seq_length_octets;
   1.181 +	my $seq_length = &encode_length($seq_octets, \$seq_length_octets);
   1.182 +	my $seq ="$DER_SEQUENCE_TAG:$seq_length:$seq_content";
   1.183 +	
   1.184 +	$seq =~ s/::/:/g;
   1.185 +	$seq = uc($seq);
   1.186 +	
   1.187 +	binmode(OUT);
   1.188 +	foreach (split(/:/, $seq)){
   1.189 +		print OUT pack('C', hex);
   1.190 +	}
   1.191 +}
   1.192 +
   1.193 +# Output to a format that can be read by Open SSL using the -extfile parameter
   1.194 +sub print_to_cnf {
   1.195 +   print OUT "extensions = extend\n";
   1.196 +   print OUT "[extend]\n";
   1.197 +   
   1.198 +   my $octets = 0; 
   1.199 +   my $output = "";
   1.200 +
   1.201 +   if (defined $sections{"device_id_list"}) {
   1.202 +	   $output .= "# Device ID List\n" .
   1.203 +		   $OID_DEVICE_ID_LIST . "= critical, " . "DER:" . 
   1.204 +		   uc(&encode_string_list(\@device_id_list, \$octets)) . "\n";
   1.205 +   }      
   1.206 +   
   1.207 +   if (defined $sections{"sid_list"}) {
   1.208 +	   $output .= "# SID List\n" .
   1.209 +		   $OID_SID_LIST . "= critical, " . "DER:" . 
   1.210 +		   uc(&encode_integer_list(\@sid_list, \$octets)) . "\n";
   1.211 +   }   
   1.212 +
   1.213 +   if (defined $sections{"vid_list"}) {
   1.214 +	   $output .= "# VID List\n" .
   1.215 +	   $OID_VID_LIST . "= critical, " . "DER:" . uc(&encode_integer_list(\@vid_list, \$octets)) . "\n";
   1.216 +   }   
   1.217 +
   1.218 +   if (defined $sections{"cert_capabilities"}) {
   1.219 +	   $output .= "# Capabilities\n" .
   1.220 +		   $OID_CAPABILITIES . "= critical, " . "DER:" . uc(&encode_bit_string($capabilities, \$octets)) . "\n";
   1.221 +   }   
   1.222 +   
   1.223 +   # Remove trailing colons
   1.224 +   $output=~ s/\:*$//mg;
   1.225 +   print OUT $output;
   1.226 +}
   1.227 +
   1.228 +# Creates a hex representation of the DER encoding of a sequence of strings.
   1.229 +sub encode_string_list($$) {
   1.230 +	my ($list, $octets) = @_;
   1.231 +	
   1.232 +	my $sequence_body = "";
   1.233 +	
   1.234 +	my $sequence_octets = 0;
   1.235 +	foreach (@$list) {
   1.236 +		my $hex_string = &encode_utf8_string($_, \$sequence_octets);
   1.237 +
   1.238 +		# Add to string sequence body
   1.239 +		if ($sequence_body ne "") {
   1.240 +			$sequence_body .= ":";
   1.241 +		}
   1.242 +		$sequence_body .= $hex_string;
   1.243 +	}
   1.244 +	my $seq_length_octets = 0;
   1.245 +	my $seq_length = &encode_length($sequence_octets, \$seq_length_octets);
   1.246 +
   1.247 +	$$octets += 1 + $seq_length_octets + $sequence_octets;
   1.248 +
   1.249 +	return "$DER_SEQUENCE_TAG:$seq_length:$sequence_body";
   1.250 +}
   1.251 +
   1.252 +# Creates a hex represenation of the DER encoding of a sequence of integers.
   1.253 +sub encode_integer_list($$) {
   1.254 +	my ($list, $octets) = @_;	
   1.255 +
   1.256 +	my $sequence_body = "";
   1.257 +	my $sequence_octets = 0;
   1.258 +	foreach (@$list) {
   1.259 +		# Increment for integer tag value
   1.260 +		# Increment for integer length < 127 octets assumed !
   1.261 +		$sequence_octets+=2;
   1.262 +
   1.263 +		if (s/^0x//) {
   1.264 +			$_ = hex;
   1.265 +		}
   1.266 +		
   1.267 +		# Convert the integer to base 256 hex and find out how
   1.268 +		# many octets were required
   1.269 +		my $hex_octets;
   1.270 +		my $hex_integer;
   1.271 +		if (//) {
   1.272 +			$hex_octets = 0;
   1.273 +			$hex_integer = "";
   1.274 +		}
   1.275 +		else {
   1.276 +			$hex_integer = &to_hex_base256($_, \$hex_octets);
   1.277 +			$sequence_octets += $hex_octets;
   1.278 +		}
   1.279 +		
   1.280 +		# Add to integer  sequence body
   1.281 +		if ($sequence_body ne "") {
   1.282 +			$sequence_body .= ":";
   1.283 +		}
   1.284 +		
   1.285 +		# No need to store length in long form because in base256
   1.286 +		# we never need more than 7 octets to store the largest number
   1.287 +		# that we need.
   1.288 +		my $int_header = sprintf("%2.2x", $hex_octets);
   1.289 +		$sequence_body .= "$DER_INTEGER_TAG:$int_header:$hex_integer";		
   1.290 +	}
   1.291 +
   1.292 +	# Get the number of octets of the entire sequence. This could require
   1.293 +	# encoding in long form.
   1.294 +	my $seq_length_octets = 0;
   1.295 +	my $seq_length = &encode_length($sequence_octets, \$seq_length_octets);
   1.296 +
   1.297 +	$$octets += 1 + $seq_length_octets + $sequence_octets;
   1.298 +
   1.299 +	return "$DER_SEQUENCE_TAG:$seq_length:$sequence_body";
   1.300 +}
   1.301 +
   1.302 +# Creates a hex represenation of the DER encoding of a UTF-8 string.
   1.303 +sub encode_utf8_string($$) {
   1.304 +	my ($input, $octets) = @_;
   1.305 +
   1.306 +	# Hex encoded string
   1.307 +	my $output = "";
   1.308 +	my $input_len = length($input);	
   1.309 +	my $i = 0;
   1.310 +	while ($i < $input_len) {
   1.311 +		my $hex_val = ord(substr($input, $i, 1));
   1.312 +		if ($output ne "") {
   1.313 +			$output .= ":";
   1.314 +		}
   1.315 +		$output .= sprintf("%2.2x", $hex_val);
   1.316 +		$i++;
   1.317 +	}
   1.318 +	
   1.319 +	# Build string header
   1.320 +	my $output_length_octets = 0;		
   1.321 +	my $output_length = &encode_length($input_len, \$output_length_octets);
   1.322 +	
   1.323 +	# Track number of octets added for string header
   1.324 +	$$octets += 1 + $output_length_octets + $input_len;
   1.325 +	return "$DER_UTF8STRING_TAG:$output_length:$output";
   1.326 +}
   1.327 +
   1.328 +# Converts the text description of capabilities into an ASCII string of 0s and 1s;
   1.329 +sub encode_capabilities($) {
   1.330 +	my ($value) = @_;
   1.331 +	my $output = "";
   1.332 +	my @caps = (0);
   1.333 +	
   1.334 +	$value = uc($value);
   1.335 +	foreach (split(/[\s,]/, $value)) {
   1.336 +		my $set_val = 1;
   1.337 +
   1.338 +		if (s/^-//g) {
   1.339 +			$set_val = 0;
   1.340 +		}
   1.341 +		
   1.342 +		if (/^ALL$/) {
   1.343 +			foreach (keys %CAPABILITY_SET) {
   1.344 +				@caps[$CAPABILITY_SET{$_}] = 1;
   1.345 +			}
   1.346 +		}
   1.347 +	    elsif (/^NONE$/) {
   1.348 +			@caps = ();
   1.349 +		}
   1.350 +		if (defined $CAPABILITY_SET{$_}) {
   1.351 +			$caps[$CAPABILITY_SET{$_}] = $set_val;
   1.352 +		}
   1.353 +	}
   1.354 +
   1.355 +	# Build the ascii bit string. Bit 0 is the left most bit
   1.356 +	for (my $i = 0; $i <= $#caps; $i++) {
   1.357 +		$output .= (defined $caps[$i] && $caps[$i] ? "1" : "0");
   1.358 +	}
   1.359 +
   1.360 +	return $output;
   1.361 +}
   1.362 +
   1.363 +# Creates a hex representation of the DER encoding of an arbitrary length bit string
   1.364 +sub encode_bit_string($$) {
   1.365 +	my ($text, $octets) = @_;
   1.366 +
   1.367 +	# Bit string in hex including padding length octet
   1.368 +	my $bit_str = "";
   1.369 +	my $bit_str_octets = 1; # one octet for padding
   1.370 +
   1.371 +	# Current byte
   1.372 +	my $byte = 0;	
   1.373 +	my $len = length($text);
   1.374 +
   1.375 +	if ($len == 0) {
   1.376 +		$$octets+=2;
   1.377 +		return "03:00";
   1.378 +	}
   1.379 +
   1.380 +	my $i = 0;
   1.381 +	while ($i < $len) {		
   1.382 +
   1.383 +		# Read the ith character and insert it in the correct place in the byte
   1.384 +		# (fill from the left)
   1.385 +		my $c = substr($text, $i, 1);		
   1.386 +		if ($c eq "1") {
   1.387 +			$byte |= (1 << (7 - ($i % 8)));
   1.388 +		}
   1.389 +		elsif ($c ne "0") {
   1.390 +			die "Invalid character $c in bit string $text";
   1.391 +		}
   1.392 +
   1.393 +		if (++$i % 8 == 0) {
   1.394 +			# Received 8 bits so output byte in hex
   1.395 +			if ($bit_str ne "") {
   1.396 +				$bit_str .= ":";
   1.397 +			}
   1.398 +			$bit_str .= sprintf("%2.2x", $byte);
   1.399 +			$bit_str_octets++;
   1.400 +			$byte = 0;
   1.401 +		}
   1.402 +	}
   1.403 +	# Pad any remaining bits / make sure 0 is output for empty string
   1.404 +	if ($byte != 0 || $bit_str_octets == 1) {
   1.405 +		if ($bit_str ne "") {
   1.406 +			$bit_str .= ":";
   1.407 +		}
   1.408 +		$bit_str .= sprintf("%2.2x", $byte);
   1.409 +		$bit_str_octets++;
   1.410 +	}
   1.411 +
   1.412 +	my $pad_length = "00";
   1.413 +	if ($len % 8 > 0) {
   1.414 +		# If this isn't a multiple of 8 bits then calculated
   1.415 +		# the number of padding bits added.
   1.416 +		$pad_length = sprintf("%2.2x", 8 - ($len % 8));
   1.417 +	}
   1.418 +	
   1.419 +	# Octets used to store the length
   1.420 +	my $bit_str_length_octets = 0;
   1.421 +	my $bit_str_length = &encode_length($bit_str_octets, \$bit_str_length_octets);
   1.422 +	$$octets += 1 + $bit_str_length_octets + $bit_str_octets;
   1.423 +
   1.424 +	return "$DER_BITSTRING_TAG:$bit_str_length:$pad_length:$bit_str";
   1.425 +}
   1.426 +
   1.427 +# Return a hex represenation of the length using DER primitive (definate length encoding)
   1.428 +sub encode_length($$) {
   1.429 +	my ($num, $octets) = @_;
   1.430 +
   1.431 +	if ($num < 128) {
   1.432 +		# Number is < 128 so encode in short form
   1.433 +		$$octets++;
   1.434 +		return sprintf("%2.2x", $num);
   1.435 +	}
   1.436 +	else {
   1.437 +		# Number >= 128 so encode in long form
   1.438 +		my $length_octets = 0;
   1.439 +		my $base256 = &to_hex_base256($num, \$length_octets);
   1.440 +		if ($length_octets > 127) {die "Encoding overflow.";}
   1.441 +		
   1.442 +		$$octets += 1 + $length_octets;
   1.443 +		
   1.444 +		# Set the top bit of the length octet to indicate long form		
   1.445 +		return "" . sprintf("%2.2x", ($length_octets | 0x80)) . ":$base256";
   1.446 +	}
   1.447 +}
   1.448 +
   1.449 +# Convert an integer into an ascii hex representation in base 256
   1.450 +# $num    - the number to encode
   1.451 +# $octets - refernce to the octet count to increment
   1.452 +sub to_hex_base256($$) {
   1.453 +	my ($num, $octets) = @_;
   1.454 +
   1.455 +	my $base256 = "";
   1.456 +	$num = int($num);
   1.457 +	while ($num > 0) {
   1.458 +		my $hexoctet = sprintf("%2.2x", $num & 0xFF);
   1.459 +		if ($base256 ne "") {
   1.460 +			$base256 = "$hexoctet:$base256";
   1.461 +		}
   1.462 +		else {
   1.463 +			$base256 = $hexoctet;
   1.464 +		}		
   1.465 +		$num >>= 8;
   1.466 +		$$octets++;
   1.467 +	}
   1.468 +	if ($base256 eq "") {
   1.469 +		$base256 = "0";
   1.470 +		$$octets++;
   1.471 +	}
   1.472 +	return $base256;
   1.473 +}