os/security/cryptoservices/certificateandkeymgmt/tx509/Data/extensions/certextbuilder.pl
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
#
sl@0
     2
# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     3
# All rights reserved.
sl@0
     4
# This component and the accompanying materials are made available
sl@0
     5
# under the terms of the License "Eclipse Public License v1.0"
sl@0
     6
# which accompanies this distribution, and is available
sl@0
     7
# at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     8
#
sl@0
     9
# Initial Contributors:
sl@0
    10
# Nokia Corporation - initial contribution.
sl@0
    11
#
sl@0
    12
# Contributors:
sl@0
    13
#
sl@0
    14
# Description: 
sl@0
    15
#
sl@0
    16
#!/bin/perl -w
sl@0
    17
sl@0
    18
use strict;
sl@0
    19
use Getopt::Long;
sl@0
    20
sl@0
    21
my $OID_DEVICE_ID_LIST="1.2.826.0.1.1796587.1.1.1.1";
sl@0
    22
my $OID_SID_LIST="1.2.826.0.1.1796587.1.1.1.4";
sl@0
    23
my $OID_VID_LIST="1.2.826.0.1.1796587.1.1.1.5";
sl@0
    24
my $OID_CAPABILITIES="1.2.826.0.1.1796587.1.1.1.6";
sl@0
    25
sl@0
    26
# Reserved for future use
sl@0
    27
#my $OID_SUBSCRIBER_ID_LIST="1.2.826.0.1.1796587.1.1.2.2"; 
sl@0
    28
#my $OID_ICC_ID_LIST="1.2.826.0.1.1796587.1.1.1.3";
sl@0
    29
sl@0
    30
my $DER_UTF8STRING_TAG="0C";
sl@0
    31
my $DER_PRINTABLESTRING_TAG="13";
sl@0
    32
my $DER_SEQUENCE_TAG="30";
sl@0
    33
my $DER_INTEGER_TAG="02";
sl@0
    34
my $DER_BITSTRING_TAG="03";
sl@0
    35
my $DER_OCTET_TAG="04";
sl@0
    36
sl@0
    37
my %CAPABILITY_SET = (
sl@0
    38
	"TCB" => 0,
sl@0
    39
	"COMMDD" => 1,
sl@0
    40
	"POWERMGMT" => 2,
sl@0
    41
	"MULTIMEDIADD" => 3,
sl@0
    42
	"READDEVICEDATA" => 4,
sl@0
    43
	"WRITEDEVICEDATA" => 5,
sl@0
    44
	"DRM" => 6,
sl@0
    45
	"TRUSTEDUI" => 7,
sl@0
    46
	"PROTSERV" => 8,
sl@0
    47
	"DISKADMIN" => 9,
sl@0
    48
	"NETWORKCONTROL" => 10,
sl@0
    49
	"ALLFILES" => 11,
sl@0
    50
	"SWEVENT" => 12,
sl@0
    51
	"NETWORKSERVICES" => 13,
sl@0
    52
	"LOCALSERVICES" => 14,
sl@0
    53
	"READUSERDATA" => 15,
sl@0
    54
	"WRITEUSERDATA" => 16,
sl@0
    55
	"LOCATION" => 17,
sl@0
    56
	"SURROUNDINGSDD" => 18,
sl@0
    57
	"USERENVIRONMENT" => 19	
sl@0
    58
	);
sl@0
    59
sl@0
    60
# Sections encountered
sl@0
    61
my %sections;
sl@0
    62
sl@0
    63
# Fields within sectins
sl@0
    64
my @device_id_list = ();
sl@0
    65
my @sid_list = ();
sl@0
    66
my @vid_list = ();
sl@0
    67
my $capabilities = '';
sl@0
    68
sl@0
    69
main();
sl@0
    70
exit(0);
sl@0
    71
sl@0
    72
# Main function.
sl@0
    73
# Loops through the input file and creates lists of items for each section.
sl@0
    74
