diff options
author | emboss <emboss@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2011-05-15 20:15:38 +0000 |
---|---|---|
committer | emboss <emboss@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2011-05-15 20:15:38 +0000 |
commit | a5eee54bbe01cef7f9b68ad323991feb9aeda0e0 (patch) | |
tree | 5cdefd1a7d209cedec74931998257418f3b8332f | |
parent | 9b710b827da8bbb9f932b4e8a2cee50ede442981 (diff) | |
download | ruby-a5eee54bbe01cef7f9b68ad323991feb9aeda0e0.tar.gz |
Mon May 16 05:13:20 2011 Martin Bosslet <Martin.Bosslet@googlemail.com>
* ext/openssl/ossl_asn1.c: Add documentation.
Previous revision: 31583
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@31584 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | ext/openssl/ossl_asn1.c | 497 |
2 files changed, 500 insertions, 1 deletions
@@ -1,3 +1,7 @@ +Mon May 16 05:13:20 2011 Martin Bosslet <Martin.Bosslet@googlemail.com> + + * ext/openssl/ossl_asn1.c: Add documentation. + Mon May 16 00:32:05 2011 KOSAKI Motohiro <kosaki.motohiro@gmail.com> * test/ruby/test_signal.rb (TestSignal#test_signal_process_group): diff --git a/ext/openssl/ossl_asn1.c b/ext/openssl/ossl_asn1.c index ca811964b5..9a0871e0c2 100644 --- a/ext/openssl/ossl_asn1.c +++ b/ext/openssl/ossl_asn1.c @@ -655,6 +655,20 @@ ossl_asn1_class2sym(int tc) return ID2SYM(sUNIVERSAL); } +/* + * call-seq: + * OpenSSL::ASN1::ASN1Data.new(value, tag, tag_class) => ASN1Data + * + * +value+: Please have a look at Constructive and Primitive to see how Ruby + * types are mapped to ASN.1 types and vice versa. + * +tag+: A +Number+ indicating the tag number. + * +tag_class: A +Symbol+ indicating the tag class. Please cf. ASN1 for + * possible values. + * + * == Example + * asn1_int = OpenSSL::ASN1Data.new(42, 2, :UNIVERSAL) # => Same as OpenSSL::ASN1::Integer.new(42) + * tagged_int = OpenSSL::ASN1Data.new(42, 0, :CONTEXT_SPECIFIC) # implicitly 0-tagged INTEGER + */ static VALUE ossl_asn1data_initialize(VALUE self, VALUE value, VALUE tag, VALUE tag_class) { @@ -687,6 +701,15 @@ join_der(VALUE enumerable) return str; } +/* + * call-seq: + * asn1.to_der => DER-encoded String + * + * Encodes this ASN1Data into a DER-encoded String value. The result is + * DER-encoded except for the possibility of infinite length encodings. + * Infinite length encodings are not allowed in strict DER, so strictly + * speaking the result of such an encoding would be a BER-encoding. + */ static VALUE ossl_asn1data_to_der(VALUE self) { @@ -855,7 +878,28 @@ ossl_asn1_decode0(unsigned char **pp, long length, long *offset, long depth, return ary; } - + +/* + * call-seq: + * OpenSSL::ASN1.traverse(asn1) -> nil + * + * If a block is given, it prints out each of the elements encountered. + * Block parameters are (in that order): + * * depth: The recursion depth, plus one with each constructed value being encountered (Number) + * * offset: Current byte offset (Number) + * * header length: Combined length in bytes of the Tag and Length headers. (Number) + * * length: The overall remaining length of the entire data (Number) + * * constructed: Whether this value is constructed or not (Boolean) + * * tag_class: Current tag class (Symbol) + * * tag: The current tag (Number) + * + * == Example + * der = File.binread('asn1data.der') + * OpenSSL::ASN1.traverse(der) do | depth, offset, header_len, length, constructed, tag_class, tag| + * puts "Depth: #{depth} Offset: #{offset} Length: #{length}" + * puts "Header length: #{header_len} Tag: #{tag} Tag class: #{tag_class} Constructed: #{constructed}" + * end + */ static VALUE ossl_asn1_traverse(VALUE self, VALUE obj) { @@ -871,6 +915,18 @@ ossl_asn1_traverse(VALUE self, VALUE obj) return Qnil; } +/* + * call-seq: + * OpenSSL::ASN1.decode(der) -> ASN1Data + * + * Decodes a BER- or DER-encoded value and creates an ASN1Data instance. +der+ + * may be a +String+ or any object that features a +#to_der+ method transforming + * it into a BER-/DER-encoded +String+. + * + * == Example + * der = File.binread('asn1data') + * asn1 = OpenSSL::ASN1.decode(der) + */ static VALUE ossl_asn1_decode(VALUE self, VALUE obj) { @@ -888,6 +944,19 @@ ossl_asn1_decode(VALUE self, VALUE obj) return ret; } +/* + * call-seq: + * OpenSSL::ASN1.decode_all(der) -> Array of ASN1Data + * + * Similar to +decode+ with the difference that +decode+ expects one + * distinct value represented in +der+. +decode_all+ on the contrary + * decodes a sequence of sequential BER/DER values lined up in +der+ + * and returns them as an array. + * + * == Example + * ders = File.binread('asn1data_seq') + * asn1_ary = OpenSSL::ASN1.decode_all(ders) + */ static VALUE ossl_asn1_decode_all(VALUE self, VALUE obj) { @@ -904,6 +973,26 @@ ossl_asn1_decode_all(VALUE self, VALUE obj) return ret; } +/* + * call-seq: + * OpenSSL::ASN1::Primitive.new( value [, tag, tagging, tag_class ]) => Primitive + * + * +value+: is mandatory. + * +tag+: optional, may be specified for tagged values. If no +tag+ is + * specified, the UNIVERSAL tag corresponding to the Primitive sub-class + * is used by default. + * +tagging+: may be used as an encoding hint to encode a value either + * explicitly or implicitly, see ASN1 for possible values. + * +tag_class+: if +tag+ and +tagging+ are +nil+ then this is set to + * +:UNIVERSAL+ by default. If either +tag+ or +tagging+ are set then + * +:CONTEXT_SPECIFIC+ is used as the default. For possible values please + * cf. ASN1. + * + * == Example + * int = OpenSSL::ASN1::Integer.new(42) + * zero_tagged_int = OpenSSL::ASN1::Integer.new(42, 0, :IMPLICIT) + * private_explicit_zero_tagged_int = OpenSSL::ASN1::Integer.new(42, 0, :EXPLICIT, :PRIVATE) + */ static VALUE ossl_asn1_initialize(int argc, VALUE *argv, VALUE self) { @@ -977,6 +1066,12 @@ ossl_ASN1_TYPE_free(ASN1_TYPE *a) ASN1_TYPE_free(a); } +/* + * call-seq: + * asn1.to_der => DER-encoded String + * + * See ASN1Data#to_der for details. * + */ static VALUE ossl_asn1prim_to_der(VALUE self) { @@ -1014,6 +1109,12 @@ ossl_asn1prim_to_der(VALUE self) return str; } +/* + * call-seq: + * asn1.to_der => DER-encoded String + * + * See ASN1Data#to_der for details. + */ static VALUE ossl_asn1cons_to_der(VALUE self) { @@ -1083,6 +1184,19 @@ ossl_asn1cons_to_der(VALUE self) return str; } +/* + * call-seq: + * asn1_ary.each { |asn1| block } => asn1_ary + * + * Calls <i>block</i> once for each element in +self+, passing that element + * as parameter +asn1+. If no block is given, an enumerator is returned + * instead. + * + * == Example + * asn1_ary.each do |asn1| + * puts asn1 + * end + */ static VALUE ossl_asn1cons_each(VALUE self) { @@ -1189,12 +1303,148 @@ Init_ossl_asn1() sEXPLICIT = rb_intern("EXPLICIT"); sIMPLICIT = rb_intern("IMPLICIT"); + /* + * Document-module: OpenSSL::ASN1 + * + * Abstract Syntax Notation One (or ASN.1) is a notation syntax to + * describe data structures and is defined in ITU-T X.680. ASN.1 itself + * does not mandate any encoding or parsing rules, but usually ASN.1 data + * structures are encoded using the Distinguished Encoding Rules (DER) or + * less often the Basic Encoding Rules (BER) described in ITU-T X.690. DER + * and BER encodings are binary Tag-Length-Value (TLV) encodings that are + * quite concise compared to other popular data description formats such + * as XML, JSON etc. + * ASN.1 data structures are very common in cryptographic applications, + * e.g. X.509 public key certificates or certificate revocation lists + * (CRLs) are all defined in ASN.1 and DER-encoded. ASN.1, DER and BER are + * the building blocks of applied cryptography. + * The ASN1 module provides the necessary classes that allow generation + * of ASN.1 data structures and the methods to encode them using a DER + * encoding. The decode method allows parsing arbitrary BER-/DER-encoded + * data to a Ruby object that can then be modified and re-encoded at will. + * + * == ASN.1 class hierarchy + * + * The base class representing ASN.1 structues is ASN1Data. ASN1Data offers + * attributes to read and set the +tag+, the +tag_class+ and finally the + * +value+ of a particular ASN.1 item. Upon parsing, any tagged values + * (implicit or explicit) will be represented by ASN1Data instances because + * their "real type" can only be determined using out-of-band information + * from the ASN.1 type declaration. Since this information is normally + * known when encoding a type, all sub-classes of ASN1Data offer an + * additional attribute +tagging+ that allows to encode a value implicitly + * (+:IMPLICIT+) or explicitly (+:EXPLICIT+). + * + * === Constructive + * + * Constructive is, as its name implies, the base class for all + * constructed encodings, i.e. those that consist of several values, + * opposed to "primitive" encodings with just one single value. + * Primitive values that are encoded with "infinite length" are typically + * constructed (their values come in multiple chunks) and are therefore + * represented by instances of Constructive. The value of an Constructive + * is always an Array. + * + * ==== ASN1::Set and ASN1::Sequence + * + * The most common constructive encodings are SETs and SEQUENCEs, which is + * why there are two sub-classes of Constructive representing each of + * them. + * + * === Primitive + * + * This is the super class of all primitive values. Primitive + * itself is not used when parsing ASN.1 data, all values are either + * instances of a corresponding sub-class of Primitive or they are + * instances of ASN1Data if the value was tagged implicitly or explicitly. + * Please cf. Primitive documentation for details on sub-classes and + * their respective mappings of ASN.1 data types to Ruby types. + * + * == Possible values for attribute +tagging+ + * + * When constructing an ASN1Data object the ASN.1 type definition may + * require certain elements to be either implicitly or explicitly tagged. + * This can be achieved by setting the +tagging+ attribute manually for + * sub-classes of ASN1Data. Use the symbol +:IMPLICIT+ for implicit + * tagging and +:EXPLICIT+ if the element requires explicit tagging. + * + * == Possible values for +tag_class+ + * + * It is possible to create arbitrary ASN1Data objects that also support + * a PRIVATE or APPLICATION tag class. Possible values for the +tag_class+ + * attribute are: + * * +:UNIVERSAL+ (the default for untagged values) + * * +:CONTEXT_SPECIFIC+ (the default for tagged values) + * * +:APPLICATION+ + * * +:PRIVATE+ + * + * == Tag constants + * + * There is a constant defined for each universal tag: + * * OpenSSL::ASN1::EOC (0) + * * OpenSSL::ASN1::BOOLEAN (1) + * * OpenSSL::ASN1::INTEGER (2) + * * OpenSSL::ASN1::BIT_STRING (3) + * * OpenSSL::ASN1::OCTET_STRING (4) + * * OpenSSL::ASN1::NULL (5) + * * OpenSSL::ASN1::OBJECT (6) + * * OpenSSL::ASN1::ENUMERATED (10) + * * OpenSSL::ASN1::UTF8STRING (12) + * * OpenSSL::ASN1::SEQUENCE (16) + * * OpenSSL::ASN1::SET (17) + * * OpenSSL::ASN1::NUMERICSTRING (18) + * * OpenSSL::ASN1::PRINTABLESTRING (19) + * * OpenSSL::ASN1::T61STRING (20) + * * OpenSSL::ASN1::VIDEOTEXSTRING (21) + * * OpenSSL::ASN1::IA5STRING (22) + * * OpenSSL::ASN1::UTCTIME (23) + * * OpenSSL::ASN1::GENERALIZEDTIME (24) + * * OpenSSL::ASN1::GRAPHICSTRING (25) + * * OpenSSL::ASN1::ISO64STRING (26) + * * OpenSSL::ASN1::GENERALSTRING (27) + * * OpenSSL::ASN1::UNIVERSALSTRING (28) + * * OpenSSL::ASN1::BMPSTRING (30) + * + * == UNIVERSAL_TAG_NAME constant + * + * An Array that stores the name of a given tag number. These names are + * the same as the name of the tag constant that is additionally defined, + * e.g. UNIVERSAL_TAG_NAME[2] = "INTEGER" and OpenSSL::ASN1::INTEGER = 2. + * + * == Example usage + * + * === Decoding and viewing a DER-encoded file + * require 'openssl' + * require 'pp' + * der = File.binread('data.der') + * asn1 = OpenSSL::ASN1.decode(der) + * pp der + * + * === Creating an ASN.1 structure and DER-encoding it + * require 'openssl' + * version = OpenSSL::ASN1::Integer.new(1) + * # Explicitly 0-tagged implies context-specific tag class + * serial = OpenSSL::ASN1::Integer.new(12345, 0, :EXPLICIT, :CONTEXT_SPECIFIC) + * name = OpenSSL::ASN1::PrintableString.new('Data 1') + * sequence = OpenSSL::ASN1::Sequence.new( [ version, serial, name ] ) + * der = sequence.to_der + */ mASN1 = rb_define_module_under(mOSSL, "ASN1"); + + /* Document-class: OpenSSL::ASN1::ASN1Error + * + * Generic error class for all errors raised in ASN1 and any of the + * classes defined in it. + */ eASN1Error = rb_define_class_under(mASN1, "ASN1Error", eOSSLError); rb_define_module_function(mASN1, "traverse", ossl_asn1_traverse, 1); rb_define_module_function(mASN1, "decode", ossl_asn1_decode, 1); rb_define_module_function(mASN1, "decode_all", ossl_asn1_decode_all, 1); ary = rb_ary_new(); + + /* + * Array storing tag names at the tag's index. + */ rb_define_const(mASN1, "UNIVERSAL_TAG_NAME", ary); for(i = 0; i < ossl_asn1_info_size; i++){ if(ossl_asn1_info[i].name[0] == '[') continue; @@ -1202,6 +1452,126 @@ Init_ossl_asn1() rb_ary_store(ary, i, rb_str_new2(ossl_asn1_info[i].name)); } + /* Document-class: OpenSSL::ASN1::ASN1Data + * + * The top-level class representing any ASN.1 object. When parsed by + * ASN1#decode, tagged values are always represented by an instance + * of ASN1Data. + * + * == Attributes + * + * === +value+ + * + * Carries the value of a ASN.1 type. + * Please confer Constructive and Primitive for the mappings between + * ASN.1 data types and Ruby classes. + * + * === +tag+ + * + * A +Number+ representing the tag number of this ASN1Data. Never +nil+. + * + * === +tag_class+ + * + * A +Symbol+ reprensenting the tag class of this ASN1Data. Never +nil+. + * See ASN1Data for possible values. + * + * === +infinite_length+ + * + * Never +nil+. A Boolean indicating whether the encoding was infinite + * length (in the case of parsing) or whether an infinite length encoding + * shall be used (in the encoding case). + * In DER, every value has a finite length associated with it. But in + * scenarios where large amounts of data need to be transferred it + * might be desirable to have some kind of streaming support available. + * For example, huge OCTET STRINGs are preferrably sent in smaller-sized + * chunks, each at a time. + * This is possible in BER by setting the length bytes of an encoding + * to zero and by this indicating that the following value will be + * sent in chunks. Infinite length encodings are always constructed. + * The end of such a stream of chunks is indicated by sending a EOC + * (End of Content) tag. SETs and SEQUENCEs may use an infinite length + * encoding, but also primitive types such as e.g. OCTET STRINGS or + * BIT STRINGS may leverage this functionality (cf. ITU-T X.690). + * + * == The role of ASN1Data for parsing tagged values + * + * When encoding an ASN.1 type it is inherently clear what original + * type a this value has, regardless of its tagging. + * But opposed to the time when an ASN.1 type is to be encoded, when + * parsing them it is not possible to deduce the "real type" of tagged + * values. This is why tagged values are generally parsed into ASN1Data + * instances, but with a different outcome for implicit and explicit + * tagging. + * === Example of a parsed implicitly tagged value + * + * An implicitly 1-tagged INTEGER value will be parsed as an + * ASN1Data with + * * +tag+ equal to 1 + * * +tag_class+ equal to +:CONTEXT_SPECIFIC+ + * * +value+ equal to a +String+ that carries the raw encoding + * of the INTEGER. + * This implies that a subsequent decoding step is required to + * completely decode implicitly tagged values. + * + * === Example of a parsed explicitly tagged value + * + * An explicitly 1-tagged INTEGER value will be parsed as an + * ASN1Data with + * * +tag+ equal to 1 + * * +tag_class+ equal to +:CONTEXT_SPECIFIC+ + * * +value+ equal to an +Array+ with one single element, an + * instance of OpenSSL::ASN1::Integer, i.e. the inner element + * is the non-tagged primitive value, and the tagging is represented + * in the outer ASN1Data + * + * == Example - Decoding an implicitly tagged INTEGER + * int = OpenSSL::ASN1::Integer.new(1, 0, :IMPLICIT) # implicit 0-tagged + * seq = OpenSSL::ASN1::Sequence.new( [int] ) + * der = seq.to_der + * asn1 = OpenSSL::ASN1.decode(der) + * # pp asn1 => #<OpenSSL::ASN1::Sequence:0x87326e0 + * # @infinite_length=false, + * # @tag=16, + * # @tag_class=:UNIVERSAL, + * # @tagging=nil, + * # @value= + * # [#<OpenSSL::ASN1::ASN1Data:0x87326f4 + * # @infinite_length=false, + * # @tag=0, + * # @tag_class=:CONTEXT_SPECIFIC, + * # @value="\x01">]> + * raw_int = asn1.value[0] + * # manually rewrite tag and tag class to make it an UNIVERSAL value + * raw_int.tag = OpenSSL::ASN1::INTEGER + * raw_int.tag_class = :UNIVERSAL + * int2 = OpenSSL::ASN1.decode(raw_int) + * puts int2.value # => 1 + * + * == Example - Decoding an explicitly tagged INTEGER + * int = OpenSSL::ASN1::Integer.new(1, 0, :EXPLICIT) # explicit 0-tagged + * seq = OpenSSL::ASN1::Sequence.new( [int] ) + * der = seq.to_der + * asn1 = OpenSSL::ASN1.decode(der) + * # pp asn1 => #<OpenSSL::ASN1::Sequence:0x87326e0 + * # @infinite_length=false, + * # @tag=16, + * # @tag_class=:UNIVERSAL, + * # @tagging=nil, + * # @value= + * # [#<OpenSSL::ASN1::ASN1Data:0x87326f4 + * # @infinite_length=false, + * # @tag=0, + * # @tag_class=:CONTEXT_SPECIFIC, + * # @value= + * # [#<OpenSSL::ASN1::Integer:0x85bf308 + * # @infinite_length=false, + * # @tag=2, + * # @tag_class=:UNIVERSAL + * # @tagging=nil, + * # @value=1>]>]> + * int2 = asn1.value[0].value[0] + * puts int2.value # => 1 + */ cASN1Data = rb_define_class_under(mASN1, "ASN1Data", rb_cObject); rb_attr(cASN1Data, rb_intern("value"), 1, 1, 0); rb_attr(cASN1Data, rb_intern("tag"), 1, 1, 0); @@ -1210,12 +1580,137 @@ Init_ossl_asn1() rb_define_method(cASN1Data, "initialize", ossl_asn1data_initialize, 3); rb_define_method(cASN1Data, "to_der", ossl_asn1data_to_der, 0); + /* Document-class: OpenSSL::ASN1::Primitive + * + * The parent class for all primitive encodings. Attributes are the same as + * for ASN1Data, with the addition of +tagging+. +tagging+ may be used + * as a hint for encoding a value either implicitly or explicitly by + * setting it either to +:IMPLICIT+ or to +:EXPLICIT+. + * +tagging+ is not set when a ASN.1 structure is parsed using + * OpenSSL::ASN1.decode. * Primitive values can never be infinite length encodings, thus it is not + * possible to set the +infinite_length+ attribute for Primitive and its + * sub-classes. + * + * == Primitive sub-classes and their mapping to Ruby classes + * * OpenSSL::ASN1::EndOfContent <=> +value+ is always +nil+ + * * OpenSSL::ASN1::Boolean <=> +value+ is a +Boolean+ + * * OpenSSL::ASN1::Integer <=> +value+ is a +Number+ + * * OpenSSL::ASN1::BitString <=> +value+ is a +String+ + * * OpenSSL::ASN1::OctetString <=> +value+ is a +String+ + * * OpenSSL::ASN1::Null <=> +value+ is always +nil+ + * * OpenSSL::ASN1::Object <=> +value+ is a +String+ + * * OpenSSL::ASN1::Enumerated <=> +value+ is a +Number+ + * * OpenSSL::ASN1::UTF8String <=> +value+ is a +String+ + * * OpenSSL::ASN1::NumericString <=> +value+ is a +String+ + * * OpenSSL::ASN1::PrintableString <=> +value+ is a +String+ + * * OpenSSL::ASN1::T61String <=> +value+ is a +String+ + * * OpenSSL::ASN1::VideotexString <=> +value+ is a +String+ + * * OpenSSL::ASN1::IA5String <=> +value+ is a +String+ + * * OpenSSL::ASN1::UTCTime <=> +value+ is a +Time+ + * * OpenSSL::ASN1::GeneralizedTime <=> +value+ is a +Time+ + * * OpenSSL::ASN1::GraphicString <=> +value+ is a +String+ + * * OpenSSL::ASN1::ISO64String <=> +value+ is a +String+ + * * OpenSSL::ASN1::GeneralString <=> +value+ is a +String+ + * * OpenSSL::ASN1::UniversalString <=> +value+ is a +String+ + * * OpenSSL::ASN1::BMPString <=> +value+ is a +String+ + * + * == OpenSSL::ASN1::BitString + * + * === Additional attributes + * +unused_bits+: if the underlying BIT STRING's + * length is a multiple of 8 then +unused_bits+ is 0. Otherwise + * +unused_bits+ indicates the number of bits that are to be ignored in + * the final octet of the +BitString+'s +value+. + * + * == OpenSSL::ASN1::ObjectId + * + * === Additional attributes + * * +sn+: the short name as defined in <openssl/objects.h>. + * * +ln+: the long name as defined in <openssl/objects.h>. + * * +oid+: the object identifier as a +String+, e.g. "1.2.3.4.5" + * * +short_name+: alias for +sn+. + * * +long_name+: alias for +ln+. + * + * == Examples + * With the Exception of OpenSSL::ASN1::EndOfContent, each Primitive class + * takes at least one parameter, the +value+. + * + * === Creating EndOfContent + * eoc = OpenSSL::ASN1::EndOfContent.new + * + * === Creating any other Primitive + * prim = <class>.new(value) # <class> being one of the sub-classes except EndOfContent + * prim_zero_tagged_implicit = <class>.new(value, 0, :IMPLICIT) + * prim_zero_tagged_explicit = <class>.new(value, 0, :EXPLICIT) + */ cASN1Primitive = rb_define_class_under(mASN1, "Primitive", cASN1Data); rb_attr(cASN1Primitive, rb_intern("tagging"), 1, 1, Qtrue); rb_undef_method(cASN1Primitive, "infinite_length="); rb_define_method(cASN1Primitive, "initialize", ossl_asn1_initialize, -1); rb_define_method(cASN1Primitive, "to_der", ossl_asn1prim_to_der, 0); + /* Document-class: OpenSSL::ASN1::Constructive + * + * The parent class for all constructed encodings. The +value+ attribute + * of a Constructive is always an +Array+. Attributes are the same as + * for ASN1Data, with the addition of +tagging+. +tagging+ may be used + * as a hint for encoding to encode a value either implicitly or + * explicitly by setting it either to +:IMPLICIT+ or to +:EXPLICIT+. + * +tagging+ is not set when a ASN.1 structure is parsed using + * OpenSSL::ASN1.decode. + * + * == SET and SEQUENCE + * + * Most constructed encodings come in the form of a SET or a SEQUENCE. + * These encodings are represented by one of the two sub-classes of + * Constructive: + * * OpenSSL::ASN1::Set + * * OpenSSL::ASN1::Sequence + * Please note that tagged sequences and sets are still parsed as + * instances of ASN1Data. Find further details on tagged values + * there. + * + * === Example - constructing a SEQUENCE + * int = OpenSSL::ASN1::Integer.new(1) + * str = OpenSSL::ASN1::PrintableString.new('abc') + * sequence = OpenSSL::ASN1::Sequence.new( [ int, str ] ) + * + * === Example - constructing a SET + * int = OpenSSL::ASN1::Integer.new(1) + * str = OpenSSL::ASN1::PrintableString.new('abc') + * set = OpenSSL::ASN1::Set.new( [ int, str ] ) + * + * == Infinite length primitive values + * + * The only case where Constructive is used directly is for infinite + * length encodings of primitive values. These encodings are always + * constructed, with the contents of the +value+ +Array+ being either + * UNIVERSAL non-infinite length partial encodings of the actual value + * or again constructive encodings with infinite length (i.e. infinite + * length primitive encodings may be constructed recursively with another + * infinite length value within an already infinite length value). Each + * partial encoding must be of the same UNIVERSAL type as the overall + * encoding. The value of the overall encoding consists of the + * concatenation of each partial encoding taken in sequence. The +value+ + * array of the outer infinite length value must end with a + * OpenSSL::ASN1::EndOfContent instance. + * + * === Example - Infinite length OCTET STRING + * partial1 = OpenSSL::ASN1::OctetString.new("\x01") + * partial2 = OpenSSL::ASN1::OctetString.new("\x02") + * inf_octets = OpenSSL::ASN1::Constructive.new( [ partial1, + * partial2, + * OpenSSL::ASN1::EndOfContent.new ], + * OpenSSL::ASN1::OCTET_STRING, + * nil, + * :UNIVERSAL ) + * # The real value of inf_octets is "\x01\x02", i.e. the concatenation + * # of partial1 and partial2 + * inf_octets.infinite_length = true + * der = inf_octets.to_der + * asn1 = OpenSSL::ASN1.decode(der) + * puts asn1.infinite_length # => true + */ cASN1Constructive = rb_define_class_under(mASN1,"Constructive", cASN1Data); rb_include_module(cASN1Constructive, rb_mEnumerable); rb_attr(cASN1Constructive, rb_intern("tagging"), 1, 1, Qtrue); |