summaryrefslogtreecommitdiffstats
path: root/tcllib/modules/asn
diff options
context:
space:
mode:
Diffstat (limited to 'tcllib/modules/asn')
-rw-r--r--tcllib/modules/asn/ChangeLog272
-rw-r--r--tcllib/modules/asn/asn.bench116
-rw-r--r--tcllib/modules/asn/asn.man464
-rw-r--r--tcllib/modules/asn/asn.pcx271
-rw-r--r--tcllib/modules/asn/asn.tcl1580
-rw-r--r--tcllib/modules/asn/asn.test956
-rw-r--r--tcllib/modules/asn/laymans_guide.txt1855
-rw-r--r--tcllib/modules/asn/pkgIndex.tcl4
8 files changed, 5518 insertions, 0 deletions
diff --git a/tcllib/modules/asn/ChangeLog b/tcllib/modules/asn/ChangeLog
new file mode 100644
index 0000000..a38aad7
--- /dev/null
+++ b/tcllib/modules/asn/ChangeLog
@@ -0,0 +1,272 @@
+2013-02-01 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.15 ========================
+ *
+
+2011-12-13 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.14 ========================
+ *
+
+2011-01-24 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.13 ========================
+ *
+
+2011-01-05 Michael Schlenker <mic42@users.sourceforge.net>
+
+ * asn.tcl : Fixed wrong asnGetBigInteger code
+ asn.man : Tcllib SF [3039090], added tests.
+ asn.test : Patchlevel now 0.8.4.
+ asn.bench: Thank to Roy Keene for the patch.
+ asn.pcx :
+
+2009-12-07 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.12 ========================
+ *
+
+2008-12-12 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.11.1 ========================
+ *
+
+2008-11-22 Michael Schlenker <mic42@users.sourceforge.net>
+
+ * asn.bench: Added a new bench for OID decoding
+
+2008-10-16 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.11 ========================
+ *
+
+2008-06-12 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * asn.pcx: New file. Syntax definitions for the public commands of
+ the asn package.
+
+2008-03-27 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * asn.man: Added documentation for a number of public yet not
+ documented.
+
+2008-03-09 Michael Schlenker <mic42@users.sourceforge.net>
+
+ * asn.tcl : Added (optional ) support for Tcl 8.5 unsigned binary
+ asn.man : scan to speed up byte extraction.
+ pkgIndex.tcl:
+
+2007-09-18 Michael Schlenker <mic42@users.sourceforge.net>
+
+ * asn.tcl : Fixed missing padding in bitstring encoder
+ asn.man : Tcllib SF [1797428], added some tests for
+ asn.test : Bitstrings. Patchlevel now 0.8.2.
+
+2007-09-12 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.10 ========================
+ *
+
+2007-04-20 Michael Schlenker <mic42@users.sourceforge.net>
+
+ * asn.tcl : Fixed misspelt PRIVATE name in docs and code,
+ asn.man : Tcllib SF [1704626].
+ asn.test : Fixed various glitches in the new commands and
+ added more tests for asnPeekTag and asnTag.
+ Version raised to 0.8.1.
+
+2007-04-20 Michael Schlenker <mic42@users.sourceforge.net>
+
+ * asn.tcl : Fixed documentation bug Tcllib [1703408].
+ asn.man : Fixed parts of [1558351] by adding handling
+ asn.bench : for tag numbers > 31 and some new commands
+ asn.test : for changing tags.
+ Fixed Bug [1645333]. Some new benchmarks.
+ Raised Version to 0.8 because of new commands.
+
+2007-03-19 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * asn.man: Fixed all warnings due to use of now deprecated
+ commands. Added a section about how to give feedback.
+
+2006-10-03 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.9 ========================
+ *
+
+2006-09-01 Michael Schlenker <mic42@users.sourceforge.net>
+ * asn.tcl : Added asnRetag, asnPeekByte and asnGetLength
+ asn.man : to the public api, because those are needed by
+ pkgIndex.tcl: the ldap package.
+
+2006-08-16 Michael Schlenker <mic42@users.sourceforge.net>
+ * asn.tcl : Fixed stupid typos in asnGetApplication.
+ Fixes bug Tcllib [1541436].
+
+2006-08-15 Michael Schlenker <mic42@users.sourceforge.net>
+ * asn.tcl : added two convenience functions,
+ asn.man : asnSequenceFromList and asnSetFromList for
+ pkgIndex.tcl: use by the ldap module. Raised version
+ to 0.6
+
+2006-08-15 Michael Schlenker <mic42@users.sourceforge.net>
+ * asn.test: Added more tests. Fixed wrong version
+ asn.man : reference in man page.
+
+2006-08-13 Michael Schlenker <mic42@users.sourceforge.net>
+
+ * asn.tcl : Fixed Tcllib Bug [1539479]. Package version
+ asn.test: raised to 0.5.2. Added smoketest for the bug.
+ Thanks to Pierre David for finding this.
+
+2006-03-22 Michael Schlenker <mic42@users.sourceforge.net>
+
+ * asn.tcl: Removed dependency on the log package to fix
+ Tcllib Bug [1408807]. Package version raised to 0.5.1.
+
+2006-01-29 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * asn.test: Fixed use of duplicate test names.
+
+2006-01-22 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * asn.test: More boilerplate simplified via use of test support.
+
+2006-01-19 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * asn.test: Hooked into the new common test support code.
+
+2006-01-16 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * asn.man: Reworked the documentation of the new commands a bit,
+ and fixed some typos in words and use of the doctools commands.
+
+2006-01-16 Michael Schlenker <mic42@users.sourceforge.net>
+
+ * asn.tcl: Added new decoders for BMPString
+ asn.man: and UTF8String. New convenience
+ asn.test: function asnGetString. Added tests
+ pkgIndex.tcl: for OIDs and the new string functions.
+ Bugfix for wrong tag in asnNumericString.
+ Version increased to 0.5.
+ Big thanks to Victor Wagner <vitus@45.free.net)
+ for the patches.
+
+2006-01-05 Michael Schlenker <mic42@users.sourceforge.net>
+
+ * asn.tcl: Fixed Tcllib Bug #1393804. Stupid typo.
+ asn.test: Added some tests for asnPeekByte,
+ asnGetByte, asnGetBytes.
+ pkgIndex.tcl: Version increased to 0.4.2
+
+2005-12-30 Michael Schlenker <mic42@users.sourceforge.net>
+
+ * asn.tcl: Applied patch from Tcllib Bug #1391776 to
+ create better (shorter) encodings for OIDs.
+ pkgIndex.tcl: Version number increased to 0.4.1
+
+2005-10-21 Andreas Kupries <andreask@activestate.com>
+
+ * asn.test: Fixed typos, new and old.
+
+2005-10-18 Andreas Kupries <andreask@activestate.com>
+
+ * asn.test: Package requires 8.4, this was not caught
+ * pkgIndex.tcl: properly in index, nor in testsuite.
+
+ * asn.bench: New file, benchmarks, only basics for now.
+
+2005-10-06 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.8 ========================
+ *
+
+2005-04-04 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * asn.man: Synchronized indexed/provided versions.
+ * pkgIndex.tcl:
+
+2005-02-09 Michael Schlenker <mic42@users.sourceforge.net>
+
+ * asn.tcl:
+ * asn.man:
+ * asn.test: Fixed incorrect length encoding and decoding .
+ Added 64-bit support for length encoding/decoding,
+ Added 64-bit support for integers.
+ Added tests for length encoding/decoding (10.x-11.x).
+ Added tests for 64-bit integers.
+ Bumped version number to 0.4
+ The package now needs Tcl 8.4 for wide() support.
+
+2004-12-29 Michael Schlenker <mic42@users.sourceforge.net>
+
+ * asn.tcl:
+ * asn.man:
+ * asn.test: Added more encoder functions
+ to the module.
+ * Added math::bignum support for encoding
+ and decoding large integers. Interface not
+ final, so no docs yet.
+ * Fixed bug with negative 3-byte integers in
+ asn::asnInteger, those were padded with 0x00 instead
+ of 0xff and added test for this (2.25).
+ * Added tests for null, boolean encoding and decoding
+ and for bignum integer encoding (5.x-9.x).
+ * Removed second signed-unsigned conversion for the tags
+ in error messages, asnGetByte returns unsigned tags.
+ * bumped version number to 0.3
+
+2004-10-05 Michael Schlenker <mic42@users.sourceforge.net>
+
+ * asn.tcl: Added more decoder functions to the module.
+ * asn.man: New primitve Types supported:
+ OBJECT IDENTIFIER,BIT STRING,UTCTIME,BOOLEAN,
+ PRINTABLE STRING, IA5 STRING, NULL
+ New structure element: Context tagging
+
+2004-10-05 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ *
+ * Released and tagged Tcllib 1.7 ========================
+ *
+
+2004-08-15 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * asn.tcl: Typo police.
+ * asn.man:
+ * ChangeLog:
+
+2004-08-06 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * asn.test:
+ * asn.tcl: Enhanced encoder for enumerations: fixed buglet for
+ 2-byte integers (not minimal in border case 127), added the
+ handling of 3-byte integers. Extended testsuite to cover
+ enumerations as well.
+
+2004-08-05 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+ * asn.test: New file, first test cases for asn package.
+
+ * asn.tcl: Enhanced integer encoder: fixed buglet for 2-byte
+ integers (not minimal in bordercase 127), added the handling of
+ 3-byte integers.
+
+2004-05-27 Andreas Kupries <andreask@activestate.com>
+
+ * New module: ASN.1 de- and encoding. This was provided to us
+ indirectly by Jochen Loewer <loewerj@web.de>, through the LDAP
+ module. It contains the same functionality internally.
+
+ * Added doctools documentation. Referenced the "Layman's Guide to
+ a Subset of ASN.1, BER, and DER" and added text version to the
+ sources, to guide future work.
diff --git a/tcllib/modules/asn/asn.bench b/tcllib/modules/asn/asn.bench
new file mode 100644
index 0000000..cadac67
--- /dev/null
+++ b/tcllib/modules/asn/asn.bench
@@ -0,0 +1,116 @@
+# -*- tcl -*-
+# Tcl Benchmark File
+#
+# This file contains a number of benchmarks for the 'asn' module.
+# This allow developers to monitor/gauge/track package performance.
+#
+# (c) 2005 Andreas Kupries <andreas_kupries@users.sourceforge.net>
+
+# We need at least version 8.2 for the package and thus the
+# benchmarks.
+
+if {![package vsatisfies [package provide Tcl] 8.4]} {
+ return
+}
+
+# ### ### ### ######### ######### ######### ###########################
+## Setting up the environment ...
+
+package forget log
+catch {namespace delete ::log}
+source [file join [file dirname [file dirname [info script]]] log log.tcl]
+
+package forget asn
+catch {namespace delete ::asn}
+source [file join [file dirname [info script]] asn.tcl]
+
+# ### ### ### ######### ######### ######### ###########################
+## Benchmarks.
+
+foreach n {
+ -10 -100 -1000 -10000 -100000 -1000000
+ 0
+ 10 100 1000 10000 100000 1000000
+} {
+ bench -desc "ASN Integer $n" -body {
+ asn::asnInteger $n
+ }
+
+ bench -desc "ASN Enum $n" -body {
+ asn::asnEnumeration $n
+ }
+
+ bench -desc "ASN Boolean $n" -body {
+ asn::asnBoolean $n
+ }
+}
+
+foreach n {10 100 1000 10000} {
+ bench -desc "ASN OctetString ${n}" -pre {
+ set str [string repeat X $n]
+ } -body {
+ asn::asnOctetString $str
+ } -post {
+ unset str
+ }
+}
+
+for {set n 1; set i 0} {$i < 64} { set n [expr {wide($n)*2}] ; incr i} {
+ bench -desc "ASN asnLength 2^${i}" -body {
+ asn::asnLength $n
+ }
+}
+
+for {set n 0} {$n < 10} { incr n} {
+ bench -desc "ASN encode oid with ${n}+2 components" -pre {
+ set oid [list 1 10]
+ for {set i 0} {$i < $n} {incr i} {
+ lappend oid $i
+ }
+ } -body {
+ asn::asnObjectIdentifier $oid
+ } -post {
+ unset oid
+ }
+}
+
+for {set n 0} {$n < 10} { incr n} {
+ bench -desc "ASN decode oid with ${n}+2 components" -pre {
+ set oid [list 1 10]
+ for {set i 0} {$i < $n} {incr i} {
+ lappend oid $i
+ }
+ set oidval [asn::asnObjectIdentifier $oid]
+ } -body {
+ asn::asnGetObjectIdentifier $oidval
+ } -post {
+ unset oid
+ unset oidval
+ }
+}
+
+foreach n {10 100 1000 10000 100000} {
+ bench -desc "ASN asnGetByte ${n}" -pre {
+ set bytes [binary format a* [string repeat X $n]]
+ } -body {
+ ::asn::asnGetByte bytes dummy
+ } -post {
+ unset bytes
+ unset dummy
+ }
+}
+
+
+foreach n {10 100 1000 10000 100000} {
+ bench -desc "ASN asnGetBytes ${n} len 5" -pre {
+ set bytes [binary format a* [string repeat X $n]]
+ } -body {
+ ::asn::asnGetBytes bytes 5 dummy
+ } -post {
+ unset bytes
+ unset dummy
+ }
+}
+
+# ### ### ### ######### ######### ######### ###########################
+## Complete
diff --git a/tcllib/modules/asn/asn.man b/tcllib/modules/asn/asn.man
new file mode 100644
index 0000000..b5eb5c5
--- /dev/null
+++ b/tcllib/modules/asn/asn.man
@@ -0,0 +1,464 @@
+[comment {-*- tcl -*- doctools manpage}]
+[manpage_begin asn n 0.8]
+[keywords asn]
+[keywords ber]
+[keywords cer]
+[keywords der]
+[keywords internet]
+[keywords protocol]
+[keywords x.208]
+[keywords x.209]
+[copyright {2004 Andreas Kupries <andreas_kupries@users.sourceforge.net>}]
+[copyright {2004 Jochen Loewer <loewerj@web.de>}]
+[copyright {2004-2011 Michael Schlenker <mic42@users.sourceforge.net>}]
+[moddesc {ASN.1 processing}]
+[category Networking]
+[titledesc {ASN.1 BER encoder/decoder}]
+[require Tcl 8.4]
+[require asn [opt 0.8.4]]
+[description]
+[para]
+
+The [package asn] package provides [emph partial] de- and encoder
+commands for BER encoded ASN.1 data. It can also be used for
+decoding DER, which is a restricted subset of BER.
+
+[para]
+
+ASN.1 is a standard [term {Abstract Syntax Notation}], and BER are its
+[term {Basic Encoding Rules}].
+
+[para]
+
+See [uri http://asn1.elibel.tm.fr/en/standards/index.htm] for more
+information about the standard.
+
+[para]
+
+Also see [uri http://luca.ntop.org/Teaching/Appunti/asn1.html] for
+[emph {A Layman's Guide to a Subset of ASN.1, BER, and DER}], an RSA
+Laboratories Technical Note by Burton S. Kaliski Jr. (Revised November
+1, 1993). A text version of this note is part of the module sources
+and should be read by any implementor.
+
+[section {PUBLIC API}]
+[subsection ENCODER]
+
+[list_begin definitions]
+
+[call [cmd ::asn::asnSequence] [arg evalue]...]
+
+Takes zero or more encoded values, packs them into an ASN sequence and
+returns its encoded binary form.
+
+[call [cmd ::asn::asnSequenceFromList] [arg elist]]
+
+Takes a list of encoded values, packs them into an ASN sequence and
+returns its encoded binary form.
+
+[call [cmd ::asn::asnSet] [arg evalue]...]
+
+Takes zero or more encoded values, packs them into an ASN set and
+returns its encoded binary form.
+
+[call [cmd ::asn::asnSetFromList] [arg elist]]
+
+Takes a list of encoded values, packs them into an ASN set and
+returns its encoded binary form.
+
+[call [cmd ::asn::asnApplicationConstr] [arg appNumber] [arg evalue]...]
+
+Takes zero or more encoded values, packs them into an ASN application
+construct and returns its encoded binary form.
+
+[call [cmd ::asn::asnApplication] [arg appNumber] [arg data]]
+
+Takes a single encoded value [arg data], packs it into an ASN
+application construct and returns its encoded binary form.
+
+[call [cmd ::asn::asnChoice] [arg appNumber] [arg evalue]...]
+
+Takes zero or more encoded values, packs them into an ASN choice
+construct and returns its encoded binary form.
+
+[call [cmd ::asn::asnChoiceConstr] [arg appNumber] [arg evalue]...]
+
+Takes zero or more encoded values, packs them into an ASN choice
+construct and returns its encoded binary form.
+
+[call [cmd ::asn::asnInteger] [arg number]]
+
+Returns the encoded form of the specified integer
+[arg number].
+
+[call [cmd ::asn::asnEnumeration] [arg number]]
+
+Returns the encoded form of the specified enumeration id
+[arg number].
+
+[call [cmd ::asn::asnBoolean] [arg bool]]
+
+Returns the encoded form of the specified boolean value
+[arg bool].
+
+[call [cmd ::asn::asnContext] [arg context] [arg data]]
+
+Takes an encoded value and packs it into a constructed value with
+application tag, the [arg context] number.
+
+[call [cmd ::asn::asnContextConstr] [arg context] [arg evalue]...]
+
+Takes zero or more encoded values and packs them into a constructed
+value with application tag, the [arg context] number.
+
+[call [cmd ::asn::asnObjectIdentifier] [arg idlist]]
+
+Takes a list of at least 2 integers describing an object identifier
+(OID) value, and returns the encoded value.
+
+[call [cmd ::asn::asnUTCTime] [arg utcstring]]
+
+Returns the encoded form of the specified UTC time string.
+
+[call [cmd ::asn::asnNull]]
+
+Returns the NULL encoding.
+
+[call [cmd ::asn::asnBitString] [arg string]]
+
+Returns the encoded form of the specified [arg string].
+
+[call [cmd ::asn::asnOctetString] [arg string]]
+
+Returns the encoded form of the specified [arg string].
+
+[call [cmd ::asn::asnNumericString] [arg string]]
+
+Returns the [arg string] encoded as ASN.1 NumericString. Raises an
+error if the [arg string] contains characters other than decimal
+numbers and space.
+
+[call [cmd ::asn::asnPrintableString] [arg string]]
+
+Returns the [arg string] encoding as ASN.1 PrintableString. Raises an
+error if the [arg string] contains characters which are not allowed by
+the Printable String datatype. The allowed characters are A-Z, a-z,
+0-9, space, apostrophe, colon, parentheses, plus, minus, comma,
+period, forward slash, question mark, and the equals sign.
+
+[call [cmd ::asn::asnIA5String] [arg string]]
+
+Returns the [arg string] encoded as ASN.1 IA5String. Raises an error
+if the [arg string] contains any characters outside of the US-ASCII
+range.
+
+[call [cmd ::asn::asnBMPString] [arg string]]
+
+Returns the [arg string] encoded as ASN.1 Basic Multilingual Plane
+string (Which is essentialy big-endian UCS2).
+
+[call [cmd ::asn::asnUTF8String] [arg string]]
+
+Returns the [arg string] encoded as UTF8 String. Note that some legacy
+applications such as Windows CryptoAPI do not like UTF8 strings. Use
+BMPStrings if you are not sure.
+
+[call [cmd ::asn::asnString] [arg string]]
+
+Returns an encoded form of [arg string], choosing the most restricted
+ASN.1 string type possible. If the string contains non-ASCII
+characters, then there is more than one string type which can be
+used. See [cmd ::asn::defaultStringType].
+
+[call [cmd ::asn::defaultStringType] [opt [arg type]]]
+
+Selects the string type to use for the encoding of non-ASCII
+strings. Returns current default when called without argument. If the
+argument [arg type] is supplied, it should be either [const UTF8] or
+[const BMP] to choose UTF8String or BMPString respectively.
+
+[list_end]
+[para]
+
+[subsection DECODER]
+
+General notes:
+
+[list_begin enumerated]
+[enum]
+Nearly all decoder commands take two arguments. These arguments are variable
+names, except for [cmd ::asn::asnGetResponse]. The first variable
+contains the encoded ASN value to decode at the beginning, and more,
+and the second variable is where the value is stored to. The remainder
+of the input after the decoded value is stored back into the
+datavariable.
+
+[enum]
+After extraction the data variable is always modified first, before by
+writing the extracted value to its variable. This means that if both
+arguments refer to the same variable, it will always contain the
+extracted value after the call, and not the remainder of the input.
+
+[list_end]
+
+[para]
+[list_begin definitions]
+[call [cmd ::asn::asnPeekByte] [arg data_var] [arg byte_var]]
+
+Retrieve the first byte of the data, without modifing [arg data_var].
+This can be used to check for implicit tags.
+
+[call [cmd ::asn::asnGetLength] [arg data_var] [arg length_var]]
+
+Decode the length information for a block of BER data. The tag has already
+to be removed from the data.
+
+[call [cmd ::asn::asnGetResponse] [arg chan] [arg data_var]]
+
+Reads an encoded ASN [emph sequence] from the channel [arg chan] and
+stores it into the variable named by [arg data_var].
+
+[call [cmd ::asn::asnGetInteger] [arg data_var] [arg int_var]]
+
+Assumes that an encoded integer value is at the front of the data
+stored in the variable named [arg data_var], extracts and stores it
+into the variable named by [arg int_var]. Additionally removes all
+bytes associated with the value from the data for further processing
+by the following decoder commands.
+
+[call [cmd ::asn::asnGetEnumeration] [arg data_var] [arg enum_var]]
+
+Assumes that an enumeration id is at the front of the data stored in
+the variable named [arg data_var], and stores it into the variable
+named by [arg enum_var]. Additionally removes all bytes associated
+with the value from the data for further processing by the following
+decoder commands.
+
+[call [cmd ::asn::asnGetOctetString] [arg data_var] [arg string_var]]
+
+Assumes that a string is at the front of the data stored in the
+variable named [arg data_var], and stores it into the variable named
+by [arg string_var]. Additionally removes all bytes associated with
+the value from the data for further processing by the following
+decoder commands.
+
+[call [cmd ::asn::asnGetString] [arg data_var] [arg string_var] [opt [arg type_var]]]
+
+Decodes a user-readable string. This is a convenience function which
+is able to automatically distinguish all supported ASN.1 string types
+and convert the input value appropriately.
+
+See [cmd ::asn::asnGetPrintableString], [cmd ::asnGetIA5String], etc.
+below for the type-specific conversion commands.
+
+[para]
+
+If the optional third argument [arg type_var] is supplied, then the
+type of the incoming string is stored in the variable named by it.
+
+[para]
+
+The function throws the error
+
+"Invalid command name asnGetSome[var UnsupportedString]" if the
+unsupported string type [var Unsupported] is encountered. You can
+create the appropriate function
+
+"asn::asnGetSome[var UnsupportedString]" in your application if
+neccessary.
+
+[call [cmd ::asn::asnGetNumericString] [arg data_var] [arg string_var]]
+
+Assumes that a numeric string value is at the front of the data stored
+in the variable named [arg data_var], and stores it into the variable
+named by [arg string_var]. Additionally removes all bytes associated
+with the value from the data for further processing by the following
+decoder commands.
+
+[call [cmd ::asn::asnGetPrintableString] [arg data_var] [arg string_var]]
+
+Assumes that a printable string value is at the front of the data
+stored in the variable named [arg data_var], and stores it into the
+variable named by [arg string_var]. Additionally removes all bytes
+associated with the value from the data for further processing by the
+following decoder commands.
+
+[call [cmd ::asn::asnGetIA5String] [arg data_var] [arg string_var]]
+
+Assumes that a IA5 (ASCII) string value is at the front of the data
+stored in the variable named [arg data_var], and stores it into the
+variable named by [arg string_var]. Additionally removes all bytes
+associated with the value from the data for further processing by the
+following decoder commands.
+
+[call [cmd ::asn::asnGetBMPString] [arg data_var] [arg string_var]]
+
+Assumes that a BMP (two-byte unicode) string value is at the front of
+the data stored in the variable named [arg data_var], and stores it
+into the variable named by [arg string_var], converting it into a
+proper Tcl string. Additionally removes all bytes associated with the
+value from the data for further processing by the following decoder
+commands.
+
+[call [cmd ::asn::asnGetUTF8String] [arg data_var] [arg string_var]]
+
+Assumes that a UTF8 string value is at the front of the data stored in
+the variable named [arg data_var], and stores it into the variable
+named by [arg string_var], converting it into a proper Tcl string.
+Additionally removes all bytes associated with the value from the data
+for further processing by the following decoder commands.
+
+[call [cmd ::asn::asnGetUTCTime] [arg data_var] [arg utc_var]]
+
+Assumes that a UTC time value is at the front of the data stored in the
+variable named [arg data_var], and stores it into the variable named
+by [arg utc_var]. The UTC time value is stored as a string, which has to
+be decoded with the usual clock scan commands.
+Additionally removes all bytes associated with the
+value from the data for further processing by the following decoder
+commands.
+
+[call [cmd ::asn::asnGetBitString] [arg data_var] [arg bits_var]]
+
+Assumes that a bit string value is at the front of the data stored in the
+variable named [arg data_var], and stores it into the variable named
+by [arg bits_var] as a string containing only 0 and 1.
+Additionally removes all bytes associated with the
+value from the data for further processing by the following decoder
+commands.
+
+[call [cmd ::asn::asnGetObjectIdentifier] [arg data_var] [arg oid_var]]
+
+Assumes that a object identifier (OID) value is at the front of the data
+stored in the variable named [arg data_var], and stores it into the variable
+named by [arg oid_var] as a list of integers.
+Additionally removes all bytes associated with the
+value from the data for further processing by the following decoder
+commands.
+
+[call [cmd ::asn::asnGetBoolean] [arg data_var] [arg bool_var]]
+
+Assumes that a boolean value is at the front of the data stored in the
+variable named [arg data_var], and stores it into the variable named
+by [arg bool_var]. Additionally removes all bytes associated with the
+value from the data for further processing by the following decoder
+commands.
+
+[call [cmd ::asn::asnGetNull] [arg data_var]]
+
+Assumes that a NULL value is at the front of the data stored in the
+variable named [arg data_var] and removes the bytes used to encode it
+from the data.
+
+[call [cmd ::asn::asnGetSequence] [arg data_var] [arg sequence_var]]
+
+Assumes that an ASN sequence is at the front of the data stored in the
+variable named [arg data_var], and stores it into the variable named
+by [arg sequence_var]. Additionally removes all bytes associated with
+the value from the data for further processing by the following
+decoder commands.
+
+[para]
+
+The data in [arg sequence_var] is encoded binary and has to be
+further decoded according to the definition of the sequence, using the
+decoder commands here.
+
+[call [cmd ::asn::asnGetSet] [arg data_var] [arg set_var]]
+
+Assumes that an ASN set is at the front of the data stored in the
+variable named [arg data_var], and stores it into the variable named
+by [arg set_var]. Additionally removes all bytes associated with the
+value from the data for further processing by the following decoder
+commands.
+
+[para]
+
+The data in [arg set_var] is encoded binary and has to be further
+decoded according to the definition of the set, using the decoder
+commands here.
+
+[call [cmd ::asn::asnGetApplication] [arg data_var] [arg appNumber_var] [opt [arg content_var]] [opt [arg encodingType_var]]]
+
+Assumes that an ASN application construct is at the front of the data
+stored in the variable named [arg data_var], and stores its id into
+the variable named by [arg appNumber_var]. Additionally removes all
+bytes associated with the value from the data for further processing
+by the following decoder commands.
+
+If a [arg content_var] is specified, then the command places all data
+associated with it into the named variable, in the binary form which
+can be processed using the decoder commands of this package.
+
+If a [arg encodingType_var] is specified, then that var is set to 1 if
+the encoding is constructed and 0 if it is primitive.
+
+[para]
+
+Otherwise it is the responsibility of the caller to decode the
+remainder of the application construct based on the id retrieved by
+this command, using the decoder commands of this package.
+
+[call [cmd ::asn::asnGetContext] [arg data_var] [arg contextNumber_var] [opt [arg content_var]] [opt [arg encodingType_var]]]
+
+Assumes that an ASN context tag construct is at the front of the data
+stored in the variable named [arg data_var], and stores its id into
+the variable named by [arg contextNumber_var]. Additionally removes all
+bytes associated with the value from the data for further processing
+by the following decoder commands.
+
+If a [arg content_var] is specified, then the command places all data
+associated with it into the named variable, in the binary form which
+can be processed using the decoder commands of this package.
+
+If a [arg encodingType_var] is specified, then that var is set to 1 if
+the encoding is constructed and 0 if it is primitive.
+
+[para]
+
+Otherwise it is the responsibility of the caller to decode the
+remainder of the construct based on the id retrieved by this command,
+using the decoder commands of this package.
+
+[list_end]
+[para]
+[subsection {HANDLING TAGS}]
+
+Working with ASN.1 you often need to decode tagged values, which use a tag thats different
+from the universal tag for a type. In those cases you have to replace the tag with the universal tag
+used for the type, to decode the value.
+
+To decode a tagged value use the [cmd ::asn::asnRetag] to change the tag to the appropriate type
+to use one of the decoders for primitive values.
+
+To help with this the module contains three functions:
+
+[list_begin definitions]
+[call [cmd ::asn::asnPeekTag] [arg data_var] [arg tag_var] [arg tagtype_var] [arg constr_var]]
+
+The [cmd ::asn::asnPeekTag] command can be used to take a peek at the data and decode the tag value, without
+removing it from the data. The [arg tag_var] gets set to the tag number, while the [arg tagtype_var] gets set
+to the class of the tag. (Either UNIVERSAL, CONTEXT, APPLICATION or PRIVATE). The [arg constr_var] is set to 1 if the
+tag is for a constructed value, and to 0 for not constructed. It returns the length of the tag.
+
+[call [cmd ::asn::asnTag] [arg tagnumber] [opt [arg class]] [opt [arg tagstyle]]]
+
+The [cmd ::asn::asnTag] can be used to create a tag value. The [arg tagnumber] gives the number of the tag, while
+the [arg class] gives one of the classes (UNIVERSAL,CONTEXT,APPLICATION or PRIVATE). The class may be abbreviated to just the first letter (U,C,A,P),
+default is UNIVERSAL.
+The [arg tagstyle] is either C for Constructed encoding, or P for primitve encoding. It defaults to P. You can also use 1 instead of C and
+0 instead of P for direct use of the values returned by [cmd ::asn::asnPeekTag].
+
+[call [cmd ::asn::asnRetag] [arg data_var] [arg newTag]]
+
+Replaces the tag in front of the data in [arg data_var] with [arg newTag]. The new Tag can be created using the [cmd ::asn::asnTag] command.
+[list_end]
+
+[section EXAMPLES]
+
+Examples for the usage of this package can be found in the
+implementation of package [package ldap].
+
+[vset CATEGORY asn]
+[include ../doctools2base/include/feedback.inc]
+[manpage_end]
diff --git a/tcllib/modules/asn/asn.pcx b/tcllib/modules/asn/asn.pcx
new file mode 100644
index 0000000..2114928
--- /dev/null
+++ b/tcllib/modules/asn/asn.pcx
@@ -0,0 +1,271 @@
+# -*- tcl -*- asn.pcx
+# Syntax of the commands provided by package asn.
+#
+# For use by TclDevKit's static syntax checker (v4.1+).
+# See http://www.activestate.com/solutions/tcl/
+# See http://aspn.activestate.com/ASPN/docs/Tcl_Dev_Kit/4.0/Checker.html#pcx_api
+# for the specification of the format of the code in this file.
+#
+
+package require pcx
+pcx::register asn
+pcx::tcldep 0.8.4 needs tcl 8.4
+
+namespace eval ::asn {}
+
+pcx::message outOfMinRange {The number "%1$s" is below the allowed minimum of "%2$s"} err
+pcx::message outOfMaxRange {The number "%1$s" is aboove the allowed maximum of "%2$s"} err
+#pcx::scan <VERSION> <NAME> <RULE>
+
+pcx::check 0.8.3 std ::asn::asnApplication \
+ {checkSimpleArgs 2 2 {
+ checkWholeNum
+ checkWord
+ }}
+pcx::check 0.8.3 std ::asn::asnApplicationConstr \
+ {checkSimpleArgs 1 -1 {
+ checkWholeNum
+ checkWord
+ }}
+pcx::check 0.8.3 std ::asn::asnBMPString \
+ {checkSimpleArgs 1 1 {
+ checkWord
+ }}
+pcx::check 0.8.3 std ::asn::asnBitString \
+ {checkSimpleArgs 1 1 {
+ checkWord
+ }}
+pcx::check 0.8.3 std ::asn::asnBoolean \
+ {checkSimpleArgs 1 1 {
+ checkBoolean
+ }}
+pcx::check 0.8.3 std ::asn::asnChoice \
+ {checkSimpleArgs 1 -1 {
+ checkWholeNum
+ checkWord
+ }}
+pcx::check 0.8.3 std ::asn::asnChoiceConstr \
+ {checkSimpleArgs 1 -1 {
+ checkWholeNum
+ checkWord
+ }}
+pcx::check 0.8.3 std ::asn::asnContext \
+ {checkSimpleArgs 2 2 {
+ checkWholeNum
+ checkWord
+ }}
+pcx::check 0.8.3 std ::asn::asnContextConstr \
+ {checkSimpleArgs 1 -1 {
+ checkWholeNum
+ checkWord
+ }}
+pcx::check 0.8.3 std ::asn::asnEnumeration \
+ {checkSimpleArgs 1 1 {
+ checkWholeNum
+ }}
+pcx::check 0.8.3 std ::asn::asnGetApplication \
+ {checkSimpleArgs 2 4 {
+ checkVarNameWrite
+ checkVarNameWrite
+ checkVarNameWrite
+ checkVarNameWrite
+ }}
+pcx::check 0.8.3 std ::asn::asnGetBMPString \
+ {checkSimpleArgs 2 2 {
+ checkVarNameWrite
+ checkVarNameWrite
+ }}
+pcx::check 0.8.3 std ::asn::asnGetBitString \
+ {checkSimpleArgs 2 2 {
+ checkVarNameWrite
+ checkVarNameWrite
+ }}
+pcx::check 0.8.3 std ::asn::asnGetBoolean \
+ {checkSimpleArgs 2 2 {
+ checkVarNameWrite
+ checkVarNameWrite
+ }}
+pcx::check 0.8.3 std ::asn::asnGetContext \
+ {checkSimpleArgs 2 4 {
+ checkVarNameWrite
+ checkVarNameWrite
+ checkVarNameWrite
+ checkVarNameWrite
+ }}
+pcx::check 0.8.3 std ::asn::asnGetEnumeration \
+ {checkSimpleArgs 2 2 {
+ checkVarNameWrite
+ checkVarNameWrite
+ }}
+pcx::check 0.8.3 std ::asn::asnGetIA5String \
+ {checkSimpleArgs 2 2 {
+ checkVarNameWrite
+ checkVarNameWrite
+ }}
+pcx::check 0.8.3 std ::asn::asnGetInteger \
+ {checkSimpleArgs 2 2 {
+ checkVarNameWrite
+ checkVarNameWrite
+ }}
+pcx::check 0.8.3 std ::asn::asnGetLength \
+ {checkSimpleArgs 2 2 {
+ checkVarname
+ checkVarNameWrite
+ }}
+pcx::check 0.8.3 std ::asn::asnGetNull \
+ {checkSimpleArgs 1 1 {
+ checkVarNameWrite
+ }}
+pcx::check 0.8.3 std ::asn::asnGetNumericString \
+ {checkSimpleArgs 2 2 {
+ checkVarNameWrite
+ checkVarNameWrite
+ }}
+pcx::check 0.8.3 std ::asn::asnGetObjectIdentifier \
+ {checkSimpleArgs 2 2 {
+ checkVarNameWrite
+ checkVarNameWrite
+ }}
+pcx::check 0.8.3 std ::asn::asnGetOctetString \
+ {checkSimpleArgs 2 2 {
+ checkVarNameWrite
+ checkVarNameWrite
+ }}
+pcx::check 0.8.3 std ::asn::asnGetPrintableString \
+ {checkSimpleArgs 2 2 {
+ checkVarNameWrite
+ checkVarNameWrite
+ }}
+pcx::check 0.8.3 std ::asn::asnGetResponse \
+ {checkSimpleArgs 2 2 {
+ checkChannelID
+ checkVarNameWrite
+ }}
+pcx::check 0.8.3 std ::asn::asnGetSequence \
+ {checkSimpleArgs 2 2 {
+ checkVarNameWrite
+ checkVarNameWrite
+ }}
+pcx::check 0.8.3 std ::asn::asnGetSet \
+ {checkSimpleArgs 2 2 {
+ checkVarNameWrite
+ checkVarNameWrite
+ }}
+pcx::check 0.8.3 std ::asn::asnGetString \
+ {checkSimpleArgs 2 3 {
+ checkVarNameWrite
+ checkVarNameWrite
+ checkVarNameWrite
+ }}
+pcx::check 0.8.3 std ::asn::asnGetUTCTime \
+ {checkSimpleArgs 2 2 {
+ checkVarNameWrite
+ checkVarNameWrite
+ }}
+pcx::check 0.8.3 std ::asn::asnGetUTF8String \
+ {checkSimpleArgs 2 2 {
+ checkVarNameWrite
+ checkVarNameWrite
+ }}
+pcx::check 0.8.3 std ::asn::asnIA5String \
+ {checkSimpleArgs 1 1 {
+ checkWord
+ }}
+pcx::check 0.8.3 std ::asn::asnInteger \
+ {checkSimpleArgs 1 1 {
+ checkInt
+ }}
+pcx::check 0.8.3 std ::asn::asnNull \
+ {checkAtEnd}
+pcx::check 0.8.3 std ::asn::asnNumericString \
+ {checkSimpleArgs 1 1 {
+ checkWord
+ }}
+pcx::check 0.8.3 std ::asn::asnObjectIdentifier \
+ {checkSimpleArgs 1 1 {
+ checkListValues 2 -1 {
+ {pcx::checkRange 0 2}
+ {pcx::checkRange 0 39}
+ checkWholeNum
+ }
+ }}
+pcx::check 0.8.3 std ::asn::asnOctetString \
+ {checkSimpleArgs 1 1 {
+ checkWord
+ }}
+pcx::check 0.8.3 std ::asn::asnPeekByte \
+ {checkSimpleArgs 2 2 {
+ checkVarname
+ checkVarNameWrite
+ }}
+pcx::check 0.8.3 std ::asn::asnPeekTag \
+ {checkSimpleArgs 4 4 {
+ checkVarname
+ checkVarNameWrite
+ checkVarNameWrite
+ checkVarNameWrite
+ }}
+pcx::check 0.8.3 std ::asn::asnPrintableString \
+ {checkSimpleArgs 1 1 {
+ checkWord
+ }}
+pcx::check 0.8.3 std ::asn::asnRetag \
+ {checkSimpleArgs 2 2 {
+ checkVarNameWrite
+ checkWholeNum
+ }}
+pcx::check 0.8.3 std ::asn::asnSequence \
+ {checkSimpleArgs 0 -1 {
+ checkWord
+ }}
+pcx::check 0.8.3 std ::asn::asnSequenceFromList \
+ {checkSimpleArgs 1 1 {
+ checkList
+ }}
+pcx::check 0.8.3 std ::asn::asnSet \
+ {checkSimpleArgs 0 -1 {
+ checkWord
+ }}
+pcx::check 0.8.3 std ::asn::asnSetFromList \
+ {checkSimpleArgs 1 1 {
+ checkList
+ }}
+pcx::check 0.8.3 std ::asn::asnString \
+ {checkSimpleArgs 1 1 {
+ checkWord
+ }}
+pcx::check 0.8.3 std ::asn::asnTag \
+ {checkSimpleArgs 1 3 {
+ checkWholeNum
+ {checkKeyword 1 {UNIVERSAL CONTEXT APPLICATION PRIVATE U C A P}}
+ {checkKeyword 1 {C P 0 1}}
+ }}
+pcx::check 0.8.3 std ::asn::asnUTCTime \
+ {checkSimpleArgs 1 1 {
+ checkWord
+ }}
+pcx::check 0.8.3 std ::asn::asnUTF8String \
+ {checkSimpleArgs 1 1 {
+ checkWord
+ }}
+pcx::check 0.8.3 std ::asn::defaultStringType \
+ {checkSimpleArgs 0 1 {
+ {checkKeyword 1 {BMP UTF8}}
+ }}
+
+proc pcx::checkInitRange {min max t i} {
+ set w [lindex $t $i]
+ if {[getLiteral $w num] && ![catch {incr num 0}]} {
+ if {($min != {}) && ($num < $min)} {
+ logError pcx::outOfMinRange [getTokenRange $w] $num $min
+ }
+ if {($max != {}) && ($num > $max)} {
+ logError pcx::outOfMaxRange [getTokenRange $w] $num $min
+ }
+ }
+ return [checkInt $t $i]
+}
+
+# Initialization via pcx::init.
+# Use a ::asn::init procedure for non-standard initialization.
+pcx::complete
diff --git a/tcllib/modules/asn/asn.tcl b/tcllib/modules/asn/asn.tcl
new file mode 100644
index 0000000..cca460a
--- /dev/null
+++ b/tcllib/modules/asn/asn.tcl
@@ -0,0 +1,1580 @@
+#-----------------------------------------------------------------------------
+# Copyright (C) 1999-2004 Jochen C. Loewer (loewerj@web.de)
+# Copyright (C) 2004-2011 Michael Schlenker (mic42@users.sourceforge.net)
+#-----------------------------------------------------------------------------
+#
+# A partial ASN decoder/encoder implementation in plain Tcl.
+#
+# See ASN.1 (X.680) and BER (X.690).
+# See 'asn_ber_intro.txt' in this directory.
+#
+# This software is copyrighted by Jochen C. Loewer (loewerj@web.de). The
+# following terms apply to all files associated with the software unless
+# explicitly disclaimed in individual files.
+#
+# The authors hereby grant permission to use, copy, modify, distribute,
+# and license this software and its documentation for any purpose, provided
+# that existing copyright notices are retained in all copies and that this
+# notice is included verbatim in any distributions. No written agreement,
+# license, or royalty fee is required for any of the authorized uses.
+# Modifications to this software may be copyrighted by their authors
+# and need not follow the licensing terms described here, provided that
+# the new terms are clearly indicated on the first page of each file where
+# they apply.
+#
+# IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
+# FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+# ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
+# DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
+# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
+# IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
+# NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
+# MODIFICATIONS.
+#
+# written by Jochen Loewer
+# 3 June, 1999
+#
+# $Id: asn.tcl,v 1.20 2011/01/05 22:33:33 mic42 Exp $
+#
+#-----------------------------------------------------------------------------
+
+# needed for using wide()
+package require Tcl 8.4
+
+namespace eval asn {
+ # Encoder commands
+ namespace export \
+ asnSequence \
+ asnSequenceFromList \
+ asnSet \
+ asnSetFromList \
+ asnApplicationConstr \
+ asnApplication \
+ asnContext\
+ asnContextConstr\
+ asnChoice \
+ asnChoiceConstr \
+ asnInteger \
+ asnEnumeration \
+ asnBoolean \
+ asnOctetString \
+ asnNull \
+ asnUTCTime \
+ asnNumericString \
+ asnPrintableString \
+ asnIA5String\
+ asnBMPString\
+ asnUTF8String\
+ asnBitString \
+ asnObjectIdentifer
+
+ # Decoder commands
+ namespace export \
+ asnGetResponse \
+ asnGetInteger \
+ asnGetEnumeration \
+ asnGetOctetString \
+ asnGetSequence \
+ asnGetSet \
+ asnGetApplication \
+ asnGetNumericString \
+ asnGetPrintableString \
+ asnGetIA5String \
+ asnGetBMPString \
+ asnGetUTF8String \
+ asnGetObjectIdentifier \
+ asnGetBoolean \
+ asnGetUTCTime \
+ asnGetBitString \
+ asnGetContext
+
+ # general BER utility commands
+ namespace export \
+ asnPeekByte \
+ asnGetLength \
+ asnRetag \
+ asnPeekTag \
+ asnTag
+
+}
+
+#-----------------------------------------------------------------------------
+# Implementation notes:
+#
+# See the 'asn_ber_intro.txt' in this directory for an introduction
+# into BER/DER encoding of ASN.1 information. Bibliography information
+#
+# A Layman's Guide to a Subset of ASN.1, BER, and DER
+#
+# An RSA Laboratories Technical Note
+# Burton S. Kaliski Jr.
+# Revised November 1, 1993
+#
+# Supersedes June 3, 1991 version, which was also published as
+# NIST/OSI Implementors' Workshop document SEC-SIG-91-17.
+# PKCS documents are available by electronic mail to
+# <pkcs@rsa.com>.
+#
+# Copyright (C) 1991-1993 RSA Laboratories, a division of RSA
+# Data Security, Inc. License to copy this document is granted
+# provided that it is identified as "RSA Data Security, Inc.
+# Public-Key Cryptography Standards (PKCS)" in all material
+# mentioning or referencing this document.
+# 003-903015-110-000-000
+#
+#-----------------------------------------------------------------------------
+
+#-----------------------------------------------------------------------------
+# asnLength : Encode some length data. Helper command.
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnLength {len} {
+
+ if {$len < 0} {
+ return -code error "Negative length octet requested"
+ }
+ if {$len < 128} {
+ # short form: ISO X.690 8.1.3.4
+ return [binary format c $len]
+ }
+ # long form: ISO X.690 8.1.3.5
+ # try to use a minimal encoding,
+ # even if not required by BER, but it is required by DER
+ # take care for signed vs. unsigned issues
+ if {$len < 256 } {
+ return [binary format H2c 81 [expr {$len - 256}]]
+ }
+ if {$len < 32769} {
+ # two octet signed value
+ return [binary format H2S 82 $len]
+ }
+ if {$len < 65536} {
+ return [binary format H2S 82 [expr {$len - 65536}]]
+ }
+ if {$len < 8388608} {
+ # three octet signed value
+ return [binary format H2cS 83 [expr {$len >> 16}] [expr {($len & 0xFFFF) - 65536}]]
+ }
+ if {$len < 16777216} {
+ # three octet signed value
+ return [binary format H2cS 83 [expr {($len >> 16) -256}] [expr {($len & 0xFFFF) -65536}]]
+ }
+ if {$len < 2147483649} {
+ # four octet signed value
+ return [binary format H2I 84 $len]
+ }
+ if {$len < 4294967296} {
+ # four octet unsigned value
+ return [binary format H2I 84 [expr {$len - 4294967296}]]
+ }
+ if {$len < 1099511627776} {
+ # five octet unsigned value
+ return [binary format H2 85][string range [binary format W $len] 3 end]
+ }
+ if {$len < 281474976710656} {
+ # six octet unsigned value
+ return [binary format H2 86][string range [binary format W $len] 2 end]
+ }
+ if {$len < 72057594037927936} {
+ # seven octet value
+ return [binary format H2 87][string range [binary format W $len] 1 end]
+ }
+
+ # must be a 64-bit wide signed value
+ return [binary format H2W 88 $len]
+}
+
+#-----------------------------------------------------------------------------
+# asnSequence : Assumes that the arguments are already ASN encoded.
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnSequence {args} {
+ asnSequenceFromList $args
+}
+
+proc ::asn::asnSequenceFromList {lst} {
+ # The sequence tag is 0x30. The length is arbitrary and thus full
+ # length coding is required. The arguments have to be BER encoded
+ # already. Constructed value, definite-length encoding.
+
+ set out ""
+ foreach part $lst {
+ append out $part
+ }
+ set len [string length $out]
+ return [binary format H2a*a$len 30 [asnLength $len] $out]
+}
+
+
+#-----------------------------------------------------------------------------
+# asnSet : Assumes that the arguments are already ASN encoded.
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnSet {args} {
+ asnSetFromList $args
+}
+
+proc ::asn::asnSetFromList {lst} {
+ # The set tag is 0x31. The length is arbitrary and thus full
+ # length coding is required. The arguments have to be BER encoded
+ # already.
+
+ set out ""
+ foreach part $lst {
+ append out $part
+ }
+ set len [string length $out]
+ return [binary format H2a*a$len 31 [asnLength $len] $out]
+}
+
+
+#-----------------------------------------------------------------------------
+# asnApplicationConstr
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnApplicationConstr {appNumber args} {
+ # Packs the arguments into a constructed value with application tag.
+
+ set out ""
+ foreach part $args {
+ append out $part
+ }
+ set code [expr {0x060 + $appNumber}]
+ set len [string length $out]
+ return [binary format ca*a$len $code [asnLength $len] $out]
+}
+
+#-----------------------------------------------------------------------------
+# asnApplication
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnApplication {appNumber data} {
+ # Packs the arguments into a constructed value with application tag.
+
+ set code [expr {0x040 + $appNumber}]
+ set len [string length $data]
+ return [binary format ca*a$len $code [asnLength $len] $data]
+}
+
+#-----------------------------------------------------------------------------
+# asnContextConstr
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnContextConstr {contextNumber args} {
+ # Packs the arguments into a constructed value with application tag.
+
+ set out ""
+ foreach part $args {
+ append out $part
+ }
+ set code [expr {0x0A0 + $contextNumber}]
+ set len [string length $out]
+ return [binary format ca*a$len $code [asnLength $len] $out]
+}
+
+#-----------------------------------------------------------------------------
+# asnContext
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnContext {contextNumber data} {
+ # Packs the arguments into a constructed value with application tag.
+ set code [expr {0x080 + $contextNumber}]
+ set len [string length $data]
+ return [binary format ca*a$len $code [asnLength $len] $data]
+}
+#-----------------------------------------------------------------------------
+# asnChoice
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnChoice {appNumber args} {
+ # Packs the arguments into a choice construction.
+
+ set out ""
+ foreach part $args {
+ append out $part
+ }
+ set code [expr {0x080 + $appNumber}]
+ set len [string length $out]
+ return [binary format ca*a$len $code [asnLength $len] $out]
+}
+
+#-----------------------------------------------------------------------------
+# asnChoiceConstr
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnChoiceConstr {appNumber args} {
+ # Packs the arguments into a choice construction.
+
+ set out ""
+ foreach part $args {
+ append out $part
+ }
+ set code [expr {0x0A0 + $appNumber}]
+ set len [string length $out]
+ return [binary format ca*a$len $code [asnLength $len] $out]
+}
+
+#-----------------------------------------------------------------------------
+# asnInteger : Encode integer value.
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnInteger {number} {
+ asnIntegerOrEnum 02 $number
+}
+
+#-----------------------------------------------------------------------------
+# asnEnumeration : Encode enumeration value.
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnEnumeration {number} {
+ asnIntegerOrEnum 0a $number
+}
+
+#-----------------------------------------------------------------------------
+# asnIntegerOrEnum : Common code for Integers and Enumerations
+# No Bignum version, as we do not expect large Enums.
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnIntegerOrEnum {tag number} {
+ # The integer tag is 0x02 , the Enum Tag 0x0a otherwise identical.
+ # The length is 1, 2, 3, or 4, coded in a
+ # single byte. This can be done directly, no need to go through
+ # asnLength. The value itself is written in big-endian.
+
+ # Known bug/issue: The command cannot handle very wide integers, i.e.
+ # anything above 8 bytes length. Use asnBignumInteger for those.
+
+ # check if we really have an int
+ set num $number
+ incr num
+
+ if {($number >= -128) && ($number < 128)} {
+ return [binary format H2H2c $tag 01 $number]
+ }
+ if {($number >= -32768) && ($number < 32768)} {
+ return [binary format H2H2S $tag 02 $number]
+ }
+ if {($number >= -8388608) && ($number < 8388608)} {
+ set numberb [expr {$number & 0xFFFF}]
+ set numbera [expr {($number >> 16) & 0xFF}]
+ return [binary format H2H2cS $tag 03 $numbera $numberb]
+ }
+ if {($number >= -2147483648) && ($number < 2147483648)} {
+ return [binary format H2H2I $tag 04 $number]
+ }
+ if {($number >= -549755813888) && ($number < 549755813888)} {
+ set numberb [expr {$number & 0xFFFFFFFF}]
+ set numbera [expr {($number >> 32) & 0xFF}]
+ return [binary format H2H2cI $tag 05 $numbera $numberb]
+ }
+ if {($number >= -140737488355328) && ($number < 140737488355328)} {
+ set numberb [expr {$number & 0xFFFFFFFF}]
+ set numbera [expr {($number >> 32) & 0xFFFF}]
+ return [binary format H2H2SI $tag 06 $numbera $numberb]
+ }
+ if {($number >= -36028797018963968) && ($number < 36028797018963968)} {
+ set numberc [expr {$number & 0xFFFFFFFF}]
+ set numberb [expr {($number >> 32) & 0xFFFF}]
+ set numbera [expr {($number >> 48) & 0xFF}]
+ return [binary format H2H2cSI $tag 07 $numbera $numberb $numberc]
+ }
+ if {($number >= -9223372036854775808) && ($number <= 9223372036854775807)} {
+ return [binary format H2H2W $tag 08 $number]
+ }
+ return -code error "Integer value to large to encode, use asnBigInteger"
+}
+
+#-----------------------------------------------------------------------------
+# asnBigInteger : Encode a long integer value using math::bignum
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnBigInteger {bignum} {
+ # require math::bignum only if it is used
+ package require math::bignum
+
+ # this is a hack to check for bignum...
+ if {[llength $bignum] < 2 || ([lindex $bignum 0] ne "bignum")} {
+ return -code error "expected math::bignum value got \"$bignum\""
+ }
+ if {[math::bignum::sign $bignum]} {
+ # generate two's complement form
+ set bits [math::bignum::bits $bignum]
+ set padding [expr {$bits % 8}]
+ set len [expr {int(ceil($bits / 8.0))}]
+ if {$padding == 0} {
+ # we need a complete extra byte for the sign
+ # unless this is a base 2 multiple
+ set test [math::bignum::fromstr 0]
+ math::bignum::setbit test [expr {$bits-1}]
+ if {[math::bignum::ne [math::bignum::abs $bignum] $test]} {
+ incr len
+ }
+ }
+ set exp [math::bignum::pow \
+ [math::bignum::fromstr 256] \
+ [math::bignum::fromstr $len]]
+ set bignum [math::bignum::add $bignum $exp]
+ set hex [math::bignum::tostr $bignum 16]
+ } else {
+ set bits [math::bignum::bits $bignum]
+ if {($bits % 8) == 0 && $bits > 0} {
+ set pad "00"
+ } else {
+ set pad ""
+ }
+ set hex $pad[math::bignum::tostr $bignum 16]
+ }
+ if {[string length $hex]%2} {
+ set hex "0$hex"
+ }
+ set octets [expr {(([string length $hex]+1)/2)}]
+ return [binary format H2a*H* 02 [asnLength $octets] $hex]
+}
+
+
+#-----------------------------------------------------------------------------
+# asnBoolean : Encode a boolean value.
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnBoolean {bool} {
+ # The boolean tag is 0x01. The length is always 1, coded in
+ # a single byte. This can be done directly, no need to go through
+ # asnLength. The value itself is written in big-endian.
+
+ return [binary format H2H2c 01 01 [expr {$bool ? 0x0FF : 0x0}]]
+}
+
+#-----------------------------------------------------------------------------
+# asnOctetString : Encode a string of arbitrary bytes
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnOctetString {string} {
+ # The octet tag is 0x04. The length is arbitrary, so we need
+ # 'asnLength' for full coding of the length.
+
+ set len [string length $string]
+ return [binary format H2a*a$len 04 [asnLength $len] $string]
+}
+
+#-----------------------------------------------------------------------------
+# asnNull : Encode a null value
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnNull {} {
+ # Null has only one valid encoding
+ return \x05\x00
+}
+
+#-----------------------------------------------------------------------------
+# asnBitstring : Encode a Bit String value
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnBitString {bitstring} {
+ # The bit string tag is 0x03.
+ # Bit strings can be either simple or constructed
+ # we always use simple encoding
+
+ set bitlen [string length $bitstring]
+ set padding [expr {(8 - ($bitlen % 8)) % 8}]
+ set len [expr {($bitlen / 8) + 1}]
+ if {$padding != 0} { incr len }
+
+ return [binary format H2a*cB* 03 [asnLength $len] $padding $bitstring]
+}
+
+#-----------------------------------------------------------------------------
+# asnUTCTime : Encode an UTC time string
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnUTCTime {UTCtimestring} {
+ # the utc time tag is 0x17.
+ #
+ # BUG: we do not check the string for well formedness
+
+ set ascii [encoding convertto ascii $UTCtimestring]
+ set len [string length $ascii]
+ return [binary format H2a*a* 17 [asnLength $len] $ascii]
+}
+
+#-----------------------------------------------------------------------------
+# asnPrintableString : Encode a printable string
+#-----------------------------------------------------------------------------
+namespace eval asn {
+ variable nonPrintableChars {[^ A-Za-z0-9'()+,.:/?=-]}
+}
+proc ::asn::asnPrintableString {string} {
+ # the printable string tag is 0x13
+ variable nonPrintableChars
+ # it is basically a restricted ascii string
+ if {[regexp $nonPrintableChars $string ]} {
+ return -code error "Illegal character in PrintableString."
+ }
+
+ # check characters
+ set ascii [encoding convertto ascii $string]
+ return [asnEncodeString 13 $ascii]
+}
+
+#-----------------------------------------------------------------------------
+# asnIA5String : Encode an Ascii String
+#-----------------------------------------------------------------------------
+proc ::asn::asnIA5String {string} {
+ # the IA5 string tag is 0x16
+ # check for extended charachers
+ if {[string length $string]!=[string bytelength $string]} {
+ return -code error "Illegal character in IA5String"
+ }
+ set ascii [encoding convertto ascii $string]
+ return [asnEncodeString 16 $ascii]
+}
+
+#-----------------------------------------------------------------------------
+# asnNumericString : Encode a Numeric String type
+#-----------------------------------------------------------------------------
+namespace eval asn {
+ variable nonNumericChars {[^0-9 ]}
+}
+proc ::asn::asnNumericString {string} {
+ # the Numeric String type has tag 0x12
+ variable nonNumericChars
+ if {[regexp $nonNumericChars $string]} {
+ return -code error "Illegal character in Numeric String."
+ }
+
+ return [asnEncodeString 12 $string]
+}
+#----------------------------------------------------------------------
+# asnBMPString: Encode a Tcl string as Basic Multinligval (UCS2) string
+#-----------------------------------------------------------------------
+proc asn::asnBMPString {string} {
+ if {$::tcl_platform(byteOrder) eq "littleEndian"} {
+ set bytes ""
+ foreach {lo hi} [split [encoding convertto unicode $string] ""] {
+ append bytes $hi $lo
+ }
+ } else {
+ set bytes [encoding convertto unicode $string]
+ }
+ return [asnEncodeString 1e $bytes]
+}
+#---------------------------------------------------------------------------
+# asnUTF8String: encode tcl string as UTF8 String
+#----------------------------------------------------------------------------
+proc asn::asnUTF8String {string} {
+ return [asnEncodeString 0c [encoding convertto utf-8 $string]]
+}
+#-----------------------------------------------------------------------------
+# asnEncodeString : Encode an RestrictedCharacter String
+#-----------------------------------------------------------------------------
+proc ::asn::asnEncodeString {tag string} {
+ set len [string length $string]
+ return [binary format H2a*a$len $tag [asnLength $len] $string]
+}
+
+#-----------------------------------------------------------------------------
+# asnObjectIdentifier : Encode an Object Identifier value
+#-----------------------------------------------------------------------------
+proc ::asn::asnObjectIdentifier {oid} {
+ # the object identifier tag is 0x06
+
+ if {[llength $oid] < 2} {
+ return -code error "OID must have at least two subidentifiers."
+ }
+
+ # basic check that it is valid
+ foreach identifier $oid {
+ if {$identifier < 0} {
+ return -code error \
+ "Malformed OID. Identifiers must be positive Integers."
+ }
+ }
+
+ if {[lindex $oid 0] > 2} {
+ return -code error "First subidentifier must be 0,1 or 2"
+ }
+ if {[lindex $oid 1] > 39} {
+ return -code error \
+ "Second subidentifier must be between 0 and 39"
+ }
+
+ # handle the special cases directly
+ switch [llength $oid] {
+ 2 { return [binary format H2H2c 06 01 \
+ [expr {[lindex $oid 0]*40+[lindex $oid 1]}]] }
+ default {
+ # This can probably be written much shorter.
+ # Just a first try that works...
+ #
+ set octets [binary format c \
+ [expr {[lindex $oid 0]*40+[lindex $oid 1]}]]
+ foreach identifier [lrange $oid 2 end] {
+ set d 128
+ if {$identifier < 128} {
+ set subidentifier [list $identifier]
+ } else {
+ set subidentifier [list]
+ # find the largest divisor
+
+ while {($identifier / $d) >= 128} {
+ set d [expr {$d * 128}]
+ }
+ # and construct the subidentifiers
+ set remainder $identifier
+ while {$d >= 128} {
+ set coefficient [expr {($remainder / $d) | 0x80}]
+ set remainder [expr {$remainder % $d}]
+ set d [expr {$d / 128}]
+ lappend subidentifier $coefficient
+ }
+ lappend subidentifier $remainder
+ }
+ append octets [binary format c* $subidentifier]
+ }
+ return [binary format H2a*a* 06 \
+ [asnLength [string length $octets]] $octets]
+ }
+ }
+
+}
+
+#-----------------------------------------------------------------------------
+# asnGetResponse : Read a ASN response from a channel.
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnGetResponse {sock data_var} {
+ upvar 1 $data_var data
+
+ # We expect a sequence here (tag 0x30). The code below is an
+ # inlined replica of 'asnGetSequence', modified for reading from a
+ # channel instead of a string.
+
+ set tag [read $sock 1]
+
+ if {$tag == "\x30"} {
+ # The following code is a replica of 'asnGetLength', modified
+ # for reading the bytes from the channel instead of a string.
+
+ set len1 [read $sock 1]
+ binary scan $len1 c num
+ set length [expr {($num + 0x100) % 0x100}]
+
+ if {$length >= 0x080} {
+ # The byte the read is not the length, but a prefix, and
+ # the lower nibble tells us how many bytes follow.
+
+ set len_length [expr {$length & 0x7f}]
+
+ # BUG: We should not perform the value extraction for an
+ # BUG: improper length. It wastes cycles, and here it can
+ # BUG: cause us trouble, reading more data than there is
+ # BUG: on the channel. Depending on the channel
+ # BUG: configuration an attacker can induce us to block,
+ # BUG: causing a denial of service.
+ set lengthBytes [read $sock $len_length]
+
+ switch $len_length {
+ 1 {
+ binary scan $lengthBytes c length
+ set length [expr {($length + 0x100) % 0x100}]
+ }
+ 2 { binary scan $lengthBytes S length }
+ 3 { binary scan \x00$lengthBytes I length }
+ 4 { binary scan $lengthBytes I length }
+ default {
+ return -code error \
+ "length information too long ($len_length)"
+ }
+ }
+ }
+
+ # Now that the length is known we get the remainder,
+ # i.e. payload, and construct proper in-memory BER encoded
+ # sequence.
+
+ set rest [read $sock $length]
+ set data [binary format aa*a$length $tag [asnLength $length] $rest]
+ } else {
+ # Generate an error message if the data is not a sequence as
+ # we expected.
+
+ set tag_hex ""
+ binary scan $tag H2 tag_hex
+ return -code error "unknown start tag [string length $tag] $tag_hex"
+ }
+}
+
+if {[package vsatisfies [package present Tcl] 8.5.0]} {
+##############################################################################
+# Code for 8.5
+##############################################################################
+#-----------------------------------------------------------------------------
+# asnGetByte (8.5 version) : Retrieve a single byte from the data (unsigned)
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnGetByte {data_var byte_var} {
+ upvar 1 $data_var data $byte_var byte
+
+ binary scan [string index $data 0] cu byte
+ set data [string range $data 1 end]
+
+ return
+}
+
+#-----------------------------------------------------------------------------
+# asnPeekByte (8.5 version) : Retrieve a single byte from the data (unsigned)
+# without removing it.
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnPeekByte {data_var byte_var {offset 0}} {
+ upvar 1 $data_var data $byte_var byte
+
+ binary scan [string index $data $offset] cu byte
+
+ return
+}
+
+#-----------------------------------------------------------------------------
+# asnGetLength (8.5 version) : Decode an ASN length value (See notes)
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnGetLength {data_var length_var} {
+ upvar 1 $data_var data $length_var length
+
+ asnGetByte data length
+ if {$length == 0x080} {
+ return -code error "Indefinite length BER encoding not yet supported"
+ }
+ if {$length > 0x080} {
+ # The retrieved byte is a prefix value, and the integer in the
+ # lower nibble tells us how many bytes were used to encode the
+ # length data following immediately after this prefix.
+
+ set len_length [expr {$length & 0x7f}]
+
+ if {[string length $data] < $len_length} {
+ return -code error \
+ "length information invalid, not enough octets left"
+ }
+
+ asnGetBytes data $len_length lengthBytes
+
+ switch $len_length {
+ 1 { binary scan $lengthBytes cu length }
+ 2 { binary scan $lengthBytes Su length }
+ 3 { binary scan \x00$lengthBytes Iu length }
+ 4 { binary scan $lengthBytes Iu length }
+ default {
+ binary scan $lengthBytes H* hexstr
+ scan $hexstr %llx length
+ }
+ }
+ }
+ return
+}
+
+} else {
+##############################################################################
+# Code for Tcl 8.4
+##############################################################################
+#-----------------------------------------------------------------------------
+# asnGetByte : Retrieve a single byte from the data (unsigned)
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnGetByte {data_var byte_var} {
+ upvar 1 $data_var data $byte_var byte
+
+ binary scan [string index $data 0] c byte
+ set byte [expr {($byte + 0x100) % 0x100}]
+ set data [string range $data 1 end]
+
+ return
+}
+
+#-----------------------------------------------------------------------------
+# asnPeekByte : Retrieve a single byte from the data (unsigned)
+# without removing it.
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnPeekByte {data_var byte_var {offset 0}} {
+ upvar 1 $data_var data $byte_var byte
+
+ binary scan [string index $data $offset] c byte
+ set byte [expr {($byte + 0x100) % 0x100}]
+
+ return
+}
+
+#-----------------------------------------------------------------------------
+# asnGetLength : Decode an ASN length value (See notes)
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnGetLength {data_var length_var} {
+ upvar 1 $data_var data $length_var length
+
+ asnGetByte data length
+ if {$length == 0x080} {
+ return -code error "Indefinite length BER encoding not yet supported"
+ }
+ if {$length > 0x080} {
+ # The retrieved byte is a prefix value, and the integer in the
+ # lower nibble tells us how many bytes were used to encode the
+ # length data following immediately after this prefix.
+
+ set len_length [expr {$length & 0x7f}]
+
+ if {[string length $data] < $len_length} {
+ return -code error \
+ "length information invalid, not enough octets left"
+ }
+
+ asnGetBytes data $len_length lengthBytes
+
+ switch $len_length {
+ 1 {
+ # Efficiently coded data will not go through this
+ # path, as small length values can be coded directly,
+ # without a prefix.
+
+ binary scan $lengthBytes c length
+ set length [expr {($length + 0x100) % 0x100}]
+ }
+ 2 { binary scan $lengthBytes S length
+ set length [expr {($length + 0x10000) % 0x10000}]
+ }
+ 3 { binary scan \x00$lengthBytes I length
+ set length [expr {($length + 0x1000000) % 0x1000000}]
+ }
+ 4 { binary scan $lengthBytes I length
+ set length [expr {(wide($length) + 0x100000000) % 0x100000000}]
+ }
+ default {
+ binary scan $lengthBytes H* hexstr
+ # skip leading zeros which are allowed by BER
+ set hexlen [string trimleft $hexstr 0]
+ # check if it fits into a 64-bit signed integer
+ if {[string length $hexlen] > 16} {
+ return -code error -errorcode {ARITH IOVERFLOW
+ {Length value too large for normal use, try asnGetBigLength}} \
+ "Length value to large"
+ } elseif { [string length $hexlen] == 16 \
+ && ([string index $hexlen 0] & 0x8)} {
+ # check most significant bit, if set we need bignum
+ return -code error -errorcode {ARITH IOVERFLOW
+ {Length value too large for normal use, try asnGetBigLength}} \
+ "Length value to large"
+ } else {
+ scan $hexstr "%lx" length
+ }
+ }
+ }
+ }
+ return
+}
+
+}
+
+#-----------------------------------------------------------------------------
+# asnRetag: Remove an explicit tag with the real newTag
+#
+#-----------------------------------------------------------------------------
+proc ::asn::asnRetag {data_var newTag} {
+ upvar 1 $data_var data
+ set tag ""
+ set type ""
+ set len [asnPeekTag data tag type dummy]
+ asnGetBytes data $len tagbytes
+ set data [binary format c* $newTag]$data
+}
+
+#-----------------------------------------------------------------------------
+# asnGetBytes : Retrieve a block of 'length' bytes from the data.
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnGetBytes {data_var length bytes_var} {
+ upvar 1 $data_var data $bytes_var bytes
+
+ incr length -1
+ set bytes [string range $data 0 $length]
+ incr length
+ set data [string range $data $length end]
+
+ return
+}
+
+#-----------------------------------------------------------------------------
+# asnPeekTag : Decode the tag value
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnPeekTag {data_var tag_var tagtype_var constr_var} {
+ upvar 1 $data_var data $tag_var tag $tagtype_var tagtype $constr_var constr
+
+ set type 0
+ set offset 0
+ asnPeekByte data type $offset
+ # check if we have a simple tag, < 31, which fits in one byte
+
+ set tval [expr {$type & 0x1f}]
+ if {$tval == 0x1f} {
+ # long tag, max 64-bit with Tcl 8.4, unlimited with 8.5 bignum
+ asnPeekByte data tagbyte [incr offset]
+ set tval [expr {wide($tagbyte & 0x7f)}]
+ while {($tagbyte & 0x80)} {
+ asnPeekByte data tagbyte [incr offset]
+ set tval [expr {($tval << 7) + ($tagbyte & 0x7f)}]
+ }
+ }
+
+ set tagtype [lindex {UNIVERSAL APPLICATION CONTEXT PRIVATE} \
+ [expr {($type & 0xc0) >>6}]]
+ set tag $tval
+ set constr [expr {($type & 0x20) > 0}]
+
+ return [incr offset]
+}
+
+#-----------------------------------------------------------------------------
+# asnTag : Build a tag value
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnTag {tagnumber {class UNIVERSAL} {tagstyle P}} {
+ set first 0
+ if {$tagnumber < 31} {
+ # encode everything in one byte
+ set first $tagnumber
+ set bytes [list]
+ } else {
+ # multi-byte tag
+ set first 31
+ set bytes [list [expr {$tagnumber & 0x7f}]]
+ set tagnumber [expr {$tagnumber >> 7}]
+ while {$tagnumber > 0} {
+ lappend bytes [expr {($tagnumber & 0x7f)+0x80}]
+ set tagnumber [expr {$tagnumber >>7}]
+ }
+
+ }
+
+ if {$tagstyle eq "C" || $tagstyle == 1 } {incr first 32}
+ switch -glob -- $class {
+ U* { ;# UNIVERSAL }
+ A* { incr first 64 ;# APPLICATION }
+ C* { incr first 128 ;# CONTEXT }
+ P* { incr first 192 ;# PRIVATE }
+ default {
+ return -code error "Unknown tag class \"$class\""
+ }
+ }
+ if {[llength $bytes] > 0} {
+ # long tag
+ set rbytes [list]
+ for {set i [expr {[llength $bytes]-1}]} {$i >= 0} {incr i -1} {
+ lappend rbytes [lindex $bytes $i]
+ }
+ return [binary format cc* $first $rbytes ]
+ }
+ return [binary format c $first]
+}
+
+
+
+#-----------------------------------------------------------------------------
+# asnGetBigLength : Retrieve a length that can not be represented in 63-bit
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnGetBigLength {data_var biglength_var} {
+
+ # Does any real world code really need this?
+ # If we encounter this, we are doomed to fail anyway,
+ # (there would be an Exabyte inside the data_var, )
+ #
+ # So i implement it just for completeness.
+ #
+ package require math::bignum
+
+ upvar 1 $data_var data $biglength_var length
+
+ asnGetByte data length
+ if {$length == 0x080} {
+ return -code error "Indefinite length BER encoding not yet supported"
+ }
+ if {$length > 0x080} {
+ # The retrieved byte is a prefix value, and the integer in the
+ # lower nibble tells us how many bytes were used to encode the
+ # length data following immediately after this prefix.
+
+ set len_length [expr {$length & 0x7f}]
+
+ if {[string length $data] < $len_length} {
+ return -code error \
+ "length information invalid, not enough octets left"
+ }
+
+ asnGetBytes data $len_length lengthBytes
+ binary scan $lengthBytes H* hexlen
+ set length [math::bignum::fromstr $hexlen 16]
+ }
+ return
+}
+
+#-----------------------------------------------------------------------------
+# asnGetInteger : Retrieve integer.
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnGetInteger {data_var int_var} {
+ # Tag is 0x02.
+
+ upvar 1 $data_var data $int_var int
+
+ asnGetByte data tag
+
+ if {$tag != 0x02} {
+ return -code error \
+ [format "Expected Integer (0x02), but got %02x" $tag]
+ }
+
+ asnGetLength data len
+ asnGetBytes data $len integerBytes
+
+ set int ?
+
+ switch $len {
+ 1 { binary scan $integerBytes c int }
+ 2 { binary scan $integerBytes S int }
+ 3 {
+ # check for negative int and pad
+ scan [string index $integerBytes 0] %c byte
+ if {$byte & 128} {
+ binary scan \xff$integerBytes I int
+ } else {
+ binary scan \x00$integerBytes I int
+ }
+ }
+ 4 { binary scan $integerBytes I int }
+ 5 -
+ 6 -
+ 7 -
+ 8 {
+ # check for negative int and pad
+ scan [string index $integerBytes 0] %c byte
+ if {$byte & 128} {
+ set pad [string repeat \xff [expr {8-$len}]]
+ } else {
+ set pad [string repeat \x00 [expr {8-$len}]]
+ }
+ binary scan $pad$integerBytes W int
+ }
+ default {
+ # Too long, or prefix coding was used.
+ return -code error "length information too long"
+ }
+ }
+ return
+}
+
+#-----------------------------------------------------------------------------
+# asnGetBigInteger : Retrieve a big integer.
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnGetBigInteger {data_var bignum_var} {
+ # require math::bignum only if it is used
+ package require math::bignum
+
+ # Tag is 0x02. We expect that the length of the integer is coded with
+ # maximal efficiency, i.e. without a prefix 0x81 prefix. If a prefix
+ # is used this decoder will fail.
+
+ upvar $data_var data $bignum_var bignum
+
+ asnGetByte data tag
+
+ if {$tag != 0x02} {
+ return -code error \
+ [format "Expected Integer (0x02), but got %02x" $tag]
+ }
+
+ asnGetLength data len
+ asnGetBytes data $len integerBytes
+
+ binary scan [string index $integerBytes 0] H* hex_head
+ set head [expr 0x$hex_head]
+ set replacement_head [expr {$head & 0x7f}]
+ set integerBytes [string replace $integerBytes 0 0 [format %c $replacement_head]]
+
+ binary scan $integerBytes H* hex
+
+ set bignum [math::bignum::fromstr $hex 16]
+
+ if {($head >> 7) && 1} {
+ set bigsub [math::bignum::pow [::math::bignum::fromstr 2] [::math::bignum::fromstr [expr {($len * 8) - 1}]]]
+ set bignum [math::bignum::sub $bignum $bigsub]
+ }
+
+ return $bignum
+}
+
+
+
+
+#-----------------------------------------------------------------------------
+# asnGetEnumeration : Retrieve an enumeration id
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnGetEnumeration {data_var enum_var} {
+ # This is like 'asnGetInteger', except for a different tag.
+
+ upvar 1 $data_var data $enum_var enum
+
+ asnGetByte data tag
+
+ if {$tag != 0x0a} {
+ return -code error \
+ [format "Expected Enumeration (0x0a), but got %02x" $tag]
+ }
+
+ asnGetLength data len
+ asnGetBytes data $len integerBytes
+ set enum ?
+
+ switch $len {
+ 1 { binary scan $integerBytes c enum }
+ 2 { binary scan $integerBytes S enum }
+ 3 { binary scan \x00$integerBytes I enum }
+ 4 { binary scan $integerBytes I enum }
+ default {
+ return -code error "length information too long"
+ }
+ }
+ return
+}
+
+#-----------------------------------------------------------------------------
+# asnGetOctetString : Retrieve arbitrary string.
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnGetOctetString {data_var string_var} {
+ # Here we need the full decoder for length data.
+
+ upvar 1 $data_var data $string_var string
+
+ asnGetByte data tag
+ if {$tag != 0x04} {
+ return -code error \
+ [format "Expected Octet String (0x04), but got %02x" $tag]
+ }
+ asnGetLength data length
+ asnGetBytes data $length temp
+ set string $temp
+ return
+}
+
+#-----------------------------------------------------------------------------
+# asnGetSequence : Retrieve Sequence data for further decoding.
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnGetSequence {data_var sequence_var} {
+ # Here we need the full decoder for length data.
+
+ upvar 1 $data_var data $sequence_var sequence
+
+ asnGetByte data tag
+ if {$tag != 0x030} {
+ return -code error \
+ [format "Expected Sequence (0x30), but got %02x" $tag]
+ }
+ asnGetLength data length
+ asnGetBytes data $length temp
+ set sequence $temp
+ return
+}
+
+#-----------------------------------------------------------------------------
+# asnGetSet : Retrieve Set data for further decoding.
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnGetSet {data_var set_var} {
+ # Here we need the full decoder for length data.
+
+ upvar 1 $data_var data $set_var set
+
+ asnGetByte data tag
+ if {$tag != 0x031} {
+ return -code error \
+ [format "Expected Set (0x31), but got %02x" $tag]
+ }
+ asnGetLength data length
+ asnGetBytes data $length temp
+ set set $temp
+ return
+}
+
+#-----------------------------------------------------------------------------
+# asnGetApplication
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnGetApplication {data_var appNumber_var {content_var {}} {encodingType_var {}} } {
+ upvar 1 $data_var data $appNumber_var appNumber
+
+ asnGetByte data tag
+ asnGetLength data length
+
+ if {($tag & 0xC0) != 0x40} {
+ return -code error \
+ [format "Expected Application, but got %02x" $tag]
+ }
+ if {$encodingType_var != {}} {
+ upvar 1 $encodingType_var encodingType
+ set encodingType [expr {($tag & 0x20) > 0}]
+ }
+ set appNumber [expr {$tag & 0x1F}]
+ if {[string length $content_var]} {
+ upvar 1 $content_var content
+ asnGetBytes data $length content
+ }
+ return
+}
+
+#-----------------------------------------------------------------------------
+# asnGetBoolean: decode a boolean value
+#-----------------------------------------------------------------------------
+
+proc asn::asnGetBoolean {data_var bool_var} {
+ upvar 1 $data_var data $bool_var bool
+
+ asnGetByte data tag
+ if {$tag != 0x01} {
+ return -code error \
+ [format "Expected Boolean (0x01), but got %02x" $tag]
+ }
+
+ asnGetLength data length
+ asnGetByte data byte
+ set bool [expr {$byte == 0 ? 0 : 1}]
+ return
+}
+
+#-----------------------------------------------------------------------------
+# asnGetUTCTime: Extract an UTC Time string from the data. Returns a string
+# representing an UTC Time.
+#
+#-----------------------------------------------------------------------------
+
+proc asn::asnGetUTCTime {data_var utc_var} {
+ upvar 1 $data_var data $utc_var utc
+
+ asnGetByte data tag
+ if {$tag != 0x17} {
+ return -code error \
+ [format "Expected UTCTime (0x17), but got %02x" $tag]
+ }
+
+ asnGetLength data length
+ asnGetBytes data $length bytes
+
+ # this should be ascii, make it explicit
+ set bytes [encoding convertfrom ascii $bytes]
+ binary scan $bytes a* utc
+
+ return
+}
+
+
+#-----------------------------------------------------------------------------
+# asnGetBitString: Extract a Bit String value (a string of 0/1s) from the
+# ASN.1 data.
+#
+#-----------------------------------------------------------------------------
+
+proc asn::asnGetBitString {data_var bitstring_var} {
+ upvar 1 $data_var data $bitstring_var bitstring
+
+ asnGetByte data tag
+ if {$tag != 0x03} {
+ return -code error \
+ [format "Expected Bit String (0x03), but got %02x" $tag]
+ }
+
+ asnGetLength data length
+ # get the number of padding bits used at the end
+ asnGetByte data padding
+ incr length -1
+ asnGetBytes data $length bytes
+ binary scan $bytes B* bits
+
+ # cut off the padding bits
+ set bits [string range $bits 0 end-$padding]
+ set bitstring $bits
+}
+
+#-----------------------------------------------------------------------------
+# asnGetObjectIdentifier: Decode an ASN.1 Object Identifier (OID) into
+# a Tcl list of integers.
+#-----------------------------------------------------------------------------
+
+proc asn::asnGetObjectIdentifier {data_var oid_var} {
+ upvar 1 $data_var data $oid_var oid
+
+ asnGetByte data tag
+ if {$tag != 0x06} {
+ return -code error \
+ [format "Expected Object Identifier (0x06), but got %02x" $tag]
+ }
+ asnGetLength data length
+
+ # the first byte encodes the OID parts in position 0 and 1
+ asnGetByte data val
+ set oid [expr {$val / 40}]
+ lappend oid [expr {$val % 40}]
+ incr length -1
+
+ # the next bytes encode the remaining parts of the OID
+ set bytes [list]
+ set incomplete 0
+ while {$length} {
+ asnGetByte data octet
+ incr length -1
+ if {$octet < 128} {
+ set oidval $octet
+ set mult 128
+ foreach byte $bytes {
+ if {$byte != {}} {
+ incr oidval [expr {$mult*$byte}]
+ set mult [expr {$mult*128}]
+ }
+ }
+ lappend oid $oidval
+ set bytes [list]
+ set incomplete 0
+ } else {
+ set byte [expr {$octet-128}]
+ set bytes [concat [list $byte] $bytes]
+ set incomplete 1
+ }
+ }
+ if {$incomplete} {
+ return -code error "OID Data is incomplete, not enough octets."
+ }
+ return
+}
+
+#-----------------------------------------------------------------------------
+# asnGetContext: Decode an explicit context tag
+#
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnGetContext {data_var contextNumber_var {content_var {}} {encodingType_var {}}} {
+ upvar 1 $data_var data $contextNumber_var contextNumber
+
+ asnGetByte data tag
+ asnGetLength data length
+
+ if {($tag & 0xC0) != 0x80} {
+ return -code error \
+ [format "Expected Context, but got %02x" $tag]
+ }
+ if {$encodingType_var != {}} {
+ upvar 1 $encodingType_var encodingType
+ set encodingType [expr {($tag & 0x20) > 0}]
+ }
+ set contextNumber [expr {$tag & 0x1F}]
+ if {[string length $content_var]} {
+ upvar 1 $content_var content
+ asnGetBytes data $length content
+ }
+ return
+}
+
+
+#-----------------------------------------------------------------------------
+# asnGetNumericString: Decode a Numeric String from the data
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnGetNumericString {data_var print_var} {
+ upvar 1 $data_var data $print_var print
+
+ asnGetByte data tag
+ if {$tag != 0x12} {
+ return -code error \
+ [format "Expected Numeric String (0x12), but got %02x" $tag]
+ }
+ asnGetLength data length
+ asnGetBytes data $length string
+ set print [encoding convertfrom ascii $string]
+ return
+}
+
+#-----------------------------------------------------------------------------
+# asnGetPrintableString: Decode a Printable String from the data
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnGetPrintableString {data_var print_var} {
+ upvar 1 $data_var data $print_var print
+
+ asnGetByte data tag
+ if {$tag != 0x13} {
+ return -code error \
+ [format "Expected Printable String (0x13), but got %02x" $tag]
+ }
+ asnGetLength data length
+ asnGetBytes data $length string
+ set print [encoding convertfrom ascii $string]
+ return
+}
+
+#-----------------------------------------------------------------------------
+# asnGetIA5String: Decode a IA5(ASCII) String from the data
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnGetIA5String {data_var print_var} {
+ upvar 1 $data_var data $print_var print
+
+ asnGetByte data tag
+ if {$tag != 0x16} {
+ return -code error \
+ [format "Expected IA5 String (0x16), but got %02x" $tag]
+ }
+ asnGetLength data length
+ asnGetBytes data $length string
+ set print [encoding convertfrom ascii $string]
+ return
+}
+#------------------------------------------------------------------------
+# asnGetBMPString: Decode Basic Multiningval (UCS2 string) from data
+#------------------------------------------------------------------------
+proc asn::asnGetBMPString {data_var print_var} {
+ upvar 1 $data_var data $print_var print
+ asnGetByte data tag
+ if {$tag != 0x1e} {
+ return -code error \
+ [format "Expected BMP String (0x1e), but got %02x" $tag]
+ }
+ asnGetLength data length
+ asnGetBytes data $length string
+ if {$::tcl_platform(byteOrder) eq "littleEndian"} {
+ set str2 ""
+ foreach {hi lo} [split $string ""] {
+ append str2 $lo $hi
+ }
+ } else {
+ set str2 $string
+ }
+ set print [encoding convertfrom unicode $str2]
+ return
+}
+#------------------------------------------------------------------------
+# asnGetUTF8String: Decode UTF8 string from data
+#------------------------------------------------------------------------
+proc asn::asnGetUTF8String {data_var print_var} {
+ upvar 1 $data_var data $print_var print
+ asnGetByte data tag
+ if {$tag != 0x0c} {
+ return -code error \
+ [format "Expected UTF8 String (0x0c), but got %02x" $tag]
+ }
+ asnGetLength data length
+ asnGetBytes data $length string
+ #there should be some error checking to see if input is
+ #properly-formatted utf8
+ set print [encoding convertfrom utf-8 $string]
+
+ return
+}
+#-----------------------------------------------------------------------------
+# asnGetNull: decode a NULL value
+#-----------------------------------------------------------------------------
+
+proc ::asn::asnGetNull {data_var} {
+ upvar 1 $data_var data
+
+ asnGetByte data tag
+ if {$tag != 0x05} {
+ return -code error \
+ [format "Expected NULL (0x05), but got %02x" $tag]
+ }
+
+ asnGetLength data length
+ asnGetBytes data $length bytes
+
+ # we do not check the null data, all bytes must be 0x00
+
+ return
+}
+
+#----------------------------------------------------------------------------
+# MultiType string routines
+#----------------------------------------------------------------------------
+
+namespace eval asn {
+ variable stringTypes
+ array set stringTypes {
+ 12 NumericString
+ 13 PrintableString
+ 16 IA5String
+ 1e BMPString
+ 0c UTF8String
+ 14 T61String
+ 15 VideotexString
+ 1a VisibleString
+ 1b GeneralString
+ 1c UniversalString
+ }
+ variable defaultStringType UTF8
+}
+#---------------------------------------------------------------------------
+# asnGetString - get readable string automatically detecting its type
+#---------------------------------------------------------------------------
+proc ::asn::asnGetString {data_var print_var {type_var {}}} {
+ variable stringTypes
+ upvar 1 $data_var data $print_var print
+ asnPeekByte data tag
+ set tag [format %02x $tag]
+ if {![info exists stringTypes($tag)]} {
+ return -code error "Expected one of string types, but got $tag"
+ }
+ asnGet$stringTypes($tag) data print
+ if {[string length $type_var]} {
+ upvar $type_var type
+ set type $stringTypes($tag)
+ }
+}
+#---------------------------------------------------------------------
+# defaultStringType - set or query default type for unrestricted strings
+#---------------------------------------------------------------------
+proc ::asn::defaultStringType {{type {}}} {
+ variable defaultStringType
+ if {![string length $type]} {
+ return $defaultStringType
+ }
+ if {$type ne "BMP" && $type ne "UTF8"} {
+ return -code error "Invalid default string type. Should be one of BMP, UTF8"
+ }
+ set defaultStringType $type
+ return
+}
+
+#---------------------------------------------------------------------------
+# asnString - encode readable string into most restricted type possible
+#---------------------------------------------------------------------------
+
+proc ::asn::asnString {string} {
+ variable nonPrintableChars
+ variable nonNumericChars
+ if {[string length $string]!=[string bytelength $string]} {
+ # There are non-ascii character
+ variable defaultStringType
+ return [asn${defaultStringType}String $string]
+ } elseif {![regexp $nonNumericChars $string]} {
+ return [asnNumericString $string]
+ } elseif {![regexp $nonPrintableChars $string]} {
+ return [asnPrintableString $string]
+ } else {
+ return [asnIA5String $string]
+ }
+}
+
+#-----------------------------------------------------------------------------
+package provide asn 0.8.4
+
diff --git a/tcllib/modules/asn/asn.test b/tcllib/modules/asn/asn.test
new file mode 100644
index 0000000..9ec628b
--- /dev/null
+++ b/tcllib/modules/asn/asn.test
@@ -0,0 +1,956 @@
+# -*- tcl -*-
+# asn.test: tests for the asn BER encoding/decoding module.
+#
+# Copyright (c) 2004 by Andreas Kupries <andreas_kupries@users.sourceforge.net>
+# Copyright (c) 2004-2007 by Michael Schlenker <mic42@users.sourceforge.net>
+# All rights reserved.
+#
+# RCS: @(#) $Id: asn.test,v 1.19 2011/01/05 22:33:33 mic42 Exp $
+
+# -------------------------------------------------------------------------
+
+
+source [file join \
+ [file dirname [file dirname [file join [pwd] [info script]]]] \
+ devtools testutilities.tcl]
+
+
+testsNeedTcl 8.4
+testsNeedTcltest 1.0
+
+testing {
+ useLocal asn.tcl asn
+}
+
+# Converts binary encoded structure into hexadecimal dump
+# which is more readable in test results
+# Allows cut'n'paste both encoded and parsed OID from dumpasn1.cfg
+#
+proc bytes2hex {string} {
+ foreach b [split $string ""] {
+ lappend l [format %02X [scan $b %c]]
+ }
+ return [join $l " "]
+}
+
+# -------------------------------------------------------------------------
+
+test asn-1.0 {integer} {
+ catch {asn::asnInteger} result
+ set result
+} [tcltest::wrongNumArgs {asn::asnInteger} {number} 0]
+
+test asn-1.1 {integer} {
+ catch {asn::asnInteger a b} result
+ set result
+} [tcltest::tooManyArgs {asn::asnInteger} {number}]
+
+test asn-1.2 {integer} {
+ catch {asn::asnInteger a} result
+ set result
+} {expected integer but got "a"}
+
+
+test asn-3.0 {enum} {
+ catch {asn::asnEnumeration} result
+ set result
+} [tcltest::wrongNumArgs {asn::asnEnumeration} {number} 0]
+
+test asn-3.1 {enum} {
+ catch {asn::asnEnumeration a b} result
+ set result
+} [tcltest::tooManyArgs {asn::asnEnumeration} {number}]
+
+test asn-3.2 {enum} {
+ catch {asn::asnEnumeration a} result
+ set result
+} {expected integer but got "a"}
+
+
+
+
+foreach {n i len hex} {
+ 0 0 01 00
+ 1 -1 01 FF
+ 2 1 01 01
+ 3 127 01 7F
+ 4 128 02 0080
+ 5 129 02 0081
+ 6 256 02 0100
+ 7 -127 01 81
+ 8 -128 01 80
+ 9 -129 02 FF7F
+ 10 32766 02 7FFE
+ 11 32767 02 7FFF
+ 12 32768 03 008000
+ 13 32769 03 008001
+ 14 -32767 02 8001
+ 15 -32768 02 8000
+ 16 -32769 03 FF7FFF
+ 17 65536 03 010000
+ 18 8388607 03 7FFFFF
+ 19 8388608 04 00800000
+ 20 8388609 04 00800001
+ 21 16777216 04 01000000
+ 22 -8388607 03 800001
+ 23 -8388608 03 800000
+ 24 -8388609 04 FF7FFFFF
+ 25 -65536 03 FF0000
+ 26 -2147483648 04 80000000
+ 27 2147483647 04 7FFFFFFF
+ 28 -549755813888 05 8000000000
+ 29 549755813887 05 7FFFFFFFFF
+ 30 -140737488355328 06 800000000000
+ 31 140737488355327 06 7FFFFFFFFFFF
+ 32 -36028797018963968 07 80000000000000
+ 33 36028797018963967 07 7FFFFFFFFFFFFF
+ 34 36028797018963968 08 0080000000000000
+ 35 -9223372036854775808 08 8000000000000000
+ 36 9223372036854775807 08 7FFFFFFFFFFFFFFF
+} {
+ test asn-2.$n {integer} {
+ binary scan [asn::asnInteger $i] H* result
+ list $i [string toupper $result]
+ } [list $i 02$len$hex] ; # {}
+
+ test asn-4.$n {enum} {
+ binary scan [asn::asnEnumeration $i] H* result
+ list $i [string toupper $result]
+ } [list $i 0A$len$hex] ; # {}
+}
+
+test asn-5.0 {boolean} {
+ catch {asn::asnBoolean} result
+ set result
+} [tcltest::wrongNumArgs {asn::asnBoolean} {bool} 0]
+
+test asn-5.1 {boolean} {
+ catch {asn::asnBoolean a b} result
+ set result
+} [tcltest::tooManyArgs {asn::asnBoolean} {bool}]
+
+test asn-5.2 {boolean} {
+ catch {asn::asnBoolean a} result
+ set result
+} {expected boolean value but got "a"}
+
+test asn-5.3 {boolean - true} {
+ binary scan [asn::asnBoolean 1] H* result
+ string toupper $result
+} {0101FF}
+
+test asn-5.4 {boolean - false} {
+ binary scan [asn::asnBoolean 0] H* result
+ string toupper $result
+} {010100}
+
+test asn-6.0 {parse boolean} {
+ catch {asn::asnGetBoolean} result
+ set result
+} [tcltest::wrongNumArgs {asn::asnGetBoolean} {data_var bool_var} 0]
+
+test asn-6.1 {parse boolean} {
+ catch {asn::asnGetBoolean a} result
+ set result
+} [tcltest::wrongNumArgs {asn::asnGetBoolean} {data_var bool_var} 1]
+
+test asn-6.2 {parse boolean} {
+ catch {asn::asnGetBoolean a b c} result
+ set result
+} [tcltest::tooManyArgs {asn::asnGetBoolean} {data_var bool_var}]
+
+test asn-6.3 {parse boolean} {
+ catch {asn::asnGetBoolean a b} result
+ set result
+} {can't read "data": no such variable}
+
+test asn-6.4 {parse boolean - wrong tag} {
+ set a \x02\x01\x00
+ catch {asn::asnGetBoolean a b} result
+ set result
+} {Expected Boolean (0x01), but got 02}
+
+test asn-6.5 {parse boolean - wrong length} {
+ set a \x01\x02\x00
+ catch {asn::asnGetBoolean a b} result
+ list $result $b
+} [list "" 0]
+
+test asn-6.6 {parse boolean - true} {
+ set a \x01\x01\xFF
+ asn::asnGetBoolean a b
+ set b
+} 1
+
+test asn-6.7 {parse boolean - true} {
+ set a \x01\x01\x01
+ asn::asnGetBoolean a b
+ set b
+} 1
+
+test asn-6.8 {parse boolean - false} {
+ set a \x01\x01\x00
+ asn::asnGetBoolean a b
+ set b
+} 0
+
+test asn-7.0 {null} {
+ catch {asn::asnNull foo} result
+ set result
+} [tcltest::tooManyArgs {asn::asnNull} {}]
+
+test asn-7.1 {null} {
+ binary scan [asn::asnNull] H* result
+ set result
+} {0500}
+
+test asn-8.0 {parse null} {
+ catch {asn::asnGetNull} result
+ set result
+} [tcltest::wrongNumArgs asn::asnGetNull {data_var} 0]
+
+test asn-8.1 {parse null} {
+ catch {asn::asnGetNull foo bar} result
+ set result
+} [tcltest::tooManyArgs {asn::asnGetNull} {data_var}]
+
+test asn-8.2 {parse null} {
+ set wrongtag \x01\x01
+ catch {asn::asnGetNull wrongtag} result
+ set result
+} {Expected NULL (0x05), but got 01}
+
+test asn-8.3 {parse null} {
+ set wronglength \x05\x01
+ catch {asn::asnGetNull wronglength} result
+ set result
+} {}
+
+test asn-8.4 {parse null} {
+ set null \x05\x00
+ asn::asnGetNull null
+} {}
+
+package require math::bignum
+foreach {n i len hex} {
+ 0 0 01 00
+ 1 -1 01 FF
+ 2 1 01 01
+ 3 127 01 7F
+ 4 128 02 0080
+ 5 129 02 0081
+ 6 256 02 0100
+ 7 -127 01 81
+ 8 -128 01 80
+ 9 -129 02 FF7F
+ 10 32766 02 7FFE
+ 11 32767 02 7FFF
+ 12 32768 03 008000
+ 13 32769 03 008001
+ 14 -32767 02 8001
+ 15 -32768 02 8000
+ 16 -32769 03 FF7FFF
+ 17 65536 03 010000
+ 18 8388607 03 7FFFFF
+ 19 8388608 04 00800000
+ 20 8388609 04 00800001
+ 21 16777216 04 01000000
+ 22 -8388607 03 800001
+ 23 -8388608 03 800000
+ 24 -8388609 04 FF7FFFFF
+ 25 -65536 03 FF0000
+} {
+ test asn-9.$n {big integer} {
+ binary scan [asn::asnBigInteger [math::bignum::fromstr $i]] H* result
+ list $i [string toupper $result]
+ } [list $i 02$len$hex] ; # {}
+
+}
+
+foreach {n len hex} {
+ 0 0 00
+ 1 1 01
+ 2 127 7F
+ 3 128 8180
+ 4 129 8181
+ 5 255 81FF
+ 6 256 820100
+ 7 32767 827FFF
+ 8 32768 828000
+ 9 32769 828001
+ 10 65535 82FFFF
+ 11 65536 83010000
+ 12 8388607 837FFFFF
+ 13 8388608 83800000
+ 14 8388609 83800001
+ 15 16777215 83FFFFFF
+ 16 16777216 8401000000
+ 17 4294967295 84FFFFFFFF
+ 18 4294967296 850100000000
+ 19 1099511627775 85FFFFFFFFFF
+ 20 1099511627776 86010000000000
+ 21 281474976710655 86FFFFFFFFFFFF
+ 22 281474976710656 8701000000000000
+ 23 72057594037927935 87FFFFFFFFFFFFFF
+ 24 72057594037927936 880100000000000000
+ 25 9223372036854775807 887FFFFFFFFFFFFFFF
+ } {
+ test asn-10.$n {asnLength encoding} {
+ binary scan [asn::asnLength $len] H* result
+ string toupper $result
+ } $hex
+}
+
+foreach {n len hex} {
+ 0 0 00
+ 1 1 01
+ 2 127 7F
+ 3 128 8180
+ 4 129 8181
+ 5 255 81FF
+ 6 256 820100
+ 7 32767 827FFF
+ 8 32768 828000
+ 9 32769 828001
+ 10 65535 82FFFF
+ 11 65536 83010000
+ 12 8388607 837FFFFF
+ 13 8388608 83800000
+ 14 8388609 83800001
+ 15 16777215 83FFFFFF
+ 16 16777216 8401000000
+ 17 4294967295 84FFFFFFFF
+ 18 4294967296 850100000000
+ 19 1099511627775 85FFFFFFFFFF
+ 20 1099511627776 86010000000000
+ 21 281474976710655 86FFFFFFFFFFFF
+ 22 281474976710656 8701000000000000
+ 23 72057594037927935 87FFFFFFFFFFFFFF
+ 24 72057594037927936 880100000000000000
+ 25 9223372036854775807 887FFFFFFFFFFFFFFF
+ } {
+ test asn-11.$n {asnGetLength decoding} {
+ set data [binary format H* $hex ]
+ asn::asnGetLength data length
+ set length
+ } $len
+}
+
+foreach {n i len hex} {
+ 0 0 01 00
+ 1 -1 01 FF
+ 2 1 01 01
+ 3 127 01 7F
+ 4 128 02 0080
+ 5 129 02 0081
+ 6 256 02 0100
+ 7 -127 01 81
+ 8 -128 01 80
+ 9 -129 02 FF7F
+ 10 32766 02 7FFE
+ 11 32767 02 7FFF
+ 12 32768 03 008000
+ 13 32769 03 008001
+ 14 -32767 02 8001
+ 15 -32768 02 8000
+ 16 -32769 03 FF7FFF
+ 17 65536 03 010000
+ 18 8388607 03 7FFFFF
+ 19 8388608 04 00800000
+ 20 8388609 04 00800001
+ 21 16777216 04 01000000
+ 22 -8388607 03 800001
+ 23 -8388608 03 800000
+ 24 -8388609 04 FF7FFFFF
+ 25 -65536 03 FF0000
+ 26 -2147483648 04 80000000
+ 27 2147483647 04 7FFFFFFF
+ 28 -549755813888 05 8000000000
+ 29 549755813887 05 7FFFFFFFFF
+ 30 -140737488355328 06 800000000000
+ 31 140737488355327 06 7FFFFFFFFFFF
+ 32 -36028797018963968 07 80000000000000
+ 33 36028797018963967 07 7FFFFFFFFFFFFF
+ 34 36028797018963968 08 0080000000000000
+ 35 -9223372036854775808 08 8000000000000000
+ 36 9223372036854775807 08 7FFFFFFFFFFFFFFF
+ 37 65537 03 010001
+ 38 -8323071 03 810001
+} {
+ test asn-12.$n {getInteger} {
+ set data [binary format H2H2H* 02 $len $hex]
+ asn::asnGetInteger data int
+ set int
+ } $i ; # {}
+}
+
+foreach {n i len hex} {
+ 0 0 01 00
+ 1 -1 01 FF
+ 2 1 01 01
+ 3 127 01 7F
+ 4 128 02 0080
+ 5 129 02 0081
+ 6 256 02 0100
+ 7 -127 01 81
+ 8 -128 01 80
+ 9 -129 02 FF7F
+ 10 32766 02 7FFE
+ 11 32767 02 7FFF
+ 12 32768 03 008000
+ 13 32769 03 008001
+ 14 -32767 02 8001
+ 15 -32768 02 8000
+ 16 -32769 03 FF7FFF
+ 17 65536 03 010000
+ 18 8388607 03 7FFFFF
+ 19 8388608 04 00800000
+ 20 8388609 04 00800001
+ 21 16777216 04 01000000
+ 22 -8388607 03 800001
+ 23 -8388608 03 800000
+ 24 -8388609 04 FF7FFFFF
+ 25 -65536 03 FF0000
+ 26 -2147483648 04 80000000
+ 27 2147483647 04 7FFFFFFF
+ 28 -549755813888 05 8000000000
+ 29 549755813887 05 7FFFFFFFFF
+ 30 -140737488355328 06 800000000000
+ 31 140737488355327 06 7FFFFFFFFFFF
+ 32 -36028797018963968 07 80000000000000
+ 33 36028797018963967 07 7FFFFFFFFFFFFF
+ 34 36028797018963968 08 0080000000000000
+ 35 -9223372036854775808 08 8000000000000000
+ 36 9223372036854775807 08 7FFFFFFFFFFFFFFF
+ 37 65537 03 010001
+ 38 -8323071 03 810001
+} {
+ test asn-12.[expr {$n+39}] {getBigInteger} {
+ set data [binary format H2H2H* 02 $len $hex]
+ asn::asnGetBigInteger data int
+ math::bignum::tostr $int
+ } $i ; # {}
+}
+
+test asn-13.0 {peekByte} {
+ set data \x0d\x0a
+ asn::asnPeekByte data byte
+ list $byte [string length $data]
+} {13 2}
+
+test asn-14.0 {getByte} {
+ set data \x0d\x0a
+ asn::asnGetByte data byte
+ list $byte [string length $data]
+} {13 1}
+
+test asn-15.0 {getBytes} {
+ set data \x0d\x0d\x0d\x0d\x0a
+ asn::asnGetBytes data 4 bytes
+ list [string length $data] [string length $bytes]
+} [list 1 4]
+
+test asn-15.1 {getBytes} {
+ set data \x0d\x0d\x0d\x0d\x0a
+ asn::asnGetBytes data 4 bytes
+ set expectedbytes \x0d\x0d\x0d\x0d
+ set expecteddata \x0a
+ list [expr {$data == $expecteddata}] [expr {$bytes == $expectedbytes}]
+} [list 1 1]
+
+# 16 ----------- string encoder/decoder invalid arguments
+array set stringtag {
+ NumericString 0x12
+ PrintableString 0x13
+ IA5String 0x16
+ BMPString 0x1e
+ UTF8String 0x0c
+}
+set i 0
+foreach strtype {NumericString PrintableString IA5String BMPString UTF8String} {
+ incr i
+ test asn-16.$i $strtype {
+ catch {asn::asn$strtype} result
+ set result
+ } [tcltest::wrongNumArgs asn::asn$strtype string 0]
+ incr i
+ test asn-16.$i $strtype {
+ catch "asn::asn$strtype a b" result
+ set result
+ } [tcltest::tooManyArgs "asn::asn$strtype" string]
+ incr i
+ test asn-16.$i get$strtype {
+ catch "asn::asnGet$strtype foo" result
+ set result
+ } [tcltest::wrongNumArgs "asn::asnGet$strtype" "data_var print_var" 0]
+ incr i
+ test asn-16.$i get$strtype {
+ catch "asn::asnGet$strtype foo bar baz" result
+ set result
+ } [tcltest::tooManyArgs "asn::asnGet$strtype" "data_var print_var"]
+ incr i
+ test asn-16.$i "get$strtype parse sequence" {
+ set data "\x30\x03abc"
+ catch "asn::asnGet$strtype data print" result
+ set result
+ } "Expected [regsub String $strtype " String"] ($stringtag($strtype)), but got 30"
+}
+incr i
+# 17 ------------------- invalid string values
+
+
+test asn-17.1 {numeric string with non-numbers} {
+ catch {asn::asnNumericString this-is-not-a-number} result
+ set result
+} "Illegal character in Numeric String."
+
+test asn-17.2 {numeric string with hexadecimals} {
+ catch {asn::asnNumericString 09AB} result
+ set result
+} "Illegal character in Numeric String."
+
+test asn-17.3 {numeric string with spaces - spaces are legal} {
+ catch {asn::asnNumericString " 093"}
+} 0 ;# TCL_OK
+
+test asn-17.4 {numeric string with minus sign} {
+ catch {asn::asnNumericString "-15"} result
+ set result
+} "Illegal character in Numeric String."
+
+test asn-17.5 {numeric string with tab (illegal)} {
+ catch {asn::asnNumericString "\t093"} result
+ set result
+} "Illegal character in Numeric String."
+
+#According to ITU-T X.680 37.4
+set printablechars {[-A-Za-z0-9 '()+,./=?:]}
+
+set i 6
+
+for {set j 1} {$j<128} {incr j;incr i} {
+ set data [format %c $j]
+ if {[regexp "^$printablechars+\$" $data]} {
+ test asn-17.$i "printable string valid char [format %02x $j]" {
+ catch {asn::asnPrintableString $data}
+ } 0 ; # {}
+ } else {
+ test asn-17.$i "printable string invalid char [format %02x $j]" {
+ catch {asn::asnPrintableString $data} result
+ set result
+ } "Illegal character in PrintableString." ; # {}
+ }
+}
+
+test asn-17.134 {IA5String with Latin-1 char} {
+ catch {asn::asnIA5String "\xD0"} result
+ set result
+} "Illegal character in IA5String"
+
+test asn-17.135 {IA5String with Cyrillic chars} {
+ catch {asn::asnIA5String "\u0420\u0443\u0441\u0441\u043a\u0438\u0439"} result
+ set result
+} "Illegal character in IA5String"
+
+# 18 - correct encoding of string values
+
+test asn-18.1 {encode numeric string} {
+ catch {asn::asnNumericString 123} result
+ set result
+} "\x12\003123"
+
+test asn-18.2 {encode numeric strin with space} {
+ catch {asn::asnNumericString "1 2 3"} result
+ set result
+} "\x12\0051 2 3"
+
+test asn-18.3 {encode printable string} {
+ catch {asn::asnPrintableString "printable string"} result
+ set result
+} "\x13\x10printable string"
+
+test asn-18.4 {encode IA5 string} {
+ catch {asn::asnIA5String "vitus@45.free.net"} result
+ set result
+} "\x16\x11vitus@45.free.net"
+
+test asn-18.5 {encode bmp string US-ASCII} {
+ catch {asn::asnBMPString "US-ASCII"} result
+ set result
+} "\x1e\x10\0U\0S\0-\0A\0S\0C\0I\0I"
+
+test asn-18.6 {encode UTF8 string US-ASCII} {
+ catch {asn::asnUTF8String "US-ASCII"} result
+ set result
+} "\x0c\x08US-ASCII"
+
+test asn-18.7 {encode bmp string latin-1} {
+ catch {asn::asnBMPString "gar\xC7on"} result
+ set result
+} "\x1e\x0c\0g\0a\0r\0\xc7\0o\0n"
+
+test asn-18.8 {encode utf-8 string latin-1} {
+ catch {asn::asnUTF8String "gar\xC7on"} result
+ set result
+} "\x0c\x07gar\xc3\x87on"
+
+test asn-18.9 {encode bmp string cyrillic} {
+ catch {asn::asnBMPString "\u0440\u0443\u0441\u0441\u043a\u0438\u0439"} result
+ set result
+} "\x1e\x0e\x04\x40\x04\x43\x04\x41\x04\x41\x04\x3a\x04\x38\x04\x39"
+
+test asn-18.10 {encode UTF8 string cyrillic} {
+ catch {asn::asnUTF8String "\u0440\u0443\u0441\u0441\u043a\u0438\u0439"} result
+ set result
+} "\x0c\x0e\xd1\x80\xd1\x83\xd1\x81\xd1\x81\xd0\xba\xd0\xb8\xd0\xb9"
+
+test asn-18.11 {decode numeric string} {
+ set data "\x12\003123"
+ asn::asnGetNumericString data print
+ set print
+} 123
+
+test asn-18.12 {decode printable string} {
+ set data "\x13\x10printable string"
+ asn::asnGetPrintableString data print
+ set print
+} "printable string"
+
+test asn-18.13 {decode IA5 string} {
+ set data "\x16\x11vitus@45.free.net"
+ asn::asnGetIA5String data print
+ set print
+} "vitus@45.free.net"
+
+test asn-18.14 {decode BMP string US-ASCII} {
+ set data "\x1e\x10\0U\0S\0-\0A\0S\0C\0I\0I"
+ asn::asnGetBMPString data print
+ set print
+} "US-ASCII"
+
+test asn-18.15 {decode UTF8 string US-ASCII} {
+ set data "\x0c\x08US-ASCII"
+ asn::asnGetUTF8String data print
+ set print
+} "US-ASCII"
+
+test asn-18.16 {decode BMP string latin-1} {
+ set data "\x1e\x0c\0g\0a\0r\0\xc7\0o\0n"
+ asn::asnGetBMPString data print
+ set print
+} "gar\xC7on"
+
+test asn-18.17 {decode UTF8 string latin-1} {
+ set data "\x0c\x07gar\xc3\x87on"
+ asn::asnGetUTF8String data print
+ set print
+} "gar\xC7on"
+
+test asn-18.18 {decode BMP string cyrillic} {
+ set data "\x1e\x0e\x04\x40\x04\x43\x04\x41\x04\x41\x04\x3a\x04\x38\x04\x39"
+ asn::asnGetBMPString data print
+ set print
+} "\u0440\u0443\u0441\u0441\u043a\u0438\u0439"
+
+test asn-18.19 {decode UTF8 string cyrillic} {
+ set data "\x0c\x0e\xd1\x80\xd1\x83\xd1\x81\xd1\x81\xd0\xba\xd0\xb8\xd0\xb9"
+ asn::asnGetUTF8String data print
+ set print
+} "\u0440\u0443\u0441\u0441\u043a\u0438\u0439"
+
+# 19 ------- multitype getString
+set i 0
+foreach {type encoded str} {
+
+NumericString "\x12\003123" 123
+PrintableString "\x13\x10printable string" "printable string"
+IA5String "\x16\x11vitus@45.free.net" "vitus@45.free.net"
+BMPString "\x1e\x10\0U\0S\0-\0A\0S\0C\0I\0I" US-ASCII
+UTF8String "\x0c\x08US-ASCII" US-ASCII
+BMPString "\x1e\x0c\0g\0a\0r\0\xc7\0o\0n" "gar\xc7on"
+UTF8String "\x0c\x07gar\xc3\x87on" "gar\xc7on"
+BMPString "\x1e\x0e\x04\x40\x04\x43\x04\x41\x04\x41\x04\x3a\x04\x38\x04\x39"
+"\u0440\u0443\u0441\u0441\u043a\u0438\u0439"
+UTF8String "\x0c\x0e\xd1\x80\xd1\x83\xd1\x81\xd1\x81\xd0\xba\xd0\xb8\xd0\xb9"
+"\u0440\u0443\u0441\u0441\u043a\u0438\u0439"} {
+incr i
+ test asn-19.$i "getString - decode $type" {
+ set data $encoded
+ asn::asnGetString data print
+ set print
+ } $str
+ incr i
+ test asn-19.$i "getString - decode $type and get its type" {
+ set data $encoded
+ asn::asnGetString data print gotType
+ list $data $print $gotType
+ } [list {} $str $type]
+}
+
+# 20 ----- multitype String encoding
+
+test asn-20.1 {Set default type to something wrong} {
+ catch {asn::defaultStringType foo} result
+ set result
+} "Invalid default string type. Should be one of BMP, UTF8"
+
+test asn-20.2 {Set default value to string type which cannot hold any char} {
+ catch {asn::defaultStringType IA5} result
+ set result
+} "Invalid default string type. Should be one of BMP, UTF8"
+
+
+test asn-20.3 {Set default type to UTF8} {
+ asn::defaultStringType UTF8
+} ""
+
+test asn-20.4 {Get default string type} {
+ asn::defaultStringType
+} UTF8
+
+test asn-20.5 {String - encode numeric value} {
+ asn::asnString 123
+} "\x12\003123"
+
+test asn-20.6 {String - encode printable value} {
+ asn::asnString "printable string"
+} "\x13\x10printable string"
+
+test asn-20.7 {String - encode ASCII value} {
+ asn::asnString vitus@45.free.net
+} "\x16\x11vitus@45.free.net"
+
+test asn-20.8 {String - encode Latin-1 value} {
+ asn::asnString "gar\xc7on"
+} "\x0c\x07gar\xc3\x87on"
+
+test asn-20.9 {String - encode Cyrillic value} {
+ asn::asnString "\u0440\u0443\u0441\u0441\u043a\u0438\u0439"
+} "\x0c\x0e\xd1\x80\xd1\x83\xd1\x81\xd1\x81\xd0\xba\xd0\xb8\xd0\xb9"
+
+test asn-20.10 {Set default string type to BMP} {
+ asn::defaultStringType BMP
+ asn::defaultStringType
+} BMP
+
+test asn-20.11 {String - encode numeric value} {
+ asn::asnString 123
+} "\x12\003123"
+
+test asn-20.12 {String - encode printable value} {
+ asn::asnString "printable string"
+} "\x13\x10printable string"
+
+test asn-20.13 {String - encode ASCII value} {
+ asn::asnString vitus@45.free.net
+} "\x16\x11vitus@45.free.net"
+
+
+test asn-20.14 {String - encode Latin-1 value} {
+ asn::asnString "gar\xc7on"
+} "\x1e\x0c\0g\0a\0r\0\xc7\0o\0n"
+
+test asn-20.15 {String - encode Cyrillic value} {
+ asn::asnString "\u0440\u0443\u0441\u0441\u043a\u0438\u0439"
+} "\x1e\x0e\x04\x40\x04\x43\x04\x41\x04\x41\x04\x3a\x04\x38\x04\x39"
+
+# 21 --------- Object identifier
+#
+
+test asn-21.1 {ObjectIdentifier start with 0} {
+ bytes2hex [asn::asnObjectIdentifier {0 2 262 1 10}]
+} "06 05 02 82 06 01 0A"
+
+
+test asn-21.2 {ObjectIdentifier start with 1} {
+ bytes2hex [asn::asnObjectIdentifier {1 2 840 10045 2 1}]
+} "06 07 2A 86 48 CE 3D 02 01"
+
+test asn-21.3 {ObjectIdentifer field > 65536} {
+ bytes2hex [asn::asnObjectIdentifier {1 2 840 113533 7 66 3}]
+} "06 09 2A 86 48 86 F6 7D 07 42 03"
+
+test asn-21.4 {ObjectIdentifer 2.23.42.9.37} {
+ bytes2hex [asn::asnObjectIdentifier {2 23 42 9 37}]
+} "06 04 67 2A 09 25"
+
+test asn-21.5 {GetObjectIdentifier 0.2.262.1.10} {
+ set data "\x06\x05\x02\x82\x06\x01\x0A"
+ asn::asnGetObjectIdentifier data print
+ set print
+} {0 2 262 1 10}
+
+test asn-21.6 {GetObjectIdentifier 1 2 840 10045 2 1} {
+ set data "\x06\x07\x2A\x86\x48\xCE\x3D\x02\x01"
+ asn::asnGetObjectIdentifier data print
+ set print
+} {1 2 840 10045 2 1}
+
+test asn-21.7 {GetObjectIdentifier 1 2 840 113533 7 66 3} {
+ set data "\x06\x09\x2A\x86\x48\x86\xF6\x7D\x07\x42\x03"
+ asn::asnGetObjectIdentifier data print
+ set print
+} {1 2 840 113533 7 66 3}
+
+# 22 --- Octet String
+
+# smoke tests to check that we can at least call the commands
+test asn-23.0 {asnContext smoke test} {
+ set data "\x00"
+ bytes2hex [asn::asnContext 1 $data]
+} {81 01 00}
+
+test asn-24.0 {asnSequence smoke test} {
+ set data [asn::asnNull]
+ bytes2hex [asn::asnSequence 1 $data]
+} {30 03 31 05 00}
+
+test asn-25.0 {asnSet smoke test} {
+ set data [asn::asnNull]
+ bytes2hex [asn::asnSet 1 $data]
+} {31 03 31 05 00}
+
+test asn-26.0 {asnApplicationConstr smoke test} {
+ set data [asn::asnNull]
+ bytes2hex [asn::asnApplicationConstr 1 $data]
+} {61 02 05 00}
+
+test asn-27.0 {asnApplication smoke test} {
+ set data [asn::asnNull]
+ bytes2hex [asn::asnApplication 1 $data]
+} {41 02 05 00}
+
+test asn-28.0 {asnContextConstr smoke test} {
+ set data [asn::asnNull]
+ bytes2hex [asn::asnContextConstr 1 $data]
+} {A1 02 05 00}
+
+test asn-29.0 {asnChoice smoke test} {
+ set data [asn::asnNull]
+ bytes2hex [asn::asnChoice 1 $data]
+} {81 02 05 00}
+
+test asn-30.0 {asnChoiceConstr smoke test} {
+ set data [asn::asnNull]
+ bytes2hex [asn::asnChoiceConstr 1 $data]
+} {A1 02 05 00}
+
+test asn-31.0 {asnPeekTag smoke test} {
+ set data [asn::asnNull]
+ asn::asnPeekTag data tag tagtype constr
+ list $tag $tagtype $constr
+} {5 UNIVERSAL 0}
+
+foreach {n hex tag type constr} {
+ 1 05 5 UNIVERSAL 0
+ 2 1E 30 UNIVERSAL 0
+ 3 1F1F 31 UNIVERSAL 0
+ 4 5F1F 31 APPLICATION 0
+ 5 1F818000 16384 UNIVERSAL 0
+ 6 45 5 APPLICATION 0
+ 7 65 5 APPLICATION 1
+ 8 85 5 CONTEXT 0
+ 9 a5 5 CONTEXT 1
+ 10 c5 5 PRIVATE 0
+ 11 e5 5 PRIVATE 1
+ 12 25 5 UNIVERSAL 1
+} {
+ test asn-31.$n "asnPeekTag $tag $type $constr" \
+ "set data \[binary format H* $hex\]
+ asn::asnPeekTag data tag tagtype constr
+ list \$tag \$tagtype \$constr" \
+ [list $tag $type $constr]
+}
+
+test asn-32.0 {asnTag smoke test} {
+ bytes2hex [asn::asnTag 5 UNIVERSAL P]
+} {05}
+
+test asn-32.1 {asnTag short tag} {
+ bytes2hex [asn::asnTag 30 UNIVERSAL P]
+} {1E}
+
+test asn-32.2 {asnTag long tag} {
+ bytes2hex [asn::asnTag 31 UNIVERSAL P]
+} {1F 1F}
+
+test asn-32.3 {asnTag long tag} {
+ bytes2hex [asn::asnTag 31 APPLICATION P]
+} {5F 1F}
+
+test asn-32.4 {asnTag long tag} {
+ bytes2hex [asn::asnTag 127 UNIVERSAL P]
+} {1F 7F}
+
+test asn-32.5 {asnTag long tag} {
+ bytes2hex [asn::asnTag 128 UNIVERSAL P]
+} {1F 81 00}
+
+test asn-32.6 {asnTag long tag} {
+ bytes2hex [asn::asnTag 16384 UNIVERSAL P]
+} {1F 81 80 00}
+
+test asn-32.7 {asnTag long tag} {
+ bytes2hex [asn::asnTag 16385 UNIVERSAL P]
+} {1F 81 80 01}
+
+test asn-32.8 {asnTag tag APPLICATION, PRIMITIVE} {
+ bytes2hex [asn::asnTag 5 APPLICATION P]
+} {45}
+
+test asn-32.9 {asnTag tag APPLICATION, CONSTRUCTED} {
+ bytes2hex [asn::asnTag 5 APPLICATION C]
+} {65}
+
+test asn-32.10 {asnTag tag CONTEXT, PRIMITIVE} {
+ bytes2hex [asn::asnTag 5 CONTEXT P]
+} {85}
+
+test asn-32.11 {asnTag tag CONTEXT, CONSTRUCTED} {
+ bytes2hex [asn::asnTag 5 CONTEXT C]
+} {A5}
+
+test asn-32.12 {asnTag tag PRIVATE,PRIMITIVE} {
+ bytes2hex [asn::asnTag 5 PRIVATE P]
+} {C5}
+
+test asn-32.13 {asnTag tag PRIVATE,CONSTRUCTED} {
+ bytes2hex [asn::asnTag 5 PRIVATE C]
+} {E5}
+
+test asn-32.14 {asnTag tag UNIVERSAL, CONSTRUCTED} {
+ bytes2hex [asn::asnTag 5 UNIVERSAL C]
+} {25}
+
+foreach {n hex bin} {
+ 1 03020780 1
+ 2 030206c0 11
+ 3 03020680 10
+ 4 030200ff 11111111
+ 5 03020000 00000000
+ 6 0303078000 100000000
+} {
+ test asn-33.$n "asnBitstring $bin" \
+ "binary scan \[asn::asnBitString $bin\] H* val
+ set val" \
+ $hex
+}
+
+foreach {n hex bin} {
+ 1 03020780 1
+ 2 030206c0 11
+ 3 03020680 10
+ 4 030200ff 11111111
+ 5 03020000 00000000
+ 6 0303078000 100000000
+} {
+ test asn-34.$n "asnGetBitstring $bin" \
+ "set data \[binary format H* $hex\]
+ asn::asnGetBitString data bits
+ set bits " \
+ $bin
+}
+
+
+testsuiteCleanup
+
diff --git a/tcllib/modules/asn/laymans_guide.txt b/tcllib/modules/asn/laymans_guide.txt
new file mode 100644
index 0000000..d4fbe64
--- /dev/null
+++ b/tcllib/modules/asn/laymans_guide.txt
@@ -0,0 +1,1855 @@
+A Layman's Guide to a Subset of ASN.1, BER, and DER
+
+An RSA Laboratories Technical Note
+Burton S. Kaliski Jr.
+Revised November 1, 1993
+
+
+Supersedes June 3, 1991 version, which was also published as
+NIST/OSI Implementors' Workshop document SEC-SIG-91-17.
+PKCS documents are available by electronic mail to
+<pkcs@rsa.com>.
+
+Copyright (C) 1991-1993 RSA Laboratories, a division of RSA
+Data Security, Inc. License to copy this document is granted
+provided that it is identified as "RSA Data Security, Inc.
+Public-Key Cryptography Standards (PKCS)" in all material
+mentioning or referencing this document.
+003-903015-110-000-000
+
+
+Abstract. This note gives a layman's introduction to a
+subset of OSI's Abstract Syntax Notation One (ASN.1), Basic
+Encoding Rules (BER), and Distinguished Encoding Rules
+(DER). The particular purpose of this note is to provide
+background material sufficient for understanding and
+implementing the PKCS family of standards.
+
+
+1. Introduction
+
+It is a generally accepted design principle that abstraction
+is a key to managing software development. With abstraction,
+a designer can specify a part of a system without concern
+for how the part is actually implemented or represented.
+Such a practice leaves the implementation open; it
+simplifies the specification; and it makes it possible to
+state "axioms" about the part that can be proved when the
+part is implemented, and assumed when the part is employed
+in another, higher-level part. Abstraction is the hallmark
+of most modern software specifications.
+
+One of the most complex systems today, and one that also
+involves a great deal of abstraction, is Open Systems
+Interconnection (OSI, described in X.200). OSI is an
+internationally standardized architecture that governs the
+interconnection of computers from the physical layer up to
+the user application layer. Objects at higher layers are
+defined abstractly and intended to be implemented with
+objects at lower layers. For instance, a service at one
+layer may require transfer of certain abstract objects
+between computers; a lower layer may provide transfer
+services for strings of ones and zeroes, using encoding
+rules to transform the abstract objects into such strings.
+OSI is called an open system because it supports many
+different implementations of the services at each layer.
+
+OSI's method of specifying abstract objects is called ASN.1
+(Abstract Syntax Notation One, defined in X.208), and one
+set of rules for representing such objects as strings of
+ones and zeros is called the BER (Basic Encoding Rules,
+defined in X.209). ASN.1 is a flexible notation that allows
+one to define a variety data types, from simple types such
+as integers and bit strings to structured types such as sets
+and sequences, as well as complex types defined in terms of
+others. BER describes how to represent or encode values of
+each ASN.1 type as a string of eight-bit octets. There is
+generally more than one way to BER-encode a given value.
+Another set of rules, called the Distinguished Encoding
+Rules (DER), which is a subset of BER, gives a unique
+encoding to each ASN.1 value.
+
+The purpose of this note is to describe a subset of ASN.1,
+BER and DER sufficient to understand and implement one OSI-
+based application, RSA Data Security, Inc.'s Public-Key
+Cryptography Standards. The features described include an
+overview of ASN.1, BER, and DER and an abridged list of
+ASN.1 types and their BER and DER encodings. Sections 2-4
+give an overview of ASN.1, BER, and DER, in that order.
+Section 5 lists some ASN.1 types, giving their notation,
+specific encoding rules, examples, and comments about their
+application to PKCS. Section 6 concludes with an example,
+X.500 distinguished names.
+
+Advanced features of ASN.1, such as macros, are not
+described in this note, as they are not needed to implement
+PKCS. For information on the other features, and for more
+detail generally, the reader is referred to CCITT
+Recommendations X.208 and X.209, which define ASN.1 and BER.
+
+Terminology and notation. In this note, an octet is an eight-
+bit unsigned integer. Bit 8 of the octet is the most
+significant and bit 1 is the least significant.
+
+The following meta-syntax is used for in describing ASN.1
+notation:
+
+ BIT monospace denotes literal characters in the type
+ and value notation; in examples, it generally
+ denotes an octet value in hexadecimal
+
+ n1 bold italics denotes a variable
+
+ [] bold square brackets indicate that a term is
+ optional
+
+ {} bold braces group related terms
+
+ | bold vertical bar delimits alternatives with a
+ group
+
+ ... bold ellipsis indicates repeated occurrences
+
+ = bold equals sign expresses terms as subterms
+
+
+2. Abstract Syntax Notation One
+
+Abstract Syntax Notation One, abbreviated ASN.1, is a
+notation for describing abstract types and values.
+
+In ASN.1, a type is a set of values. For some types, there
+are a finite number of values, and for other types there are
+an infinite number. A value of a given ASN.1 type is an
+element of the type's set. ASN.1 has four kinds of type:
+simple types, which are "atomic" and have no components;
+structured types, which have components; tagged types, which
+are derived from other types; and other types, which include
+the CHOICE type and the ANY type. Types and values can be
+given names with the ASN.1 assignment operator (::=) , and
+those names can be used in defining other types and values.
+
+Every ASN.1 type other than CHOICE and ANY has a tag, which
+consists of a class and a nonnegative tag number. ASN.1
+types are abstractly the same if and only if their tag
+numbers are the same. In other words, the name of an ASN.1
+type does not affect its abstract meaning, only the tag
+does. There are four classes of tag:
+
+ Universal, for types whose meaning is the same in all
+ applications; these types are only defined in
+ X.208.
+
+ Application, for types whose meaning is specific to an
+ application, such as X.500 directory services;
+ types in two different applications may have the
+ same application-specific tag and different
+ meanings.
+
+ Private, for types whose meaning is specific to a given
+ enterprise.
+
+ Context-specific, for types whose meaning is specific
+ to a given structured type; context-specific tags
+ are used to distinguish between component types
+ with the same underlying tag within the context of
+ a given structured type, and component types in
+ two different structured types may have the same
+ tag and different meanings.
+
+The types with universal tags are defined in X.208, which
+also gives the types' universal tag numbers. Types with
+other tags are defined in many places, and are always
+obtained by implicit or explicit tagging (see Section 2.3).
+Table 1 lists some ASN.1 types and their universal-class
+tags.
+
+ Type Tag number Tag number
+ (decimal) (hexadecimal)
+ INTEGER 2 02
+ BIT STRING 3 03
+ OCTET STRING 4 04
+ NULL 5 05
+ OBJECT IDENTIFIER 6 06
+ SEQUENCE and SEQUENCE OF 16 10
+ SET and SET OF 17 11
+ PrintableString 19 13
+ T61String 20 14
+ IA5String 22 16
+ UTCTime 23 17
+
+ Table 1. Some types and their universal-class tags.
+
+ASN.1 types and values are expressed in a flexible,
+programming-language-like notation, with the following
+special rules:
+
+ o Layout is not significant; multiple spaces and
+ line breaks can be considered as a single space.
+
+ o Comments are delimited by pairs of hyphens (--),
+ or a pair of hyphens and a line break.
+
+ o Identifiers (names of values and fields) and type
+ references (names of types) consist of upper- and
+ lower-case letters, digits, hyphens, and spaces;
+ identifiers begin with lower-case letters; type
+ references begin with upper-case letters.
+
+The following four subsections give an overview of simple
+types, structured types, implicitly and explicitly tagged
+types, and other types. Section 5 describes specific types
+in more detail.
+
+
+2.1 Simple types
+
+Simple types are those not consisting of components; they
+are the "atomic" types. ASN.1 defines several; the types
+that are relevant to the PKCS standards are the following:
+
+ BIT STRING, an arbitrary string of bits (ones and
+ zeroes).
+
+ IA5String, an arbitrary string of IA5 (ASCII)
+ characters.
+
+ INTEGER, an arbitrary integer.
+
+ NULL, a null value.
+
+ OBJECT IDENTIFIER, an object identifier, which is a
+ sequence of integer components that identify an
+ object such as an algorithm or attribute type.
+
+ OCTET STRING, an arbitrary string of octets (eight-bit
+ values).
+
+ PrintableString, an arbitrary string of printable
+ characters.
+
+ T61String, an arbitrary string of T.61 (eight-bit)
+ characters.
+
+ UTCTime, a "coordinated universal time" or Greenwich
+ Mean Time (GMT) value.
+
+Simple types fall into two categories: string types and non-
+string types. BIT STRING, IA5String, OCTET STRING,
+PrintableString, T61String, and UTCTime are string types.
+
+String types can be viewed, for the purposes of encoding, as
+consisting of components, where the components are
+substrings. This view allows one to encode a value whose
+length is not known in advance (e.g., an octet string value
+input from a file stream) with a constructed, indefinite-
+length encoding (see Section 3).
+
+The string types can be given size constraints limiting the
+length of values.
+
+
+2.2 Structured types
+
+Structured types are those consisting of components. ASN.1
+defines four, all of which are relevant to the PKCS
+standards:
+
+ SEQUENCE, an ordered collection of one or more types.
+
+ SEQUENCE OF, an ordered collection of zero or more
+ occurrences of a given type.
+
+ SET, an unordered collection of one or more types.
+
+ SET OF, an unordered collection of zero or more
+ occurrences of a given type.
+
+The structured types can have optional components, possibly
+with default values.
+
+
+2.3 Implicitly and explicitly tagged types
+
+Tagging is useful to distinguish types within an
+application; it is also commonly used to distinguish
+component types within a structured type. For instance,
+optional components of a SET or SEQUENCE type are typically
+given distinct context-specific tags to avoid ambiguity.
+
+There are two ways to tag a type: implicitly and explicitly.
+
+Implicitly tagged types are derived from other types by
+changing the tag of the underlying type. Implicit tagging is
+denoted by the ASN.1 keywords [class number] IMPLICIT (see
+Section 5.1).
+
+Explicitly tagged types are derived from other types by
+adding an outer tag to the underlying type. In effect,
+explicitly tagged types are structured types consisting of
+one component, the underlying type. Explicit tagging is
+denoted by the ASN.1 keywords [class number] EXPLICIT (see
+Section 5.2).
+
+The keyword [class number] alone is the same as explicit
+tagging, except when the "module" in which the ASN.1 type is
+defined has implicit tagging by default. ("Modules" are
+among the advanced features not described in this note.)
+
+For purposes of encoding, an implicitly tagged type is
+considered the same as the underlying type, except that the
+tag is different. An explicitly tagged type is considered
+like a structured type with one component, the underlying
+type. Implicit tags result in shorter encodings, but
+explicit tags may be necessary to avoid ambiguity if the tag
+of the underlying type is indeterminate (e.g., the
+underlying type is CHOICE or ANY).
+
+
+2.4 Other types
+
+Other types in ASN.1 include the CHOICE and ANY types. The
+CHOICE type denotes a union of one or more alternatives; the
+ANY type denotes an arbitrary value of an arbitrary type,
+where the arbitrary type is possibly defined in the
+registration of an object identifier or integer value.
+
+
+3. Basic Encoding Rules
+
+The Basic Encoding Rules for ASN.1, abbreviated BER, give
+one or more ways to represent any ASN.1 value as an octet
+string. (There are certainly other ways to represent ASN.1
+values, but BER is the standard for interchanging such
+values in OSI.)
+
+There are three methods to encode an ASN.1 value under BER,
+the choice of which depends on the type of value and whether
+the length of the value is known. The three methods are
+primitive, definite-length encoding; constructed, definite-
+length encoding; and constructed, indefinite-length
+encoding. Simple non-string types employ the primitive,
+definite-length method; structured types employ either of
+the constructed methods; and simple string types employ any
+of the methods, depending on whether the length of the value
+is known. Types derived by implicit tagging employ the
+method of the underlying type and types derived by explicit
+tagging employ the constructed methods.
+
+In each method, the BER encoding has three or four parts:
+
+ Identifier octets. These identify the class and tag
+ number of the ASN.1 value, and indicate whether
+ the method is primitive or constructed.
+
+ Length octets. For the definite-length methods, these
+ give the number of contents octets. For the
+ constructed, indefinite-length method, these
+ indicate that the length is indefinite.
+
+ Contents octets. For the primitive, definite-length
+ method, these give a concrete representation of
+ the value. For the constructed methods, these
+ give the concatenation of the BER encodings of the
+ components of the value.
+
+ End-of-contents octets. For the constructed, indefinite-
+ length method, these denote the end of the
+ contents. For the other methods, these are absent.
+
+The three methods of encoding are described in the following
+sections.
+
+
+3.1 Primitive, definite-length method
+
+This method applies to simple types and types derived from
+simple types by implicit tagging. It requires that the
+length of the value be known in advance. The parts of the
+BER encoding are as follows:
+
+Identifier octets. There are two forms: low tag number (for
+tag numbers between 0 and 30) and high tag number (for tag
+numbers 31 and greater).
+
+ Low-tag-number form. One octet. Bits 8 and 7 specify
+ the class (see Table 2), bit 6 has value "0,"
+ indicating that the encoding is primitive, and
+ bits 5-1 give the tag number.
+
+ Class Bit Bit
+ 8 7
+ universal 0 0
+ application 0 1
+ context-specific 1 0
+ private 1 1
+
+ Table 2. Class encoding in identifier octets.
+
+ High-tag-number form. Two or more octets. First octet
+ is as in low-tag-number form, except that bits 5-1
+ all have value "1." Second and following octets
+ give the tag number, base 128, most significant
+ digit first, with as few digits as possible, and
+ with the bit 8 of each octet except the last set
+ to "1."
+
+Length octets. There are two forms: short (for lengths
+between 0 and 127), and long definite (for lengths between 0
+and 21008-1).
+
+ Short form. One octet. Bit 8 has value "0" and bits 7-1
+ give the length.
+
+ Long form. Two to 127 octets. Bit 8 of first octet has
+ value "1" and bits 7-1 give the number of
+ additional length octets. Second and following
+ octets give the length, base 256, most significant
+ digit first.
+
+Contents octets. These give a concrete representation of the
+value (or the value of the underlying type, if the type is
+derived by implicit tagging). Details for particular types
+are given in Section 5.
+
+
+3.2 Constructed, definite-length method
+
+This method applies to simple string types, structured
+types, types derived simple string types and structured
+types by implicit tagging, and types derived from anything
+by explicit tagging. It requires that the length of the
+value be known in advance. The parts of the BER encoding are
+as follows:
+
+Identifier octets. As described in Section 3.1, except that
+bit 6 has value "1," indicating that the encoding is
+constructed.
+
+Length octets. As described in Section 3.1.
+
+Contents octets. The concatenation of the BER encodings of
+the components of the value:
+
+ o For simple string types and types derived from
+ them by implicit tagging, the concatenation of the
+ BER encodings of consecutive substrings of the
+ value (underlying value for implicit tagging).
+
+ o For structured types and types derived from them
+ by implicit tagging, the concatenation of the BER
+ encodings of components of the value (underlying
+ value for implicit tagging).
+
+ o For types derived from anything by explicit
+ tagging, the BER encoding of the underlying value.
+
+Details for particular types are given in Section 5.
+
+
+3.3 Constructed, indefinite-length method
+
+This method applies to simple string types, structured
+types, types derived simple string types and structured
+types by implicit tagging, and types derived from anything
+by explicit tagging. It does not require that the length of
+the value be known in advance. The parts of the BER encoding
+are as follows:
+
+Identifier octets. As described in Section 3.2.
+
+Length octets. One octet, 80.
+
+Contents octets. As described in Section 3.2.
+
+End-of-contents octets. Two octets, 00 00.
+
+Since the end-of-contents octets appear where an ordinary
+BER encoding might be expected (e.g., in the contents octets
+of a sequence value), the 00 and 00 appear as identifier and
+length octets, respectively. Thus the end-of-contents octets
+is really the primitive, definite-length encoding of a value
+with universal class, tag number 0, and length 0.
+
+
+4. Distinguished Encoding Rules
+
+The Distinguished Encoding Rules for ASN.1, abbreviated DER,
+are a subset of BER, and give exactly one way to represent
+any ASN.1 value as an octet string. DER is intended for
+applications in which a unique octet string encoding is
+needed, as is the case when a digital signature is computed
+on an ASN.1 value. DER is defined in Section 8.7 of X.509.
+
+DER adds the following restrictions to the rules given in
+Section 3:
+
+ 1. When the length is between 0 and 127, the short
+ form of length must be used
+
+ 2. When the length is 128 or greater, the long form
+ of length must be used, and the length must be
+ encoded in the minimum number of octets.
+
+ 3. For simple string types and implicitly tagged
+ types derived from simple string types, the
+ primitive, definite-length method must be
+ employed.
+
+ 4. For structured types, implicitly tagged types
+ derived from structured types, and explicitly
+ tagged types derived from anything, the
+ constructed, definite-length method must be
+ employed.
+
+Other restrictions are defined for particular types (such as
+BIT STRING, SEQUENCE, SET, and SET OF), and can be found in
+Section 5.
+
+
+5. Notation and encodings for some types
+
+This section gives the notation for some ASN.1 types and
+describes how to encode values of those types under both BER
+and DER.
+
+The types described are those presented in Section 2. They
+are listed alphabetically here.
+
+Each description includes ASN.1 notation, BER encoding, and
+DER encoding. The focus of the encodings is primarily on the
+contents octets; the tag and length octets follow Sections 3
+and 4. The descriptions also explain where each type is used
+in PKCS and related standards. ASN.1 notation is generally
+only for types, although for the type OBJECT IDENTIFIER,
+value notation is given as well.
+
+
+5.1 Implicitly tagged types
+
+An implicitly tagged type is a type derived from another
+type by changing the tag of the underlying type.
+
+Implicit tagging is used for optional SEQUENCE components
+with underlying type other than ANY throughout PKCS, and for
+the extendedCertificate alternative of PKCS #7's
+ExtendedCertificateOrCertificate type.
+
+ASN.1 notation:
+
+[[class] number] IMPLICIT Type
+
+class = UNIVERSAL | APPLICATION | PRIVATE
+
+where Type is a type, class is an optional class name, and
+number is the tag number within the class, a nonnegative
+integer.
+
+In ASN.1 "modules" whose default tagging method is implicit
+tagging, the notation [[class] number] Type is also
+acceptable, and the keyword IMPLICIT is implied. (See
+Section 2.3.) For definitions stated outside a module, the
+explicit inclusion of the keyword IMPLICIT is preferable to
+prevent ambiguity.
+
+If the class name is absent, then the tag is context-
+specific. Context-specific tags can only appear in a
+component of a structured or CHOICE type.
+
+Example: PKCS #8's PrivateKeyInfo type has an optional
+attributes component with an implicit, context-specific tag:
+
+PrivateKeyInfo ::= SEQUENCE {
+ version Version,
+ privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
+ privateKey PrivateKey,
+ attributes [0] IMPLICIT Attributes OPTIONAL }
+
+Here the underlying type is Attributes, the class is absent
+(i.e., context-specific), and the tag number within the
+class is 0.
+
+BER encoding. Primitive or constructed, depending on the
+underlying type. Contents octets are as for the BER encoding
+of the underlying value.
+
+Example: The BER encoding of the attributes component of a
+PrivateKeyInfo value is as follows:
+
+ o the identifier octets are 80 if the underlying
+ Attributes value has a primitive BER encoding and
+ a0 if the underlying Attributes value has a
+ constructed BER encoding
+
+ o the length and contents octets are the same as the
+ length and contents octets of the BER encoding of
+ the underlying Attributes value
+
+DER encoding. Primitive or constructed, depending on the
+underlying type. Contents octets are as for the DER encoding
+of the underlying value.
+
+
+5.2 Explicitly tagged types
+
+Explicit tagging denotes a type derived from another type by
+adding an outer tag to the underlying type.
+
+Explicit tagging is used for optional SEQUENCE components
+with underlying type ANY throughout PKCS, and for the
+version component of X.509's Certificate type.
+
+ASN.1 notation:
+
+[[class] number] EXPLICIT Type
+
+class = UNIVERSAL | APPLICATION | PRIVATE
+
+where Type is a type, class is an optional class name, and
+number is the tag number within the class, a nonnegative
+integer.
+
+If the class name is absent, then the tag is context-
+specific. Context-specific tags can only appear in a
+component of a SEQUENCE, SET or CHOICE type.
+
+In ASN.1 "modules" whose default tagging method is explicit
+tagging, the notation [[class] number] Type is also
+acceptable, and the keyword EXPLICIT is implied. (See
+Section 2.3.) For definitions stated outside a module, the
+explicit inclusion of the keyword EXPLICIT is preferable to
+prevent ambiguity.
+
+Example 1: PKCS #7's ContentInfo type has an optional
+content component with an explicit, context-specific tag:
+
+ContentInfo ::= SEQUENCE {
+ contentType ContentType,
+ content
+ [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
+
+Here the underlying type is ANY DEFINED BY contentType, the
+class is absent (i.e., context-specific), and the tag number
+within the class is 0.
+
+Example 2: X.509's Certificate type has a version component
+with an explicit, context-specific tag, where the EXPLICIT
+keyword is omitted:
+
+Certificate ::= ...
+ version [0] Version DEFAULT v1988,
+...
+
+The tag is explicit because the default tagging method for
+the ASN.1 "module" in X.509 that defines the Certificate
+type is explicit tagging.
+
+BER encoding. Constructed. Contents octets are the BER
+encoding of the underlying value.
+
+Example: the BER encoding of the content component of a
+ContentInfo value is as follows:
+
+ o identifier octets are a0
+
+ o length octets represent the length of the BER
+ encoding of the underlying ANY DEFINED BY
+ contentType value
+
+ o contents octets are the BER encoding of the
+ underlying ANY DEFINED BY contentType value
+
+DER encoding. Constructed. Contents octets are the DER
+encoding of the underlying value.
+
+
+5.3 ANY
+
+The ANY type denotes an arbitrary value of an arbitrary
+type, where the arbitrary type is possibly defined in the
+registration of an object identifier or associated with an
+integer index.
+
+The ANY type is used for content of a particular content
+type in PKCS #7's ContentInfo type, for parameters of a
+particular algorithm in X.509's AlgorithmIdentifier type,
+and for attribute values in X.501's Attribute and
+AttributeValueAssertion types. The Attribute type is used by
+PKCS #6, #7, #8, #9 and #10, and the AttributeValueAssertion
+type is used in X.501 distinguished names.
+
+ASN.1 notation:
+
+ANY [DEFINED BY identifier]
+
+where identifier is an optional identifier.
+
+In the ANY form, the actual type is indeterminate.
+
+The ANY DEFINED BY identifier form can only appear in a
+component of a SEQUENCE or SET type for which identifier
+identifies some other component, and that other component
+has type INTEGER or OBJECT IDENTIFIER (or a type derived
+from either of those by tagging). In that form, the actual
+type is determined by the value of the other component,
+either in the registration of the object identifier value,
+or in a table of integer values.
+
+Example: X.509's AlgorithmIdentifier type has a component of
+type ANY:
+
+AlgorithmIdentifier ::= SEQUENCE {
+ algorithm OBJECT IDENTIFIER,
+ parameters ANY DEFINED BY algorithm OPTIONAL }
+
+Here the actual type of the parameter component depends on
+the value of the algorithm component. The actual type would
+be defined in the registration of object identifier values
+for the algorithm component.
+
+BER encoding. Same as the BER encoding of the actual value.
+
+Example: The BER encoding of the value of the parameter
+component is the BER encoding of the value of the actual
+type as defined in the registration of object identifier
+values for the algorithm component.
+
+DER encoding. Same as the DER encoding of the actual value.
+
+
+5.4 BIT STRING
+
+The BIT STRING type denotes an arbitrary string of bits
+(ones and zeroes). A BIT STRING value can have any length,
+including zero. This type is a string type.
+
+The BIT STRING type is used for digital signatures on
+extended certificates in PKCS #6's ExtendedCertificate type,
+for digital signatures on certificates in X.509's
+Certificate type, and for public keys in certificates in
+X.509's SubjectPublicKeyInfo type.
+
+ASN.1 notation:
+
+BIT STRING
+
+Example: X.509's SubjectPublicKeyInfo type has a component
+of type BIT STRING:
+
+SubjectPublicKeyInfo ::= SEQUENCE {
+ algorithm AlgorithmIdentifier,
+ publicKey BIT STRING }
+
+BER encoding. Primitive or constructed. In a primitive
+encoding, the first contents octet gives the number of bits
+by which the length of the bit string is less than the next
+multiple of eight (this is called the "number of unused
+bits"). The second and following contents octets give the
+value of the bit string, converted to an octet string. The
+conversion process is as follows:
+
+ 1. The bit string is padded after the last bit with
+ zero to seven bits of any value to make the length
+ of the bit string a multiple of eight. If the
+ length of the bit string is a multiple of eight
+ already, no padding is done.
+
+ 2. The padded bit string is divided into octets. The
+ first eight bits of the padded bit string become
+ the first octet, bit 8 to bit 1, and so on through
+ the last eight bits of the padded bit string.
+
+In a constructed encoding, the contents octets give the
+concatenation of the BER encodings of consecutive substrings
+of the bit string, where each substring except the last has
+a length that is a multiple of eight bits.
+
+Example: The BER encoding of the BIT STRING value
+"011011100101110111" can be any of the following, among
+others, depending on the choice of padding bits, the form of
+length octets, and whether the encoding is primitive or
+constructed:
+
+03 04 06 6e 5d c0 DER encoding
+
+03 04 06 6e 5d e0 padded with "100000"
+
+03 81 04 06 6e 5d c0 long form of length octets
+
+23 09 constructed encoding: "0110111001011101" + "11"
+ 03 03 00 6e 5d
+ 03 02 06 c0
+
+DER encoding. Primitive. The contents octects are as for a
+primitive BER encoding, except that the bit string is padded
+with zero-valued bits.
+
+Example: The DER encoding of the BIT STRING value
+"011011100101110111" is
+
+03 04 06 6e 5d c0
+
+
+5.5 CHOICE
+
+The CHOICE type denotes a union of one or more alternatives.
+
+The CHOICE type is used to represent the union of an
+extended certificate and an X.509 certificate in PKCS #7's
+ExtendedCertificateOrCertificate type.
+
+ASN.1 notation:
+
+CHOICE {
+ [identifier1] Type1,
+ ...,
+ [identifiern] Typen }
+
+where identifier1 , ..., identifiern are optional, distinct
+identifiers for the alternatives, and Type1, ..., Typen are
+the types of the alternatives. The identifiers are primarily
+for documentation; they do not affect values of the type or
+their encodings in any way.
+
+The types must have distinct tags. This requirement is
+typically satisfied with explicit or implicit tagging on
+some of the alternatives.
+
+Example: PKCS #7's ExtendedCertificateOrCertificate type is
+a CHOICE type:
+
+ExtendedCertificateOrCertificate ::= CHOICE {
+ certificate Certificate, -- X.509
+ extendedCertificate [0] IMPLICIT ExtendedCertificate
+}
+
+Here the identifiers for the alternatives are certificate
+and extendedCertificate, and the types of the alternatives
+are Certificate and [0] IMPLICIT ExtendedCertificate.
+
+BER encoding. Same as the BER encoding of the chosen
+alternative. The fact that the alternatives have distinct
+tags makes it possible to distinguish between their BER
+encodings.
+
+Example: The identifier octets for the BER encoding are 30
+if the chosen alternative is certificate, and a0 if the
+chosen alternative is extendedCertificate.
+
+DER encoding. Same as the DER encoding of the chosen
+alternative.
+
+
+5.6 IA5String
+
+The IA5String type denotes an arbtrary string of IA5
+characters. IA5 stands for International Alphabet 5, which
+is the same as ASCII. The character set includes non-
+printing control characters. An IA5String value can have any
+length, including zero. This type is a string type.
+
+The IA5String type is used in PKCS #9's electronic-mail
+address, unstructured-name, and unstructured-address
+attributes.
+
+ASN.1 notation:
+
+IA5String
+
+BER encoding. Primitive or constructed. In a primitive
+encoding, the contents octets give the characters in the IA5
+string, encoded in ASCII. In a constructed encoding, the
+contents octets give the concatenation of the BER encodings
+of consecutive substrings of the IA5 string.
+
+Example: The BER encoding of the IA5String value
+"test1@rsa.com" can be any of the following, among others,
+depending on the form of length octets and whether the
+encoding is primitive or constructed:
+
+16 0d 74 65 73 74 31 40 72 73 61 2e 63 6f 6d DER encoding
+
+16 81 0d long form of length octets
+ 74 65 73 74 31 40 72 73 61 2e 63 6f 6d
+
+36 13 constructed encoding: "test1" + "@" + "rsa.com"
+ 16 05 74 65 73 74 31
+ 16 01 40
+ 16 07 72 73 61 2e 63 6f 6d
+
+DER encoding. Primitive. Contents octets are as for a
+primitive BER encoding.
+
+Example: The DER encoding of the IA5String value
+"test1@rsa.com" is
+
+16 0d 74 65 73 74 31 40 72 73 61 2e 63 6f 6d
+
+
+5.7 INTEGER
+
+The INTEGER type denotes an arbitrary integer. INTEGER
+values can be positive, negative, or zero, and can have any
+magnitude.
+
+The INTEGER type is used for version numbers throughout
+PKCS, cryptographic values such as modulus, exponent, and
+primes in PKCS #1's RSAPublicKey and RSAPrivateKey types and
+PKCS #3's DHParameter type, a message-digest iteration count
+in PKCS #5's PBEParameter type, and version numbers and
+serial numbers in X.509's Certificate type.
+
+ASN.1 notation:
+
+INTEGER [{ identifier1(value1) ... identifiern(valuen) }]
+
+where identifier1, ..., identifiern are optional distinct
+identifiers and value1, ..., valuen are optional integer
+values. The identifiers, when present, are associated with
+values of the type.
+
+Example: X.509's Version type is an INTEGER type with
+identified values:
+
+Version ::= INTEGER { v1988(0) }
+
+The identifier v1988 is associated with the value 0. X.509's
+Certificate type uses the identifier v1988 to give a default
+value of 0 for the version component:
+
+Certificate ::= ...
+ version Version DEFAULT v1988,
+...
+
+BER encoding. Primitive. Contents octets give the value of
+the integer, base 256, in two's complement form, most
+significant digit first, with the minimum number of octets.
+The value 0 is encoded as a single 00 octet.
+
+Some example BER encodings (which also happen to be DER
+encodings) are given in Table 3.
+
+ Integer BER encoding
+ value
+ 0 02 01 00
+ 127 02 01 7F
+ 128 02 02 00 80
+ 256 02 02 01 00
+ -128 02 01 80
+ -129 02 02 FF 7F
+
+ Table 3. Example BER encodings of INTEGER values.
+
+DER encoding. Primitive. Contents octets are as for a
+primitive BER encoding.
+
+
+5.8 NULL
+
+The NULL type denotes a null value.
+
+The NULL type is used for algorithm parameters in several
+places in PKCS.
+
+ASN.1 notation:
+
+NULL
+
+BER encoding. Primitive. Contents octets are empty.
+
+Example: The BER encoding of a NULL value can be either of
+the following, as well as others, depending on the form of
+the length octets:
+
+05 00
+
+05 81 00
+
+DER encoding. Primitive. Contents octets are empty; the DER
+encoding of a NULL value is always 05 00.
+
+
+5.9 OBJECT IDENTIFIER
+
+The OBJECT IDENTIFIER type denotes an object identifier, a
+sequence of integer components that identifies an object
+such as an algorithm, an attribute type, or perhaps a
+registration authority that defines other object
+identifiers. An OBJECT IDENTIFIER value can have any number
+of components, and components can generally have any
+nonnegative value. This type is a non-string type.
+
+OBJECT IDENTIFIER values are given meanings by registration
+authorities. Each registration authority is responsible for
+all sequences of components beginning with a given sequence.
+A registration authority typically delegates responsibility
+for subsets of the sequences in its domain to other
+registration authorities, or for particular types of object.
+There are always at least two components.
+
+The OBJECT IDENTIFIER type is used to identify content in
+PKCS #7's ContentInfo type, to identify algorithms in
+X.509's AlgorithmIdentifier type, and to identify attributes
+in X.501's Attribute and AttributeValueAssertion types. The
+Attribute type is used by PKCS #6, #7, #8, #9, and #10, and
+the AttributeValueAssertion type is used in X.501
+distinguished names. OBJECT IDENTIFIER values are defined
+throughout PKCS.
+
+ASN.1 notation:
+
+OBJECT IDENTIFIER
+
+The ASN.1 notation for values of the OBJECT IDENTIFIER type
+is
+
+{ [identifier] component1 ... componentn }
+
+componenti = identifieri | identifieri (valuei) | valuei
+
+where identifier, identifier1, ..., identifiern are
+identifiers, and value1, ..., valuen are optional integer
+values.
+
+The form without identifier is the "complete" value with all
+its components; the form with identifier abbreviates the
+beginning components with another object identifier value.
+The identifiers identifier1, ..., identifiern are intended
+primarily for documentation, but they must correspond to the
+integer value when both are present. These identifiers can
+appear without integer values only if they are among a small
+set of identifiers defined in X.208.
+
+Example: The following values both refer to the object
+identifier assigned to RSA Data Security, Inc.:
+
+{ iso(1) member-body(2) 840 113549 }
+{ 1 2 840 113549 }
+
+(In this example, which gives ASN.1 value notation, the
+object identifier values are decimal, not hexadecimal.)
+Table 4 gives some other object identifier values and their
+meanings.
+
+ Object identifier value Meaning
+ { 1 2 } ISO member bodies
+ { 1 2 840 } US (ANSI)
+ { 1 2 840 113549 } RSA Data Security, Inc.
+ { 1 2 840 113549 1 } RSA Data Security, Inc. PKCS
+ { 2 5 } directory services (X.500)
+ { 2 5 8 } directory services-algorithms
+
+ Table 4. Some object identifier values and their meanings.
+
+BER encoding. Primitive. Contents octets are as follows,
+where value1, ..., valuen denote the integer values of the
+components in the complete object identifier:
+
+ 1. The first octet has value 40 * value1 + value2.
+ (This is unambiguous, since value1 is limited to
+ values 0, 1, and 2; value2 is limited to the range
+ 0 to 39 when value1 is 0 or 1; and, according to
+ X.208, n is always at least 2.)
+
+ 2. The following octets, if any, encode value3, ...,
+ valuen. Each value is encoded base 128, most
+ significant digit first, with as few digits as
+ possible, and the most significant bit of each
+ octet except the last in the value's encoding set
+ to "1."
+
+Example: The first octet of the BER encoding of RSA Data
+Security, Inc.'s object identifier is 40 * 1 + 2 = 42 =
+2a16. The encoding of 840 = 6 * 128 + 4816 is 86 48 and the
+encoding of 113549 = 6 * 1282 + 7716 * 128 + d16 is 86 f7
+0d. This leads to the following BER encoding:
+
+06 06 2a 86 48 86 f7 0d
+
+DER encoding. Primitive. Contents octets are as for a
+primitive BER encoding.
+
+
+5.10 OCTET STRING
+
+The OCTET STRING type denotes an arbitrary string of octets
+(eight-bit values). An OCTET STRING value can have any
+length, including zero. This type is a string type.
+
+The OCTET STRING type is used for salt values in PKCS #5's
+PBEParameter type, for message digests, encrypted message
+digests, and encrypted content in PKCS #7, and for private
+keys and encrypted private keys in PKCS #8.
+
+ASN.1 notation:
+
+OCTET STRING [SIZE ({size | size1..size2})]
+
+where size, size1, and size2 are optional size constraints.
+In the OCTET STRING SIZE (size) form, the octet string must
+have size octets. In the OCTET STRING SIZE (size1..size2)
+form, the octet string must have between size1 and size2
+octets. In the OCTET STRING form, the octet string can have
+any size.
+
+Example: PKCS #5's PBEParameter type has a component of type
+OCTET STRING:
+
+PBEParameter ::= SEQUENCE {
+ salt OCTET STRING SIZE(8),
+ iterationCount INTEGER }
+
+Here the size of the salt component is always eight octets.
+
+BER encoding. Primitive or constructed. In a primitive
+encoding, the contents octets give the value of the octet
+string, first octet to last octet. In a constructed
+encoding, the contents octets give the concatenation of the
+BER encodings of substrings of the OCTET STRING value.
+
+Example: The BER encoding of the OCTET STRING value 01 23 45
+67 89 ab cd ef can be any of the following, among others,
+depending on the form of length octets and whether the
+encoding is primitive or constructed:
+
+04 08 01 23 45 67 89 ab cd ef DER encoding
+
+04 81 08 01 23 45 67 89 ab cd ef long form of length octets
+
+24 0c constructed encoding: 01 ... 67 + 89 ... ef
+ 04 04 01 23 45 67
+ 04 04 89 ab cd ef
+
+DER encoding. Primitive. Contents octets are as for a
+primitive BER encoding.
+
+Example: The BER encoding of the OCTET STRING value 01 23 45
+67 89 ab cd ef is
+
+04 08 01 23 45 67 89 ab cd ef
+
+
+5.11 PrintableString
+
+The PrintableString type denotes an arbitrary string of
+printable characters from the following character set:
+
+ A, B, ..., Z
+ a, b, ..., z
+ 0, 1, ..., 9
+ (space) ' ( ) + , - . / : = ?
+
+This type is a string type.
+
+The PrintableString type is used in PKCS #9's challenge-
+password and unstructuerd-address attributes, and in several
+X.521 distinguished names attributes.
+
+ASN.1 notation:
+
+PrintableString
+
+BER encoding. Primitive or constructed. In a primitive
+encoding, the contents octets give the characters in the
+printable string, encoded in ASCII. In a constructed
+encoding, the contents octets give the concatenation of the
+BER encodings of consecutive substrings of the string.
+
+Example: The BER encoding of the PrintableString value "Test
+User 1" can be any of the following, among others, depending
+on the form of length octets and whether the encoding is
+primitive or constructed:
+
+13 0b 54 65 73 74 20 55 73 65 72 20 31 DER encoding
+
+13 81 0b long form of length octets
+ 54 65 73 74 20 55 73 65 72 20 31
+
+33 0f constructed encoding: "Test " + "User 1"
+ 13 05 54 65 73 74 20
+ 13 06 55 73 65 72 20 31
+
+DER encoding. Primitive. Contents octets are as for a
+primitive BER encoding.
+
+Example: The DER encoding of the PrintableString value "Test
+User 1" is
+
+13 0b 54 65 73 74 20 55 73 65 72 20 31
+
+
+5.12 SEQUENCE
+
+The SEQUENCE type denotes an ordered collection of one or
+more types.
+
+The SEQUENCE type is used throughout PKCS and related
+standards.
+
+ASN.1 notation:
+
+SEQUENCE {
+ [identifier1] Type1 [{OPTIONAL | DEFAULT value1}],
+ ...,
+ [identifiern] Typen [{OPTIONAL | DEFAULT valuen}]}
+
+where identifier1 , ..., identifiern are optional, distinct
+identifiers for the components, Type1, ..., Typen are the
+types of the components, and value1, ..., valuen are optional
+default values for the components. The identifiers are
+primarily for documentation; they do not affect values of
+the type or their encodings in any way.
+
+The OPTIONAL qualifier indicates that the value of a
+component is optional and need not be present in the
+sequence. The DEFAULT qualifier also indicates that the
+value of a component is optional, and assigns a default
+value to the component when the component is absent.
+
+The types of any consecutive series of components with the
+OPTIONAL or DEFAULT qualifier, as well as of any component
+immediately following that series, must have distinct tags.
+This requirement is typically satisfied with explicit or
+implicit tagging on some of the components.
+
+Example: X.509's Validity type is a SEQUENCE type with two
+components:
+
+Validity ::= SEQUENCE {
+ start UTCTime,
+ end UTCTime }
+
+Here the identifiers for the components are start and end,
+and the types of the components are both UTCTime.
+
+BER encoding. Constructed. Contents octets are the
+concatenation of the BER encodings of the values of the
+components of the sequence, in order of definition, with the
+following rules for components with the OPTIONAL and DEFAULT
+qualifiers:
+
+ o if the value of a component with the OPTIONAL or
+ DEFAULT qualifier is absent from the sequence,
+ then the encoding of that component is not
+ included in the contents octets
+
+ o if the value of a component with the DEFAULT
+ qualifier is the default value, then the encoding
+ of that component may or may not be included in
+ the contents octets
+
+DER encoding. Constructed. Contents octets are the same as
+the BER encoding, except that if the value of a component
+with the DEFAULT qualifier is the default value, the
+encoding of that component is not included in the contents
+octets.
+
+
+5.13 SEQUENCE OF
+
+The SEQUENCE OF type denotes an ordered collection of zero
+or more occurrences of a given type.
+
+The SEQUENCE OF type is used in X.501 distinguished names.
+
+ASN.1 notation:
+
+SEQUENCE OF Type
+
+where Type is a type.
+
+Example: X.501's RDNSequence type consists of zero or more
+occurences of the RelativeDistinguishedName type, most
+significant occurrence first:
+
+RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+
+BER encoding. Constructed. Contents octets are the
+concatenation of the BER encodings of the values of the
+occurrences in the collection, in order of occurence.
+
+DER encoding. Constructed. Contents octets are the
+concatenation of the DER encodings of the values of the
+occurrences in the collection, in order of occurence.
+
+
+5.14 SET
+
+The SET type denotes an unordered collection of one or more
+types.
+
+The SET type is not used in PKCS.
+
+ASN.1 notation:
+
+SET {
+ [identifier1] Type1 [{OPTIONAL | DEFAULT value1}],
+ ...,
+ [identifiern] Typen [{OPTIONAL | DEFAULT valuen}]}
+
+where identifier1, ..., identifiern are optional, distinct
+identifiers for the components, Type1, ..., Typen are the
+types of the components, and value1, ..., valuen are
+optional default values for the components. The identifiers
+are primarily for documentation; they do not affect values
+of the type or their encodings in any way.
+
+The OPTIONAL qualifier indicates that the value of a
+component is optional and need not be present in the set.
+The DEFAULT qualifier also indicates that the value of a
+component is optional, and assigns a default value to the
+component when the component is absent.
+
+The types must have distinct tags. This requirement is
+typically satisfied with explicit or implicit tagging on
+some of the components.
+
+BER encoding. Constructed. Contents octets are the
+concatenation of the BER encodings of the values of the
+components of the set, in any order, with the following
+rules for components with the OPTIONAL and DEFAULT
+qualifiers:
+
+ o if the value of a component with the OPTIONAL or
+ DEFAULT qualifier is absent from the set, then the
+ encoding of that component is not included in the
+ contents octets
+
+ o if the value of a component with the DEFAULT
+ qualifier is the default value, then the encoding
+ of that component may or may not be included in
+ the contents octets
+
+DER encoding. Constructed. Contents octets are the same as
+for the BER encoding, except that:
+
+ 1. If the value of a component with the DEFAULT
+ qualifier is the default value, the encoding of
+ that component is not included.
+
+ 2. There is an order to the components, namely
+ ascending order by tag.
+
+
+5.15 SET OF
+
+The SET OF type denotes an unordered collection of zero or
+more occurrences of a given type.
+
+The SET OF type is used for sets of attributes in PKCS #6,
+#7, #8, #9 and #10, for sets of message-digest algorithm
+identifiers, signer information, and recipient information
+in PKCS #7, and in X.501 distinguished names.
+
+ASN.1 notation:
+
+SET OF Type
+
+where Type is a type.
+
+Example: X.501's RelativeDistinguishedName type consists of
+zero or more occurrences of the AttributeValueAssertion
+type, where the order is unimportant:
+
+RelativeDistinguishedName ::=
+ SET OF AttributeValueAssertion
+
+BER encoding. Constructed. Contents octets are the
+concatenation of the BER encodings of the values of the
+occurrences in the collection, in any order.
+
+DER encoding. Constructed. Contents octets are the same as
+for the BER encoding, except that there is an order, namely
+ascending lexicographic order of BER encoding. Lexicographic
+comparison of two different BER encodings is done as
+follows: Logically pad the shorter BER encoding after the
+last octet with dummy octets that are smaller in value than
+any normal octet. Scan the BER encodings from left to right
+until a difference is found. The smaller-valued BER encoding
+is the one with the smaller-valued octet at the point of
+difference.
+
+
+5.16 T61String
+
+The T61String type denotes an arbtrary string of T.61
+characters. T.61 is an eight-bit extension to the ASCII
+character set. Special "escape" sequences specify the
+interpretation of subsequent character values as, for
+example, Japanese; the initial interpretation is Latin. The
+character set includes non-printing control characters. The
+T61String type allows only the Latin and Japanese character
+interepretations, and implementors' agreements for directory
+names exclude control characters [NIST92]. A T61String value
+can have any length, including zero. This type is a string
+type.
+
+The T61String type is used in PKCS #9's unstructured-address
+and challenge-password attributes, and in several X.521
+attributes.
+
+ASN.1 notation:
+
+T61String
+
+BER encoding. Primitive or constructed. In a primitive
+encoding, the contents octets give the characters in the
+T.61 string, encoded in ASCII. In a constructed encoding,
+the contents octets give the concatenation of the BER
+encodings of consecutive substrings of the T.61 string.
+
+Example: The BER encoding of the T61String value "cl'es
+publiques" (French for "public keys") can be any of the
+following, among others, depending on the form of length
+octets and whether the encoding is primitive or constructed:
+
+14 0f DER encoding
+ 63 6c c2 65 73 20 70 75 62 6c 69 71 75 65 73
+
+14 81 0f long form of length octets
+ 63 6c c2 65 73 20 70 75 62 6c 69 71 75 65 73
+
+34 15 constructed encoding: "cl'es" + " " + "publiques"
+ 14 05 63 6c c2 65 73
+ 14 01 20
+ 14 09 70 75 62 6c 69 71 75 65 73
+
+The eight-bit character c2 is a T.61 prefix that adds an
+acute accent (') to the next character.
+
+DER encoding. Primitive. Contents octets are as for a
+primitive BER encoding.
+
+Example: The DER encoding of the T61String value "cl'es
+publiques" is
+
+14 0f 63 6c c2 65 73 20 70 75 62 6c 69 71 75 65 73
+
+
+5.17 UTCTime
+
+The UTCTime type denotes a "coordinated universal time" or
+Greenwich Mean Time (GMT) value. A UTCTime value includes
+the local time precise to either minutes or seconds, and an
+offset from GMT in hours and minutes. It takes any of the
+following forms:
+
+YYMMDDhhmmZ
+YYMMDDhhmm+hh'mm'
+YYMMDDhhmm-hh'mm'
+YYMMDDhhmmssZ
+YYMMDDhhmmss+hh'mm'
+YYMMDDhhmmss-hh'mm'
+
+where:
+
+ YY is the least significant two digits of the year
+
+ MM is the month (01 to 12)
+
+ DD is the day (01 to 31)
+
+ hh is the hour (00 to 23)
+
+ mm are the minutes (00 to 59)
+
+ ss are the seconds (00 to 59)
+
+ Z indicates that local time is GMT, + indicates that
+ local time is later than GMT, and - indicates that
+ local time is earlier than GMT
+
+ hh' is the absolute value of the offset from GMT in
+ hours
+
+ mm' is the absolute value of the offset from GMT in
+ minutes
+
+This type is a string type.
+
+The UTCTime type is used for signing times in PKCS #9's
+signing-time attribute and for certificate validity periods
+in X.509's Validity type.
+
+ASN.1 notation:
+
+UTCTime
+
+BER encoding. Primitive or constructed. In a primitive
+encoding, the contents octets give the characters in the
+string, encoded in ASCII. In a constructed encoding, the
+contents octets give the concatenation of the BER encodings
+of consecutive substrings of the string. (The constructed
+encoding is not particularly interesting, since UTCTime
+values are so short, but the constructed encoding is
+permitted.)
+
+Example: The time this sentence was originally written was
+4:45:40 p.m. Pacific Daylight Time on May 6, 1991, which can
+be represented with either of the following UTCTime values,
+among others:
+
+"910506164540-0700"
+
+"910506234540Z"
+
+These values have the following BER encodings, among others:
+
+17 0d 39 31 30 35 30 36 32 33 34 35 34 30 5a
+
+17 11 39 31 30 35 30 36 31 36 34 35 34 30 2D 30 37 30
+ 30
+
+DER encoding. Primitive. Contents octets are as for a
+primitive BER encoding.
+
+
+6. An example
+
+This section gives an example of ASN.1 notation and DER
+encoding: the X.501 type Name.
+
+
+6.1 Abstract notation
+
+This section gives the ASN.1 notation for the X.501 type
+Name.
+
+Name ::= CHOICE {
+ RDNSequence }
+
+RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+
+RelativeDistinguishedName ::=
+ SET OF AttributeValueAssertion
+
+AttributeValueAssertion ::= SEQUENCE {
+ AttributeType,
+ AttributeValue }
+
+AttributeType ::= OBJECT IDENTIFIER
+
+AttributeValue ::= ANY
+
+The Name type identifies an object in an X.500 directory.
+Name is a CHOICE type consisting of one alternative:
+RDNSequence. (Future revisions of X.500 may have other
+alternatives.)
+
+The RDNSequence type gives a path through an X.500 directory
+tree starting at the root. RDNSequence is a SEQUENCE OF type
+consisting of zero or more occurences of
+RelativeDistinguishedName.
+
+The RelativeDistinguishedName type gives a unique name to an
+object relative to the object superior to it in the
+directory tree. RelativeDistinguishedName is a SET OF type
+consisting of zero or more occurrences of
+AttributeValueAssertion.
+
+The AttributeValueAssertion type assigns a value to some
+attribute of a relative distinguished name, such as country
+name or common name. AttributeValueAssertion is a SEQUENCE
+type consisting of two components, an AttributeType type and
+an AttributeValue type.
+
+The AttributeType type identifies an attribute by object
+identifier. The AttributeValue type gives an arbitrary
+attribute value. The actual type of the attribute value is
+determined by the attribute type.
+
+
+6.2 DER encoding
+
+This section gives an example of a DER encoding of a value
+of type Name, working from the bottom up.
+
+The name is that of the Test User 1 from the PKCS examples
+[Kal93]. The name is represented by the following path:
+
+ (root)
+ |
+ countryName = "US"
+ |
+ organizationName = "Example Organization"
+ |
+ commonName = "Test User 1"
+
+Each level corresponds to one RelativeDistinguishedName
+value, each of which happens for this name to consist of one
+AttributeValueAssertion value. The AttributeType value is
+before the equals sign, and the AttributeValue value (a
+printable string for the given attribute types) is after the
+equals sign.
+
+The countryName, organizationName, and commonUnitName are
+attribute types defined in X.520 as:
+
+attributeType OBJECT IDENTIFIER ::=
+ { joint-iso-ccitt(2) ds(5) 4 }
+
+countryName OBJECT IDENTIFIER ::= { attributeType 6 }
+organizationName OBJECT IDENTIFIER ::=
+ { attributeType 10 }
+commonUnitName OBJECT IDENTIFIER ::=
+ { attributeType 3 }
+
+
+6.2.1 AttributeType
+
+The three AttributeType values are OCTET STRING values, so
+their DER encoding follows the primitive, definite-length
+method:
+
+06 03 55 04 06 countryName
+
+06 03 55 04 0a organizationName
+
+06 03 55 04 03 commonName
+
+The identifier octets follow the low-tag form, since the tag
+is 6 for OBJECT IDENTIFIER. Bits 8 and 7 have value "0,"
+indicating universal class, and bit 6 has value "0,"
+indicating that the encoding is primitive. The length octets
+follow the short form. The contents octets are the
+concatenation of three octet strings derived from
+subidentifiers (in decimal): 40 * 2 + 5 = 85 = 5516; 4; and
+6, 10, or 3.
+
+
+6.2.2 AttributeValue
+
+The three AttributeValue values are PrintableString values,
+so their encodings follow the primitive, definite-length
+method:
+
+13 02 55 53 "US"
+
+13 14 "Example Organization"
+ 45 78 61 6d 70 6c 65 20 4f 72 67 61 6e 69 7a 61
+ 74 69 6f 6e
+
+13 0b "Test User 1"
+ 54 65 73 74 20 55 73 65 72 20 31
+
+The identifier octets follow the low-tag-number form, since
+the tag for PrintableString, 19 (decimal), is between 0 and
+30. Bits 8 and 7 have value "0" since PrintableString is in
+the universal class. Bit 6 has value "0" since the encoding
+is primitive. The length octets follow the short form, and
+the contents octets are the ASCII representation of the
+attribute value.
+
+
+6.2.3 AttributeValueAssertion
+
+The three AttributeValueAssertion values are SEQUENCE
+values, so their DER encodings follow the constructed,
+definite-length method:
+
+30 09 countryName = "US"
+ 06 03 55 04 06
+ 13 02 55 53
+
+30 1b organizationName = "Example Organizaiton"
+ 06 03 55 04 0a
+ 13 14 ... 6f 6e
+
+30 12 commonName = "Test User 1"
+ 06 03 55 04 0b
+ 13 0b ... 20 31
+
+The identifier octets follow the low-tag-number form, since
+the tag for SEQUENCE, 16 (decimal), is between 0 and 30.
+Bits 8 and 7 have value "0" since SEQUENCE is in the
+universal class. Bit 6 has value "1" since the encoding is
+constructed. The length octets follow the short form, and
+the contents octets are the concatenation of the DER
+encodings of the attributeType and attributeValue
+components.
+
+
+6.2.4 RelativeDistinguishedName
+
+The three RelativeDistinguishedName values are SET OF
+values, so their DER encodings follow the constructed,
+definite-length method:
+
+31 0b
+ 30 09 ... 55 53
+
+31 1d
+ 30 1b ... 6f 6e
+
+31 14
+ 30 12 ... 20 31
+
+The identifier octets follow the low-tag-number form, since
+the tag for SET OF, 17 (decimal), is between 0 and 30. Bits
+8 and 7 have value "0" since SET OF is in the universal
+class Bit 6 has value "1" since the encoding is constructed.
+The lengths octets follow the short form, and the contents
+octets are the DER encodings of the respective
+AttributeValueAssertion values, since there is only one
+value in each set.
+
+
+6.2.5 RDNSequence
+
+The RDNSequence value is a SEQUENCE OF value, so its DER
+encoding follows the constructed, definite-length method:
+
+30 42
+ 31 0b ... 55 53
+ 31 1d ... 6f 6e
+ 31 14 ... 20 31
+
+The identifier octets follow the low-tag-number form, since
+the tag for SEQUENCE OF, 16 (decimal), is between 0 and 30.
+Bits 8 and 7 have value "0" since SEQUENCE OF is in the
+universal class. Bit 6 has value "1" since the encoding is
+constructed. The lengths octets follow the short form, and
+the contents octets are the concatenation of the DER
+encodings of the three RelativeDistinguishedName values, in
+order of occurrence.
+
+
+6.2.6 Name
+
+The Name value is a CHOICE value, so its DER encoding is the
+same as that of the RDNSequence value:
+
+30 42
+ 31 0b
+ 30 09
+ 06 03 55 04 06 attributeType = countryName
+ 13 02 55 53 attributeValue = "US"
+ 31 1d
+ 30 1b
+ 06 03 55 04 0a attributeType = organizationName
+ 13 14 attributeValue = "Example Organization"
+ 45 78 61 6d 70 6c 65 20 4f 72 67 61 6e 69 7a 61
+ 74 69 6f 6e
+
+ 31 14
+ 30 12
+ 06 03 55 04 03 attributeType = commonName
+ 13 0b attributeValue = "Test User 1"
+ 54 65 73 74 20 55 73 65 72 20 31
+
+
+References
+
+PKCS #1 RSA Laboratories. PKCS #1: RSA Encryption
+ Standard. Version 1.5, November 1993.
+
+PKCS #3 RSA Laboratories. PKCS #3: Diffie-Hellman Key-
+ Agreement Standard. Version 1.4, November 1993.
+
+PKCS #5 RSA Laboratories. PKCS #5: Password-Based
+ Encryption Standard. Version 1.5, November 1993.
+
+PKCS #6 RSA Laboratories. PKCS #6: Extended-Certificate
+ Syntax Standard. Version 1.5, November 1993.
+
+PKCS #7 RSA Laboratories. PKCS #7: Cryptographic Message
+ Syntax Standard. Version 1.5, November 1993.
+
+PKCS #8 RSA Laboratories. PKCS #8: Private-Key Information
+ Syntax Standard. Version 1.2, November 1993.
+
+PKCS #9 RSA Laboratories. PKCS #9: Selected Attribute
+ Types. Version 1.1, November 1993.
+
+PKCS #10 RSA Laboratories. PKCS #10: Certification Request
+ Syntax Standard. Version 1.0, November 1993.
+
+X.200 CCITT. Recommendation X.200: Reference Model of
+ Open Systems Interconnection for CCITT
+ Applications. 1984.
+
+X.208 CCITT. Recommendation X.208: Specification of
+ Abstract Syntax Notation One (ASN.1). 1988.
+
+X.209 CCITT. Recommendation X.209: Specification of
+ Basic Encoding Rules for Abstract Syntax Notation
+ One (ASN.1). 1988.
+
+X.500 CCITT. Recommendation X.500: The
+ Directory--Overview of Concepts, Models and
+ Services. 1988.
+
+X.501 CCITT. Recommendation X.501: The Directory--
+ Models. 1988.
+
+X.509 CCITT. Recommendation X.509: The Directory--
+ Authentication Framework. 1988.
+
+X.520 CCITT. Recommendation X.520: The Directory--
+ Selected Attribute Types. 1988.
+
+[Kal93] Burton S. Kaliski Jr. Some Examples of the PKCS
+ Standards. RSA Laboratories, November 1993.
+
+[NIST92] NIST. Special Publication 500-202: Stable
+ Implementation Agreements for Open Systems
+ Interconnection Protocols. Part 11 (Directory
+ Services Protocols). December 1992.
+
+
+Revision history
+
+
+June 3, 1991 version
+
+The June 3, 1991 version is part of the initial public
+release of PKCS. It was published as NIST/OSI Implementors'
+Workshop document SEC-SIG-91-17.
+
+
+November 1, 1993 version
+
+The November 1, 1993 version incorporates several editorial
+changes, including the addition of a revision history. It is
+updated to be consistent with the following versions of the
+PKCS documents:
+
+ PKCS #1: RSA Encryption Standard. Version 1.5, November
+ 1993.
+
+ PKCS #3: Diffie-Hellman Key-Agreement Standard. Version
+ 1.4, November 1993.
+
+ PKCS #5: Password-Based Encryption Standard. Version
+ 1.5, November 1993.
+
+ PKCS #6: Extended-Certificate Syntax Standard. Version
+ 1.5, November 1993.
+
+ PKCS #7: Cryptographic Message Syntax Standard. Version
+ 1.5, November 1993.
+
+ PKCS #8: Private-Key Information Syntax Standard.
+ Version 1.2, November 1993.
+
+ PKCS #9: Selected Attribute Types. Version 1.1,
+ November 1993.
+
+ PKCS #10: Certification Request Syntax Standard.
+ Version 1.0, November 1993.
+
+The following substantive changes were made:
+
+ Section 5: Description of T61String type is added.
+
+ Section 6: Names are changed, consistent with other
+ PKCS examples.
+
+
+Author's address
+
+Burton S. Kaliski Jr., Ph.D.
+Chief Scientist
+RSA Laboratories (415) 595-7703
+100 Marine Parkway (415) 595-4126 (fax)
+Redwood City, CA 94065 USA burt@rsa.com
diff --git a/tcllib/modules/asn/pkgIndex.tcl b/tcllib/modules/asn/pkgIndex.tcl
new file mode 100644
index 0000000..3cbafd6
--- /dev/null
+++ b/tcllib/modules/asn/pkgIndex.tcl
@@ -0,0 +1,4 @@
+# Tcl package index file, version 1.1
+
+if {![package vsatisfies [package provide Tcl] 8.4]} {return}
+package ifneeded asn 0.8.4 [list source [file join $dir asn.tcl]]