sub main {
sl@0
    75
	my $section = "";
sl@0
    76
	my $output_binary = 0;
sl@0
    77
sl@0
    78
	GetOptions('binary' => \$output_binary);			   
sl@0
    79
	my ($infile, $outfile) = @ARGV;
sl@0
    80
	
sl@0
    81
	if (defined $infile) {
sl@0
    82
		open IN, "$infile" || die "Cannot open input file $infile";
sl@0
    83
	}
sl@0
    84
	else {
sl@0
    85
		*IN = *STDIN;
sl@0
    86
	}
sl@0
    87
sl@0
    88
	if (defined $outfile) {
sl@0
    89
		open OUT,  ">$outfile" || die "Cannot open input file $outfile";
sl@0
    90
	}
sl@0
    91
	else {
sl@0
    92
		*OUT = *STDOUT;
sl@0
    93
	}
sl@0
    94
	
sl@0
    95
	while (<IN>) {
sl@0
    96
		chomp;
sl@0
    97
		if (/^\s*\[\w*\]/) {
sl@0
    98
			# Process the new section name
sl@0
    99
			
sl@0
   100
			s/.*\[\s*(.*)\s*].*/$1/g;
sl@0
   101
			$section = lc($_);
sl@0
   102
    		$sections{$section} = 1;
sl@0
   103
	    }
sl@0
   104
	    elsif (/^\s*\#/) {
sl@0
   105
			# Comment - ignore
sl@0
   106
		}
sl@0
   107
	    elsif (/.*=.*/ ) {
sl@0
   108
			# Process element within section
sl@0
   109
			s/.*=//g;
sl@0
   110
			if ($section eq "device_id_list") {
sl@0
   111
				push @device_id_list, $_;
sl@0
   112
			}
sl@0
   113
            elsif ($section eq "sid_list") {
sl@0
   114
                push @sid_list, $_;
sl@0
   115
			}
sl@0
   116
			elsif ($section eq "vid_list") {
sl@0
   117
				push @vid_list, $_;
sl@0
   118
			}
sl@0
   119
			elsif ($section eq "cert_capabilities") {
sl@0
   120
sl@0
   121
				if (! $capabilities eq "") {
sl@0
   122
					die "Error: Multiple capability constraints defined.";
sl@0
   123
				}
sl@0
   124
sl@0
   125
				$capabilities = $_;
sl@0
   126
				if ($capabilities eq "" || $capabilities =~ /^\s*[01]+\s*$/)  {
sl@0
   127
					# Handle explicit bit strings
sl@0
   128
					$capabilities =~ s/\s//g;
sl@0
   129
				}
sl@0
   130
				else {
sl@0
   131
					# Convert MMP syntax into an explicit bit string
sl@0
   132
					$capabilities = &encode_capabilities($capabilities);					
sl@0
   133
				}
sl@0
   134
			}
sl@0
   135
			else {
sl@0
   136
				# Not in a section so ignore text
sl@0
   137
			}
sl@0
   138
		}   
sl@0
   139
   }   
sl@0
   140
 
sl@0
   141
   if ($output_binary) {
sl@0
   142
	   print_to_der();  
sl@0
   143
   }
sl@0
   144
   else {
sl@0
   145
       print_to_cnf();
sl@0
   146
   }
sl@0
   147
   close IN;
sl@0
   148
   close OUT;
sl@0
   149
}
sl@0
   150
sl@0
   151
# Test function which outputs the binary DER encoding. This can be vieweed using an
sl@0
   152
# ASN.1 viewer.
sl@0
   153
# This is really a debug function.
sl@0
   154
