--- a/cryptoservices/certificateandkeymgmt/tx509/Data/extensions/certextbuilder.pl Tue Jul 21 01:04:32 2009 +0100
+++ b/cryptoservices/certificateandkeymgmt/tx509/Data/extensions/certextbuilder.pl Thu Sep 10 14:01:51 2009 +0300
@@ -1,493 +1,493 @@
-#
-# Copyright (c) 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:
-#
-#!/bin/perl -w
-
-# 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 "Symbian Foundation License v1.0"
-# which accompanies this distribution, and is available
-# at the URL "http://www.symbianfoundation.org/legal/sfl-v10.html".
-#
-# Initial Contributors:
-# Nokia Corporation - initial contribution.
-#
-# Contributors:
-#
-# Description:
-# This script converts certificate constraint extensions specified in an INI
-# format into a hex representation of the DER encoding that OpenSSL can
-# add to a certificate.
-# This script allows corrupt certificate extensions to be generated for unit
-# testing and therefore using this script to create production certificates is
-# NOT supported.
-# See SGL.GT0220.255_Developer_Certificates.doc for usage instructions.
-#
-#
-
-use strict;
-use Getopt::Long;
-
-my $OID_DEVICE_ID_LIST="1.2.826.0.1.1796587.1.1.1.1";
-my $OID_SID_LIST="1.2.826.0.1.1796587.1.1.1.4";
-my $OID_VID_LIST="1.2.826.0.1.1796587.1.1.1.5";
-my $OID_CAPABILITIES="1.2.826.0.1.1796587.1.1.1.6";
-
-# Reserved for future use
-#my $OID_SUBSCRIBER_ID_LIST="1.2.826.0.1.1796587.1.1.2.2";
-#my $OID_ICC_ID_LIST="1.2.826.0.1.1796587.1.1.1.3";
-
-my $DER_UTF8STRING_TAG="0C";
-my $DER_PRINTABLESTRING_TAG="13";
-my $DER_SEQUENCE_TAG="30";
-my $DER_INTEGER_TAG="02";
-my $DER_BITSTRING_TAG="03";
-my $DER_OCTET_TAG="04";
-
-my %CAPABILITY_SET = (
- "TCB" => 0,
- "COMMDD" => 1,
- "POWERMGMT" => 2,
- "MULTIMEDIADD" => 3,
- "READDEVICEDATA" => 4,
- "WRITEDEVICEDATA" => 5,
- "DRM" => 6,
- "TRUSTEDUI" => 7,
- "PROTSERV" => 8,
- "DISKADMIN" => 9,
- "NETWORKCONTROL" => 10,
- "ALLFILES" => 11,
- "SWEVENT" => 12,
- "NETWORKSERVICES" => 13,
- "LOCALSERVICES" => 14,
- "READUSERDATA" => 15,
- "WRITEUSERDATA" => 16,
- "LOCATION" => 17,
- "SURROUNDINGSDD" => 18,
- "USERENVIRONMENT" => 19
- );
-
-# Sections encountered
-my %sections;
-
-# Fields within sectins
-my @device_id_list = ();
-my @sid_list = ();
-my @vid_list = ();
-my $capabilities = '';
-
-main();
-exit(0);
-
-# Main function.
-# Loops through the input file and creates lists of items for each section.
-sub main {
- my $section = "";
- my $output_binary = 0;
-
- GetOptions('binary' => \$output_binary);
- my ($infile, $outfile) = @ARGV;
-
- if (defined $infile) {
- open IN, "$infile" || die "Cannot open input file $infile";
- }
- else {
- *IN = *STDIN;
- }
-
- if (defined $outfile) {
- open OUT, ">$outfile" || die "Cannot open input file $outfile";
- }
- else {
- *OUT = *STDOUT;
- }
-
- while (<IN>) {
- chomp;
- if (/^\s*\[\w*\]/) {
- # Process the new section name
-
- s/.*\[\s*(.*)\s*].*/$1/g;
- $section = lc($_);
- $sections{$section} = 1;
- }
- elsif (/^\s*\#/) {
- # Comment - ignore
- }
- elsif (/.*=.*/ ) {
- # Process element within section
- s/.*=//g;
- if ($section eq "device_id_list") {
- push @device_id_list, $_;
- }
- elsif ($section eq "sid_list") {
- push @sid_list, $_;
- }
- elsif ($section eq "vid_list") {
- push @vid_list, $_;
- }
- elsif ($section eq "cert_capabilities") {
-
- if (! $capabilities eq "") {
- die "Error: Multiple capability constraints defined.";
- }
-
- $capabilities = $_;
- if ($capabilities eq "" || $capabilities =~ /^\s*[01]+\s*$/) {
- # Handle explicit bit strings
- $capabilities =~ s/\s//g;
- }
- else {
- # Convert MMP syntax into an explicit bit string
- $capabilities = &encode_capabilities($capabilities);
- }
- }
- else {
- # Not in a section so ignore text
- }
- }
- }
-
- if ($output_binary) {
- print_to_der();
- }
- else {
- print_to_cnf();
- }
- close IN;
- close OUT;
-}
-
-# Test function which outputs the binary DER encoding. This can be vieweed using an
-# ASN.1 viewer.
-# This is really a debug function.
-sub print_to_der {
- my $seq_octets = 0;
- my $seq_content = "";
-
- if (defined $sections{"device_id_list"}) {
- $seq_content .= ":" . &encode_string_list(\@device_id_list, \$seq_octets);
- }
-
- if (defined $sections{"sid_list"}) {
- $seq_content .= ":" . &encode_integer_list(\@sid_list, \$seq_octets);
- }
-
- if (defined $sections{"vid_list"}) {
- $seq_content .= ":" . &encode_integer_list(\@vid_list, \$seq_octets);
- }
-
- if (defined $sections{"cert_capabilities"}) {
- $seq_content .= ":" . &encode_bit_string($capabilities, \$seq_octets);
- }
- # Tidy up repreated colons
- $seq_content =~ s/::/:/;
- $seq_content =~ s/^://g;
-
- my $seq_length_octets;
- my $seq_length = &encode_length($seq_octets, \$seq_length_octets);
- my $seq ="$DER_SEQUENCE_TAG:$seq_length:$seq_content";
-
- $seq =~ s/::/:/g;
- $seq = uc($seq);
-
- binmode(OUT);
- foreach (split(/:/, $seq)){
- print OUT pack('C', hex);
- }
-}
-
-# Output to a format that can be read by Open SSL using the -extfile parameter
-sub print_to_cnf {
- print OUT "extensions = extend\n";
- print OUT "[extend]\n";
-
- my $octets = 0;
- my $output = "";
-
- if (defined $sections{"device_id_list"}) {
- $output .= "# Device ID List\n" .
- $OID_DEVICE_ID_LIST . "= critical, " . "DER:" .
- uc(&encode_string_list(\@device_id_list, \$octets)) . "\n";
- }
-
- if (defined $sections{"sid_list"}) {
- $output .= "# SID List\n" .
- $OID_SID_LIST . "= critical, " . "DER:" .
- uc(&encode_integer_list(\@sid_list, \$octets)) . "\n";
- }
-
- if (defined $sections{"vid_list"}) {
- $output .= "# VID List\n" .
- $OID_VID_LIST . "= critical, " . "DER:" . uc(&encode_integer_list(\@vid_list, \$octets)) . "\n";
- }
-
- if (defined $sections{"cert_capabilities"}) {
- $output .= "# Capabilities\n" .
- $OID_CAPABILITIES . "= critical, " . "DER:" . uc(&encode_bit_string($capabilities, \$octets)) . "\n";
- }
-
- # Remove trailing colons
- $output=~ s/\:*$//mg;
- print OUT $output;
-}
-
-# Creates a hex representation of the DER encoding of a sequence of strings.
-sub encode_string_list($$) {
- my ($list, $octets) = @_;
-
- my $sequence_body = "";
-
- my $sequence_octets = 0;
- foreach (@$list) {
- my $hex_string = &encode_utf8_string($_, \$sequence_octets);
-
- # Add to string sequence body
- if ($sequence_body ne "") {
- $sequence_body .= ":";
- }
- $sequence_body .= $hex_string;
- }
- my $seq_length_octets = 0;
- my $seq_length = &encode_length($sequence_octets, \$seq_length_octets);
-
- $$octets += 1 + $seq_length_octets + $sequence_octets;
-
- return "$DER_SEQUENCE_TAG:$seq_length:$sequence_body";
-}
-
-# Creates a hex represenation of the DER encoding of a sequence of integers.
-sub encode_integer_list($$) {
- my ($list, $octets) = @_;
-
- my $sequence_body = "";
- my $sequence_octets = 0;
- foreach (@$list) {
- # Increment for integer tag value
- # Increment for integer length < 127 octets assumed !
- $sequence_octets+=2;
-
- if (s/^0x//) {
- $_ = hex;
- }
-
- # Convert the integer to base 256 hex and find out how
- # many octets were required
- my $hex_octets;
- my $hex_integer;
- if (//) {
- $hex_octets = 0;
- $hex_integer = "";
- }
- else {
- $hex_integer = &to_hex_base256($_, \$hex_octets);
- $sequence_octets += $hex_octets;
- }
-
- # Add to integer sequence body
- if ($sequence_body ne "") {
- $sequence_body .= ":";
- }
-
- # No need to store length in long form because in base256
- # we never need more than 7 octets to store the largest number
- # that we need.
- my $int_header = sprintf("%2.2x", $hex_octets);
- $sequence_body .= "$DER_INTEGER_TAG:$int_header:$hex_integer";
- }
-
- # Get the number of octets of the entire sequence. This could require
- # encoding in long form.
- my $seq_length_octets = 0;
- my $seq_length = &encode_length($sequence_octets, \$seq_length_octets);
-
- $$octets += 1 + $seq_length_octets + $sequence_octets;
-
- return "$DER_SEQUENCE_TAG:$seq_length:$sequence_body";
-}
-
-# Creates a hex represenation of the DER encoding of a UTF-8 string.
-sub encode_utf8_string($$) {
- my ($input, $octets) = @_;
-
- # Hex encoded string
- my $output = "";
- my $input_len = length($input);
- my $i = 0;
- while ($i < $input_len) {
- my $hex_val = ord(substr($input, $i, 1));
- if ($output ne "") {
- $output .= ":";
- }
- $output .= sprintf("%2.2x", $hex_val);
- $i++;
- }
-
- # Build string header
- my $output_length_octets = 0;
- my $output_length = &encode_length($input_len, \$output_length_octets);
-
- # Track number of octets added for string header
- $$octets += 1 + $output_length_octets + $input_len;
- return "$DER_UTF8STRING_TAG:$output_length:$output";
-}
-
-# Converts the text description of capabilities into an ASCII string of 0s and 1s;
-sub encode_capabilities($) {
- my ($value) = @_;
- my $output = "";
- my @caps = (0);
-
- $value = uc($value);
- foreach (split(/[\s,]/, $value)) {
- my $set_val = 1;
-
- if (s/^-//g) {
- $set_val = 0;
- }
-
- if (/^ALL$/) {
- foreach (keys %CAPABILITY_SET) {
- @caps[$CAPABILITY_SET{$_}] = 1;
- }
- }
- elsif (/^NONE$/) {
- @caps = ();
- }
- if (defined $CAPABILITY_SET{$_}) {
- $caps[$CAPABILITY_SET{$_}] = $set_val;
- }
- }
-
- # Build the ascii bit string. Bit 0 is the left most bit
- for (my $i = 0; $i <= $#caps; $i++) {
- $output .= (defined $caps[$i] && $caps[$i] ? "1" : "0");
- }
-
- return $output;
-}
-
-# Creates a hex representation of the DER encoding of an arbitrary length bit string
-sub encode_bit_string($$) {
- my ($text, $octets) = @_;
-
- # Bit string in hex including padding length octet
- my $bit_str = "";
- my $bit_str_octets = 1; # one octet for padding
-
- # Current byte
- my $byte = 0;
- my $len = length($text);
-
- if ($len == 0) {
- $$octets+=2;
- return "03:00";
- }
-
- my $i = 0;
- while ($i < $len) {
-
- # Read the ith character and insert it in the correct place in the byte
- # (fill from the left)
- my $c = substr($text, $i, 1);
- if ($c eq "1") {
- $byte |= (1 << (7 - ($i % 8)));
- }
- elsif ($c ne "0") {
- die "Invalid character $c in bit string $text";
- }
-
- if (++$i % 8 == 0) {
- # Received 8 bits so output byte in hex
- if ($bit_str ne "") {
- $bit_str .= ":";
- }
- $bit_str .= sprintf("%2.2x", $byte);
- $bit_str_octets++;
- $byte = 0;
- }
- }
- # Pad any remaining bits / make sure 0 is output for empty string
- if ($byte != 0 || $bit_str_octets == 1) {
- if ($bit_str ne "") {
- $bit_str .= ":";
- }
- $bit_str .= sprintf("%2.2x", $byte);
- $bit_str_octets++;
- }
-
- my $pad_length = "00";
- if ($len % 8 > 0) {
- # If this isn't a multiple of 8 bits then calculated
- # the number of padding bits added.
- $pad_length = sprintf("%2.2x", 8 - ($len % 8));
- }
-
- # Octets used to store the length
- my $bit_str_length_octets = 0;
- my $bit_str_length = &encode_length($bit_str_octets, \$bit_str_length_octets);
- $$octets += 1 + $bit_str_length_octets + $bit_str_octets;
-
- return "$DER_BITSTRING_TAG:$bit_str_length:$pad_length:$bit_str";
-}
-
-# Return a hex represenation of the length using DER primitive (definate length encoding)
-sub encode_length($$) {
- my ($num, $octets) = @_;
-
- if ($num < 128) {
- # Number is < 128 so encode in short form
- $$octets++;
- return sprintf("%2.2x", $num);
- }
- else {
- # Number >= 128 so encode in long form
- my $length_octets = 0;
- my $base256 = &to_hex_base256($num, \$length_octets);
- if ($length_octets > 127) {die "Encoding overflow.";}
-
- $$octets += 1 + $length_octets;
-
- # Set the top bit of the length octet to indicate long form
- return "" . sprintf("%2.2x", ($length_octets | 0x80)) . ":$base256";
- }
-}
-
-# Convert an integer into an ascii hex representation in base 256
-# $num - the number to encode
-# $octets - refernce to the octet count to increment
-sub to_hex_base256($$) {
- my ($num, $octets) = @_;
-
- my $base256 = "";
- $num = int($num);
- while ($num > 0) {
- my $hexoctet = sprintf("%2.2x", $num & 0xFF);
- if ($base256 ne "") {
- $base256 = "$hexoctet:$base256";
- }
- else {
- $base256 = $hexoctet;
- }
- $num >>= 8;
- $$octets++;
- }
- if ($base256 eq "") {
- $base256 = "0";
- $$octets++;
- }
- return $base256;
-}
+#
+# Copyright (c) 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:
+#
+#!/bin/perl -w
+
+# 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 "Symbian Foundation License v1.0"
+# which accompanies this distribution, and is available
+# at the URL "http://www.symbianfoundation.org/legal/sfl-v10.html".
+#
+# Initial Contributors:
+# Nokia Corporation - initial contribution.
+#
+# Contributors:
+#
+# Description:
+# This script converts certificate constraint extensions specified in an INI
+# format into a hex representation of the DER encoding that OpenSSL can
+# add to a certificate.
+# This script allows corrupt certificate extensions to be generated for unit
+# testing and therefore using this script to create production certificates is
+# NOT supported.
+# See SGL.GT0220.255_Developer_Certificates.doc for usage instructions.
+#
+#
+
+use strict;
+use Getopt::Long;
+
+my $OID_DEVICE_ID_LIST="1.2.826.0.1.1796587.1.1.1.1";
+my $OID_SID_LIST="1.2.826.0.1.1796587.1.1.1.4";
+my $OID_VID_LIST="1.2.826.0.1.1796587.1.1.1.5";
+my $OID_CAPABILITIES="1.2.826.0.1.1796587.1.1.1.6";
+
+# Reserved for future use
+#my $OID_SUBSCRIBER_ID_LIST="1.2.826.0.1.1796587.1.1.2.2";
+#my $OID_ICC_ID_LIST="1.2.826.0.1.1796587.1.1.1.3";
+
+my $DER_UTF8STRING_TAG="0C";
+my $DER_PRINTABLESTRING_TAG="13";
+my $DER_SEQUENCE_TAG="30";
+my $DER_INTEGER_TAG="02";
+my $DER_BITSTRING_TAG="03";
+my $DER_OCTET_TAG="04";
+
+my %CAPABILITY_SET = (
+ "TCB" => 0,
+ "COMMDD" => 1,
+ "POWERMGMT" => 2,
+ "MULTIMEDIADD" => 3,
+ "READDEVICEDATA" => 4,
+ "WRITEDEVICEDATA" => 5,
+ "DRM" => 6,
+ "TRUSTEDUI" => 7,
+ "PROTSERV" => 8,
+ "DISKADMIN" => 9,
+ "NETWORKCONTROL" => 10,
+ "ALLFILES" => 11,
+ "SWEVENT" => 12,
+ "NETWORKSERVICES" => 13,
+ "LOCALSERVICES" => 14,
+ "READUSERDATA" => 15,
+ "WRITEUSERDATA" => 16,
+ "LOCATION" => 17,
+ "SURROUNDINGSDD" => 18,
+ "USERENVIRONMENT" => 19
+ );
+
+# Sections encountered
+my %sections;
+
+# Fields within sectins
+my @device_id_list = ();
+my @sid_list = ();
+my @vid_list = ();
+my $capabilities = '';
+
+main();
+exit(0);
+
+# Main function.
+# Loops through the input file and creates lists of items for each section.
+sub main {
+ my $section = "";
+ my $output_binary = 0;
+
+ GetOptions('binary' => \$output_binary);
+ my ($infile, $outfile) = @ARGV;
+
+ if (defined $infile) {
+ open IN, "$infile" || die "Cannot open input file $infile";
+ }
+ else {
+ *IN = *STDIN;
+ }
+
+ if (defined $outfile) {
+ open OUT, ">$outfile" || die "Cannot open input file $outfile";
+ }
+ else {
+ *OUT = *STDOUT;
+ }
+
+ while (<IN>) {
+ chomp;
+ if (/^\s*\[\w*\]/) {
+ # Process the new section name
+
+ s/.*\[\s*(.*)\s*].*/$1/g;
+ $section = lc($_);
+ $sections{$section} = 1;
+ }
+ elsif (/^\s*\#/) {
+ # Comment - ignore
+ }
+ elsif (/.*=.*/ ) {
+ # Process element within section
+ s/.*=//g;
+ if ($section eq "device_id_list") {
+ push @device_id_list, $_;
+ }
+ elsif ($section eq "sid_list") {
+ push @sid_list, $_;
+ }
+ elsif ($section eq "vid_list") {
+ push @vid_list, $_;
+ }
+ elsif ($section eq "cert_capabilities") {
+
+ if (! $capabilities eq "") {
+ die "Error: Multiple capability constraints defined.";
+ }
+
+ $capabilities = $_;
+ if ($capabilities eq "" || $capabilities =~ /^\s*[01]+\s*$/) {
+ # Handle explicit bit strings
+ $capabilities =~ s/\s//g;
+ }
+ else {
+ # Convert MMP syntax into an explicit bit string
+ $capabilities = &encode_capabilities($capabilities);
+ }
+ }
+ else {
+ # Not in a section so ignore text
+ }
+ }
+ }
+
+ if ($output_binary) {
+ print_to_der();
+ }
+ else {
+ print_to_cnf();
+ }
+ close IN;
+ close OUT;
+}
+
+# Test function which outputs the binary DER encoding. This can be vieweed using an
+# ASN.1 viewer.
+# This is really a debug function.
+sub print_to_der {
+ my $seq_octets = 0;
+ my $seq_content = "";
+
+ if (defined $sections{"device_id_list"}) {
+ $seq_content .= ":" . &encode_string_list(\@device_id_list, \$seq_octets);
+ }
+
+ if (defined $sections{"sid_list"}) {
+ $seq_content .= ":" . &encode_integer_list(\@sid_list, \$seq_octets);
+ }
+
+ if (defined $sections{"vid_list"}) {
+ $seq_content .= ":" . &encode_integer_list(\@vid_list, \$seq_octets);
+ }
+
+ if (defined $sections{"cert_capabilities"}) {
+ $seq_content .= ":" . &encode_bit_string($capabilities, \$seq_octets);
+ }
+ # Tidy up repreated colons
+ $seq_content =~ s/::/:/;
+ $seq_content =~ s/^://g;
+
+ my $seq_length_octets;
+ my $seq_length = &encode_length($seq_octets, \$seq_length_octets);
+ my $seq ="$DER_SEQUENCE_TAG:$seq_length:$seq_content";
+
+ $seq =~ s/::/:/g;
+ $seq = uc($seq);
+
+ binmode(OUT);
+ foreach (split(/:/, $seq)){
+ print OUT pack('C', hex);
+ }
+}
+
+# Output to a format that can be read by Open SSL using the -extfile parameter
+sub print_to_cnf {
+ print OUT "extensions = extend\n";
+ print OUT "[extend]\n";
+
+ my $octets = 0;
+ my $output = "";
+
+ if (defined $sections{"device_id_list"}) {
+ $output .= "# Device ID List\n" .
+ $OID_DEVICE_ID_LIST . "= critical, " . "DER:" .
+ uc(&encode_string_list(\@device_id_list, \$octets)) . "\n";
+ }
+
+ if (defined $sections{"sid_list"}) {
+ $output .= "# SID List\n" .
+ $OID_SID_LIST . "= critical, " . "DER:" .
+ uc(&encode_integer_list(\@sid_list, \$octets)) . "\n";
+ }
+
+ if (defined $sections{"vid_list"}) {
+ $output .= "# VID List\n" .
+ $OID_VID_LIST . "= critical, " . "DER:" . uc(&encode_integer_list(\@vid_list, \$octets)) . "\n";
+ }
+
+ if (defined $sections{"cert_capabilities"}) {
+ $output .= "# Capabilities\n" .
+ $OID_CAPABILITIES . "= critical, " . "DER:" . uc(&encode_bit_string($capabilities, \$octets)) . "\n";
+ }
+
+ # Remove trailing colons
+ $output=~ s/\:*$//mg;
+ print OUT $output;
+}
+
+# Creates a hex representation of the DER encoding of a sequence of strings.
+sub encode_string_list($$) {
+ my ($list, $octets) = @_;
+
+ my $sequence_body = "";
+
+ my $sequence_octets = 0;
+ foreach (@$list) {
+ my $hex_string = &encode_utf8_string($_, \$sequence_octets);
+
+ # Add to string sequence body
+ if ($sequence_body ne "") {
+ $sequence_body .= ":";
+ }
+ $sequence_body .= $hex_string;
+ }
+ my $seq_length_octets = 0;
+ my $seq_length = &encode_length($sequence_octets, \$seq_length_octets);
+
+ $$octets += 1 + $seq_length_octets + $sequence_octets;
+
+ return "$DER_SEQUENCE_TAG:$seq_length:$sequence_body";
+}
+
+# Creates a hex represenation of the DER encoding of a sequence of integers.
+sub encode_integer_list($$) {
+ my ($list, $octets) = @_;
+
+ my $sequence_body = "";
+ my $sequence_octets = 0;
+ foreach (@$list) {
+ # Increment for integer tag value
+ # Increment for integer length < 127 octets assumed !
+ $sequence_octets+=2;
+
+ if (s/^0x//) {
+ $_ = hex;
+ }
+
+ # Convert the integer to base 256 hex and find out how
+ # many octets were required
+ my $hex_octets;
+ my $hex_integer;
+ if (//) {
+ $hex_octets = 0;
+ $hex_integer = "";
+ }
+ else {
+ $hex_integer = &to_hex_base256($_, \$hex_octets);
+ $sequence_octets += $hex_octets;
+ }
+
+ # Add to integer sequence body
+ if ($sequence_body ne "") {
+ $sequence_body .= ":";
+ }
+
+ # No need to store length in long form because in base256
+ # we never need more than 7 octets to store the largest number
+ # that we need.
+ my $int_header = sprintf("%2.2x", $hex_octets);
+ $sequence_body .= "$DER_INTEGER_TAG:$int_header:$hex_integer";
+ }
+
+ # Get the number of octets of the entire sequence. This could require
+ # encoding in long form.
+ my $seq_length_octets = 0;
+ my $seq_length = &encode_length($sequence_octets, \$seq_length_octets);
+
+ $$octets += 1 + $seq_length_octets + $sequence_octets;
+
+ return "$DER_SEQUENCE_TAG:$seq_length:$sequence_body";
+}
+
+# Creates a hex represenation of the DER encoding of a UTF-8 string.
+sub encode_utf8_string($$) {
+ my ($input, $octets) = @_;
+
+ # Hex encoded string
+ my $output = "";
+ my $input_len = length($input);
+ my $i = 0;
+ while ($i < $input_len) {
+ my $hex_val = ord(substr($input, $i, 1));
+ if ($output ne "") {
+ $output .= ":";
+ }
+ $output .= sprintf("%2.2x", $hex_val);
+ $i++;
+ }
+
+ # Build string header
+ my $output_length_octets = 0;
+ my $output_length = &encode_length($input_len, \$output_length_octets);
+
+ # Track number of octets added for string header
+ $$octets += 1 + $output_length_octets + $input_len;
+ return "$DER_UTF8STRING_TAG:$output_length:$output";
+}
+
+# Converts the text description of capabilities into an ASCII string of 0s and 1s;
+sub encode_capabilities($) {
+ my ($value) = @_;
+ my $output = "";
+ my @caps = (0);
+
+ $value = uc($value);
+ foreach (split(/[\s,]/, $value)) {
+ my $set_val = 1;
+
+ if (s/^-//g) {
+ $set_val = 0;
+ }
+
+ if (/^ALL$/) {
+ foreach (keys %CAPABILITY_SET) {
+ @caps[$CAPABILITY_SET{$_}] = 1;
+ }
+ }
+ elsif (/^NONE$/) {
+ @caps = ();
+ }
+ if (defined $CAPABILITY_SET{$_}) {
+ $caps[$CAPABILITY_SET{$_}] = $set_val;
+ }
+ }
+
+ # Build the ascii bit string. Bit 0 is the left most bit
+ for (my $i = 0; $i <= $#caps; $i++) {
+ $output .= (defined $caps[$i] && $caps[$i] ? "1" : "0");
+ }
+
+ return $output;
+}
+
+# Creates a hex representation of the DER encoding of an arbitrary length bit string
+sub encode_bit_string($$) {
+ my ($text, $octets) = @_;
+
+ # Bit string in hex including padding length octet
+ my $bit_str = "";
+ my $bit_str_octets = 1; # one octet for padding
+
+ # Current byte
+ my $byte = 0;
+ my $len = length($text);
+
+ if ($len == 0) {
+ $$octets+=2;
+ return "03:00";
+ }
+
+ my $i = 0;
+ while ($i < $len) {
+
+ # Read the ith character and insert it in the correct place in the byte
+ # (fill from the left)
+ my $c = substr($text, $i, 1);
+ if ($c eq "1") {
+ $byte |= (1 << (7 - ($i % 8)));
+ }
+ elsif ($c ne "0") {
+ die "Invalid character $c in bit string $text";
+ }
+
+ if (++$i % 8 == 0) {
+ # Received 8 bits so output byte in hex
+ if ($bit_str ne "") {
+ $bit_str .= ":";
+ }
+ $bit_str .= sprintf("%2.2x", $byte);
+ $bit_str_octets++;
+ $byte = 0;
+ }
+ }
+ # Pad any remaining bits / make sure 0 is output for empty string
+ if ($byte != 0 || $bit_str_octets == 1) {
+ if ($bit_str ne "") {
+ $bit_str .= ":";
+ }
+ $bit_str .= sprintf("%2.2x", $byte);
+ $bit_str_octets++;
+ }
+
+ my $pad_length = "00";
+ if ($len % 8 > 0) {
+ # If this isn't a multiple of 8 bits then calculated
+ # the number of padding bits added.
+ $pad_length = sprintf("%2.2x", 8 - ($len % 8));
+ }
+
+ # Octets used to store the length
+ my $bit_str_length_octets = 0;
+ my $bit_str_length = &encode_length($bit_str_octets, \$bit_str_length_octets);
+ $$octets += 1 + $bit_str_length_octets + $bit_str_octets;
+
+ return "$DER_BITSTRING_TAG:$bit_str_length:$pad_length:$bit_str";
+}
+
+# Return a hex represenation of the length using DER primitive (definate length encoding)
+sub encode_length($$) {
+ my ($num, $octets) = @_;
+
+ if ($num < 128) {
+ # Number is < 128 so encode in short form
+ $$octets++;
+ return sprintf("%2.2x", $num);
+ }
+ else {
+ # Number >= 128 so encode in long form
+ my $length_octets = 0;
+ my $base256 = &to_hex_base256($num, \$length_octets);
+ if ($length_octets > 127) {die "Encoding overflow.";}
+
+ $$octets += 1 + $length_octets;
+
+ # Set the top bit of the length octet to indicate long form
+ return "" . sprintf("%2.2x", ($length_octets | 0x80)) . ":$base256";
+ }
+}
+
+# Convert an integer into an ascii hex representation in base 256
+# $num - the number to encode
+# $octets - refernce to the octet count to increment
+sub to_hex_base256($$) {
+ my ($num, $octets) = @_;
+
+ my $base256 = "";
+ $num = int($num);
+ while ($num > 0) {
+ my $hexoctet = sprintf("%2.2x", $num & 0xFF);
+ if ($base256 ne "") {
+ $base256 = "$hexoctet:$base256";
+ }
+ else {
+ $base256 = $hexoctet;
+ }
+ $num >>= 8;
+ $$octets++;
+ }
+ if ($base256 eq "") {
+ $base256 = "0";
+ $$octets++;
+ }
+ return $base256;
+}