sub print_to_der {
sl@0
   155
	my $seq_octets = 0; 
sl@0
   156
	my $seq_content = "";
sl@0
   157
sl@0
   158
	if (defined $sections{"device_id_list"}) { 
sl@0
   159
		$seq_content .= ":" . &encode_string_list(\@device_id_list, \$seq_octets);
sl@0
   160
	}
sl@0
   161
	
sl@0
   162
	if (defined $sections{"sid_list"}) {
sl@0
   163
		$seq_content .= ":" . &encode_integer_list(\@sid_list, \$seq_octets);
sl@0
   164
	}
sl@0
   165
sl@0
   166
	if (defined $sections{"vid_list"}) {
sl@0
   167
		$seq_content .= ":" . &encode_integer_list(\@vid_list, \$seq_octets);
sl@0
   168
	}
sl@0
   169
sl@0
   170
	if (defined $sections{"cert_capabilities"}) {
sl@0
   171
		$seq_content .= ":" . &encode_bit_string($capabilities, \$seq_octets);
sl@0
   172
	}
sl@0
   173
	# Tidy up repreated colons
sl@0
   174
	$seq_content =~ s/::/:/;
sl@0
   175
	$seq_content =~ s/^://g;
sl@0
   176
	
sl@0
   177
	my $seq_length_octets;
sl@0
   178
	my $seq_length = &encode_length($seq_octets, \$seq_length_octets);
sl@0
   179
	my $seq ="$DER_SEQUENCE_TAG:$seq_length:$seq_content";
sl@0
   180
	
sl@0
   181
	$seq =~ s/::/:/g;
sl@0
   182
	$seq = uc($seq);
sl@0
   183
	
sl@0
   184
	binmode(OUT);
sl@0
   185
	foreach (split(/:/, $seq)){
sl@0
   186
		print OUT pack('C', hex);
sl@0
   187
	}
sl@0
   188
}
sl@0
   189
sl@0
   190
# Output to a format that can be read by Open SSL using the -extfile parameter
sl@0
   191
sub print_to_cnf {
sl@0
   192
   print OUT "extensions = extend\n";
sl@0
   193
   print OUT "[extend]\n";
sl@0
   194
   
sl@0
   195
   my $octets = 0; 
sl@0
   196
   my $output = "";
sl@0
   197
sl@0
   198
   if (defined $sections{"device_id_list"}) {
sl@0
   199
	   $output .= "# Device ID List\n" .
sl@0
   200
		   $OID_DEVICE_ID_LIST . "= critical, " . "DER:" . 
sl@0
   201
		   uc(&encode_string_list(\@device_id_list, \$octets)) . "\n";
sl@0
   202
   }      
sl@0
   203
   
sl@0
   204
   if (defined $sections{"sid_list"}) {
sl@0
   205
	   $output .= "# SID List\n" .
sl@0
   206
		   $OID_SID_LIST . "= critical, " . "DER:" . 
sl@0
   207
		   uc(&encode_integer_list(\@sid_list, \$octets)) . "\n";
sl@0
   208
   }   
sl@0
   209
sl@0
   210
   if (defined $sections{"vid_list"}) {
sl@0
   211
	   $output .= "# VID List\n" .
sl@0
   212
	   $OID_VID_LIST . "= critical, " . "DER:" . uc(&encode_integer_list(\@vid_list, \$octets)) . "\n";
sl@0
   213
   }   
sl@0
   214
sl@0
   215
   if (defined $sections{"cert_capabilities"}) {
sl@0
   216
	   $output .= "# Capabilities\n" .
sl@0
   217
		   $OID_CAPABILITIES . "= critical, " . "DER:" . uc(&encode_bit_string($capabilities, \$octets)) . "\n";
sl@0
   218
   }   
sl@0
   219
   
sl@0
   220
   # Remove trailing colons
sl@0
   221
   $output=~ s/\:*$//mg;
sl@0
   222
   print OUT $output;
sl@0
   223
}
sl@0
   224
sl@0
   225
# Creates a hex representation of the DER encoding of a sequence of strings.
sl@0
   226
sub encode_string_list($$) {
sl@0
   227
	my ($list, $octets) = @_;
sl@0
   228
	
sl@0
   229
	my $sequence_body = "";
sl@0
   230
	
sl@0
   231
	my $sequence_octets = 0;
sl@0
   232
	foreach (@$list) {
sl@0
   233
		my $hex_string = &encode_utf8_string($_, \$sequence_octets);
sl@0
   234
sl@0
   235
		# Add to string sequence body
sl@0
   236
		if ($sequence_body ne "") {
sl@0
   237
			$sequence_body .= ":";
sl@0
   238
		}
sl@0
   239
		$sequence_body .= $hex_string;
sl@0
   240
	}
sl@0
   241
	my $seq_length_octets = 0;
sl@0
   242
	my $seq_length = &encode_length($sequence_octets, \$seq_length_octets);
sl@0
   243
sl@0
   244
	$$octets += 1 + $seq_length_octets + $sequence_octets;
sl@0
   245
sl@0
   246
	return "$DER_SEQUENCE_TAG:$seq_length:$sequence_body";
sl@0
   247
}
sl@0
   248
sl@0
   249
# Creates a hex represenation of the DER encoding of a sequence of integers.
sl@0
   250
sub encode_integer_list($$) {
sl@0
   251
	my ($list, $octets) = @_;	
sl@0
   252
sl@0
   253
	my $sequence_body = "";
sl@0
   254
	my $sequence_octets = 0;
sl@0
   255
	foreach (@$list) {
sl@0
   256
		# Increment for integer tag value
sl@0
   257
		# Increment for integer length < 127 octets assumed !
sl@0
   258
		$sequence_octets+=2;
sl@0
   259
sl@0
   260
		if (s/^0x//) {
sl@0
   261
			$_ = hex;
sl@0
   262
		}
sl@0
   263
		
sl@0
   264
		# Convert the integer to base 256 hex and find out how
sl@0
   265
		# many octets were required
sl@0
   266
		my $hex_octets;
sl@0
   267
		my $hex_integer;
sl@0
   268
		if (//) {
sl@0
   269
			$hex_octets = 0;
sl@0
   270
			$hex_integer = "";
sl@0
   271
		}
sl@0
   272
		else {
sl@0
   273
			$hex_integer = &to_hex_base256($_, \$hex_octets);
sl@0
   274
			$sequence_octets += $hex_octets;
sl@0
   275
		}
sl@0
   276
		
sl@0
   277
		# Add to integer  sequence body
sl@0
   278
		if ($sequence_body ne "") {
sl@0
   279
			$sequence_body .= ":";
sl@0
   280
		}
sl@0
   281
		
sl@0
   282
		# No need to store length in long form because in base256
sl@0
   283
		# we never need more than 7 octets to store the largest number
sl@0
   284
		# that we need.
sl@0
   285
		my $int_header = sprintf("%2.2x", $hex_octets);
sl@0
   286
		$sequence_body .= "$DER_INTEGER_TAG:$int_header:$hex_integer";		
sl@0
   287
	}
sl@0
   288
sl@0
   289
	# Get the number of octets of the entire sequence. This could require
sl@0
   290
	# encoding in long form.
sl@0
   291
	my $seq_length_octets = 0;
sl@0
   292
	my $seq_length = &encode_length($sequence_octets, \$seq_length_octets);
sl@0
   293
sl@0
   294
	$$octets += 1 + $seq_length_octets + $sequence_octets;
sl@0
   295
sl@0
   296
	return "$DER_SEQUENCE_TAG:$seq_length:$sequence_body";
sl@0
   297
}
sl@0
   298
sl@0
   299
# Creates a hex represenation of the DER encoding of a UTF-8 string.
sl@0
   300
sub encode_utf8_string($$) {
sl@0
   301
	my ($input, $octets) = @_;
sl@0
   302
sl@0
   303
	# Hex encoded string
sl@0
   304
	my $output = "";
sl@0
   305
	my $input_len = length($input);	
sl@0
   306
	my $i = 0;
sl@0
   307
	while ($i < $input_len) {
sl@0
   308
		my $hex_val = ord(substr($input, $i, 1));
sl@0
   309
		if ($output ne "") {
sl@0
   310
			$output .= ":";
sl@0
   311
		}
sl@0
   312
		$output .= sprintf("%2.2x", $hex_val);
sl@0
   313
		$i++;
sl@0
   314
	}
sl@0
   315
	
sl@0
   316
	# Build string header
sl@0
   317
	my $output_length_octets = 0;		
sl@0
   318
	my $output_length = &encode_length($input_len, \$output_length_octets);
sl@0
   319
	
sl@0
   320
	# Track number of octets added for string header
sl@0
   321
	$$octets += 1 + $output_length_octets + $input_len;
sl@0
   322
	return "$DER_UTF8STRING_TAG:$output_length:$output";
sl@0
   323
}
sl@0
   324
sl@0
   325
# Converts the text description of capabilities into an ASCII string of 0s and 1s;
sl@0
   326
sub encode_capabilities($) {
sl@0
   327
	my ($value) = @_;
sl@0
   328
	my $output = "";
sl@0
   329
	my @caps = (0);
sl@0
   330
	
sl@0
   331
	$value = uc($value);
sl@0
   332
	foreach (split(/[\s,]/, $value)) {
sl@0
   333
		my $set_val = 1;
sl@0
   334
sl@0
   335
		if (s/^-//g) {
sl@0
   336
			$set_val = 0;
sl@0
   337
		}
sl@0
   338
		
sl@0
   339
		if (/^ALL$/) {
sl@0
   340
			foreach (keys %CAPABILITY_SET) {
sl@0
   341
				@caps[$CAPABILITY_SET{$_}] = 1;
sl@0
   342
			}
sl@0
   343
		}
sl@0
   344
	    elsif (/^NONE$/) {
sl@0
   345
			@caps = ();
sl@0
   346
		}
sl@0
   347
		if (defined $CAPABILITY_SET{$_}) {
sl@0
   348
			$caps[$CAPABILITY_SET{$_}] = $set_val;
sl@0
   349
		}
sl@0
   350
	}
sl@0
   351
sl@0
   352
	# Build the ascii bit string. Bit 0 is the left most bit
sl@0
   353
	for (my $i = 0; $i <= $#caps; $i++) {
sl@0
   354
		$output .= (defined $caps[$i] && $caps[$i] ? "1" : "0");
sl@0
   355
	}
sl@0
   356
sl@0
   357
	return $output;
sl@0
   358
}
sl@0
   359
sl@0
   360
# Creates a hex representation of the DER encoding of an arbitrary length bit string
sl@0
   361
sub encode_bit_string($$) {
sl@0
   362
	my ($text, $octets) = @_;
sl@0
   363
sl@0
   364
	# Bit string in hex including padding length octet
sl@0
   365
	my $bit_str = "";
sl@0
   366
	my $bit_str_octets = 1; # one octet for padding
sl@0
   367
sl@0
   368
	# Current byte
sl@0
   369
	my $byte = 0;	
sl@0
   370
	my $len = length($text);
sl@0
   371
sl@0
   372
	if ($len == 0) {
sl@0
   373
		$$octets+=2;
sl@0
   374
		return "03:00";
sl@0
   375
	}
sl@0
   376
sl@0
   377
	my $i = 0;
sl@0
   378
	while ($i < $len) {		
sl@0
   379
sl@0
   380
		# Read the ith character and insert it in the correct place in the byte
sl@0
   381
		# (fill from the left)
sl@0
   382
		my $c = substr($text, $i, 1);		
sl@0
   383
		if ($c eq "1") {
sl@0
   384
			$byte |= (1 << (7 - ($i % 8)));
sl@0
   385
		}
sl@0
   386
		elsif ($c ne "0") {
sl@0
   387
			die "Invalid character $c in bit string $text";
sl@0
   388
		}
sl@0
   389
sl@0
   390
		if (++$i % 8 == 0) {
sl@0
   391
			# Received 8 bits so output byte in hex
sl@0
   392
			if ($bit_str ne "") {
sl@0
   393
				$bit_str .= ":";
sl@0
   394
			}
sl@0
   395
			$bit_str .= sprintf("%2.2x", $byte);
sl@0
   396
			$bit_str_octets++;
sl@0
   397
			$byte = 0;
sl@0
   398
		}
sl@0
   399
	}
sl@0
   400
	# Pad any remaining bits / make sure 0 is output for empty string
sl@0
   401
	if ($byte != 0 || $bit_str_octets == 1) {
sl@0
   402
		if ($bit_str ne "") {
sl@0
   403
			$bit_str .= ":";
sl@0
   404
		}
sl@0
   405
		$bit_str .= sprintf("%2.2x", $byte);
sl@0
   406
		$bit_str_octets++;
sl@0
   407
	}
sl@0
   408
sl@0
   409
	my $pad_length = "00";
sl@0
   410
	if ($len % 8 > 0) {
sl@0
   411
		# If this isn't a multiple of 8 bits then calculated
sl@0
   412
		# the number of padding bits added.
sl@0
   413
		$pad_length = sprintf("%2.2x", 8 - ($len % 8));
sl@0
   414
	}
sl@0
   415
	
sl@0
   416
	# Octets used to store the length
sl@0
   417
	my $bit_str_length_octets = 0;
sl@0
   418
	my $bit_str_length = &encode_length($bit_str_octets, \$bit_str_length_octets);
sl@0
   419
	$$octets += 1 + $bit_str_length_octets + $bit_str_octets;
sl@0
   420
sl@0
   421
	return "$DER_BITSTRING_TAG:$bit_str_length:$pad_length:$bit_str";
sl@0
   422
}
sl@0
   423
sl@0
   424
# Return a hex represenation of the length using DER primitive (definate length encoding)
sl@0
   425
sub encode_length($$) {
sl@0
   426
	my ($num, $octets) = @_;
sl@0
   427
sl@0
   428
	if ($num < 128) {
sl@0
   429
		# Number is < 128 so encode in short form
sl@0
   430
		$$octets++;
sl@0
   431
		return sprintf("%2.2x", $num);
sl@0
   432
	}
sl@0
   433
	else {
sl@0
   434
		# Number >= 128 so encode in long form
sl@0
   435
		my $length_octets = 0;
sl@0
   436
		my $base256 = &to_hex_base256($num, \$length_octets);
sl@0
   437
		if ($length_octets > 127) {die "Encoding overflow.";}
sl@0
   438
		
sl@0
   439
		$$octets += 1 + $length_octets;
sl@0
   440
		
sl@0
   441
		# Set the top bit of the length octet to indicate long form		
sl@0
   442
		return "" . sprintf("%2.2x", ($length_octets | 0x80)) . ":$base256";
sl@0
   443
	}
sl@0
   444
}
sl@0
   445
sl@0
   446
# Convert an integer into an ascii hex representation in base 256
sl@0
   447
# $num    - the number to encode
sl@0
   448
# $octets - refernce to the octet count to increment
sl@0
   449
sub to_hex_base256($$) {
sl@0
   450
	my ($num, $octets) = @_;
sl@0
   451
sl@0
   452
	my $base256 = "";
sl@0
   453
	$num = int($num);
sl@0
   454
	while ($num > 0) {
sl@0
   455
		my $hexoctet = sprintf("%2.2x", $num & 0xFF);
sl@0
   456
		if ($base256 ne "") {
sl@0
   457
			$base256 = "$hexoctet:$base256";
sl@0
   458
		}
sl@0
   459
		else {
sl@0
   460
			$base256 = $hexoctet;
sl@0
   461
		}		
sl@0
   462
		$num >>= 8;
sl@0
   463
		$$octets++;
sl@0
   464
	}
sl@0
   465
	if ($base256 eq "") {
sl@0
   466
		$base256 = "0";
sl@0
   467
		$$octets++;
sl@0
   468
	}
sl@0
   469
	return $base256;
sl@0
   470
}