pike.git / lib / modules / Standards.pmod / ASN1.pmod / Types.pmod

version» Context lines:

pike.git/lib/modules/Standards.pmod/ASN1.pmod/Types.pmod:1:   //! Encodes various asn.1 objects according to the Distinguished   //! Encoding Rules (DER)      #pike __REAL_VERSION__   #pragma strict_types - #define COMPATIBILITY +       #if 0   #define WERROR werror   #else   #define WERROR(x ...)   #endif         // Helper functions    - #define MAKE_COMBINED_TAG(cls, tag) (((tag) << 2) | (cls)) -  - //! Combines tag and class as a single integer, in a somewhat arbitrary - //! way. This works also for tags beyond 31 (although not for tags - //! beyond 2^30. + //! Combines tag and class to a single integer, for internal uses.   //!   //! @param cls - //! ASN1 type class + //! ASN1 type class (0..3).   //! @param tag - //! ASN1 type tag + //! ASN1 type tag (1..).   //! @returns - //! combined tag + //! The combined tag.   //! @seealso - //! @[Standards.ASN1.Types.extract_tag] - //! @[Standards.ASN1.Types.extract_cls] - int make_combined_tag(int cls, int tag) - { return MAKE_COMBINED_TAG(cls, tag); } + //! @[extract_tag], @[extract_cls] + int(4..) make_combined_tag(int(0..3) cls, int(1..) tag) + { return [int(4..)](tag << 2 | cls); }    - //! extract ASN1 type tag from a combined tag + //! Extract ASN1 type tag from a combined tag.   //! @seealso - //! @[Standards.ASN1.Types.make_combined_tag] - int extract_tag(int i) { return i >> 2; } + //! @[make_combined_tag] + int(0..) extract_tag(int(0..) i) { return i >> 2; }    - //! extract ASN1 type class from a combined tag + //! Extract ASN1 type class from a combined tag.   //! @seealso - //! @[Standards.ASN1.Types.make_combined_tag] - int extract_cls(int i) { return i & 3; } + //! @[make_combined_tag] + int(0..3) extract_cls(int(0..) i) { return [int(0..3)](i & 3); }         // Class definitions    -  + #define CODEC(X) \ +  array _encode() { return ({ cls, tag, value }); } \ +  void _decode(array(X) x) { [ cls, tag, value ] = x; } +    //! Generic, abstract base class for ASN1 data types.   class Object   { -  constant cls = 0; -  constant tag = 0; +  int(0..3) cls = 0; +  int(1..) tag = 0;    constant constructed = 0;    -  constant type_name = 0; -  string(0..255) der_encode(); +  constant type_name = "";    -  +  protected string(8bit) get_der_content() +  { +  return ""; +  } +     //! Get the class of this object.    //!    //! @returns    //! The class of this object. -  int get_cls() { return cls; } +  int(0..3) get_cls() { return cls; }       //! Get the tag for this object.    //!    //! @returns    //! The tag for this object. -  int get_tag() { return tag; } +  int(1..) get_tag() { return tag; }       //! Get the combined tag (tag + class) for this object.    //!    //! @returns    //! the combined tag header -  int get_combined_tag() { -  return make_combined_tag(get_tag(), get_cls()); +  int(1..) get_combined_tag() { +  return make_combined_tag(get_cls(), get_tag());    }    -  string(0..255) der; +  protected string(0..255) der;       // Should be overridden by subclasses    this_program decode_primitive(string contents, -  function(ADT.struct, +  function(Stdio.Buffer,    mapping(int:program(Object)):    Object) decoder,    mapping(int:program(Object)) types); -  this_program begin_decode_constructed(string raw); -  this_program decode_constructed_element(int i, object e); -  this_program end_decode_constructed(int length); +  void begin_decode_constructed(string raw); +  void decode_constructed_element(int i, object e);       mapping(int:program(Object)) element_types(int i,    mapping(int:program(Object)) types) {    return types; i;    }    this_program init(mixed ... args) { return this; args; }    -  string(0..255) to_base_128(int n) +  protected string(0..255) to_base_128(int n)    { -  if (!n) -  return "\0"; -  /* Convert tag number to base 128 */ -  array(int) digits = ({ }); -  -  /* Array is built in reverse order, least significant digit first */ -  while(n) +  string(0..255) ret = [string(0..127)]sprintf("%c", n&0x7f); +  n >>= 7; +  while( n )    { -  digits += ({ (n & 0x7f) | 0x80 }); +  ret = [string(0..255)]sprintf("%c", (n&0x7f) | 0x80) + ret;    n >>= 7;    } -  digits[0] &= 0x7f; -  -  return [string(0..255)]sprintf("%@c", reverse(digits)); +  return ret;    }    -  string(0..255) encode_tag() +  protected string(0..255) encode_tag()    { -  int tag = get_tag(); -  int cls = get_cls(); +  int(0..3) cls = get_cls(); +  int(1..) tag = get_tag();    if (tag < 31)    return [string(0..255)]sprintf("%c",    (cls << 6) | (constructed << 5) | tag);       return [string(0..255)]sprintf("%c%s",    (cls << 6) | (constructed << 5) | 0x1f,    to_base_128(tag) );    }    -  string(0..255) encode_length(int|object len) +  protected string(0..255) encode_length(int|object len)    {    if (len < 0x80)    return [string(0..255)]sprintf("%c", len);    string s = Gmp.mpz(len)->digits(256);    if (sizeof(s) >= 0x80)    error("Max length exceeded.\n" );    return [string(0..255)]sprintf("%c%s", sizeof(s) | 0x80, s);    }    -  string(0..255) build_der(string(0..255) contents) +  protected string(0..255) build_der(string(0..255) contents)    {    string(0..255) data =    encode_tag() + encode_length(sizeof(contents)) + contents;    WERROR("build_der: %O\n", data);    return data;    }    -  __deprecated__ string(0..255) record_der(string(0..255) s) -  { -  return (der = s); -  } -  -  void record_der_contents(string(0..255) s) -  { -  der = build_der(s); -  } -  -  +     //! Get the DER encoded version of this object.    //!    //! @returns    //! DER encoded representation of this object.    string(0..255) get_der() { -  return der || (der = der_encode()); +  return build_der(get_der_content());    }    -  void create(mixed ...args) { +  protected void create(mixed ...args) {    WERROR("asn1_object[%s]->create\n", type_name);    if (sizeof(args))    init(@args);    }   }      //! Compound object primitive   class Compound   {    inherit Object;       constant constructed = 1;    -  //! contents of compound object, elements are from @[Standards.ASN1.Types] +  //! Contents of compound object.    array(Object) elements = ({ });       this_program init(array args) {    WERROR("asn1_compound[%s]->init(%O)\n", type_name, args);    foreach(args, mixed o)    if (!objectp(o))    error( "Non-object argument %O\n", o );    elements = [array(Object)]args;    WERROR("asn1_compound: %O\n", elements);    return this;    }    -  this_program begin_decode_constructed(string(0..255) raw) { +  void begin_decode_constructed(string(0..255) raw) {    WERROR("asn1_compound[%s]->begin_decode_constructed\n", type_name); -  record_der_contents(raw); -  return this; +     }    -  this_program decode_constructed_element(int i, object e) { +  void decode_constructed_element(int i, object e) {    WERROR("asn1_compound[%s]->decode_constructed_element(%O)\n",    type_name, e);    if (i != sizeof(elements))    error("Unexpected index!\n");    elements += ({ e }); -  return this; +     }    -  this_program end_decode_constructed(int length) { -  if (length != sizeof(elements)) -  error("Invalid length!\n"); -  return this; -  } -  +     protected mixed `[](mixed index)    {    if( intp(index) )    return elements[index];    return ::`[]([string]index);    }       protected int _sizeof()    {    return sizeof(elements);    }       protected string _sprintf(int t,mapping(string:int)|void params) {    if (params) ++params->indent; else params=([]);    return t=='O' && sprintf("%O(%*O)", this_program, params, elements);    }    - #ifdef COMPATIBILITY -  __deprecated__ string debug_string() { -  WERROR("asn1_compound[%s]->debug_string(), elements = %O\n", -  type_name, elements); -  return _sprintf('O'); +  array _encode() +  { +  return ({ cls, tag, elements });    } - #endif +  +  void _decode(array(int|array(Object)) x) +  { +  cls = [int(0..3)]x[0]; +  tag = [int(1..)]x[1]; +  elements = [array(Object)]x[2];    } -  + }      //! string object primitive   class String   {    inherit Object;       //! value of object    string value;    -  +  //! @ignore +  CODEC(string); +  //! @endignore +     this_program init(string(0..255) s) {    value = s;    return this;    }    -  string(0..255) der_encode() { -  return build_der([string(0..255)]value); +  string(0..255) get_der_content() { +  return [string(0..255)]value;    }       this_program decode_primitive(string(0..255) contents, -  function(ADT.struct, +  function(Stdio.Buffer,    mapping(int:program(Object)):    Object)|void decoder,    mapping(int:program(Object))|void types) { -  record_der_contents(contents); +     value = contents;    return this;    }    -  protected string _sprintf(int t) { -  return t=='O' && sprintf("%O(%O)", this_program, value); +  void begin_decode_constructed(string raw) +  { +  value = "";    }    - #ifdef COMPATIBILITY -  __deprecated__ string debug_string() { -  WERROR("asn1_string[%s]->debug_string(), value = %O\n", type_name, value); -  return _sprintf('O'); +  void decode_constructed_element(int i, object(this_program) e) +  { +  value += e->value;    } - #endif +  +  protected string _sprintf(int t) { +  return t=='O' && sprintf("%O(%O)", this_program, value);    } -  + }    - // FIXME: What is the DER-encoding of TRUE??? - // According to Jan Petrous, the LDAP spec says that 0xff is right. - // No, every nonzero value is true according to the ASN1 spec, - // but they use 0xff as example of a true value. /Nilsson -  +    //! boolean object   class Boolean   {    inherit Object; -  constant tag = 1; +  +  int(1..) tag = 1;    constant type_name = "BOOLEAN";       //! value of object    int value;    -  +  //! @ignore +  CODEC(int); +  //! @endignore +     this_program init(int x) {    value = x;    return this;    }    -  string(0..255) der_encode() { -  return build_der(value ? "\377" : "\0"); +  // While every non-zero value is true, the canonical true is 0xff. +  string(0..255) get_der_content() +  { +  return value ? "\377" : "\0";    }       this_program decode_primitive(string(0..255) contents, -  function(ADT.struct, +  function(Stdio.Buffer,    mapping(int:program(Object)):    Object)|void decoder,    mapping(int:program(Object))|void types) { -  record_der_contents(contents); +  if( contents=="" ) error("Illegal boolean value.\n");    value = (contents != "\0");    return this;    }       protected string _sprintf(int t) {    return t=='O' && sprintf("%O(%s)", this_program, (value?"TRUE":"FALSE"));    } -  - #ifdef COMPATIBILITY -  __deprecated__ string debug_string() { -  return value ? "TRUE" : "FALSE"; +    } - #endif - } +       //! Integer object   //! All integers are represented as bignums, for simplicity   class Integer   {    inherit Object; -  constant tag = 2; +  +  int(1..) tag = 2;    constant type_name = "INTEGER";       //! value of object    Gmp.mpz value;    -  +  //! @ignore +  CODEC(Gmp.mpz); +  //! @endignore +     this_object init(int|object n) {    value = Gmp.mpz(n);    WERROR("i = %s\n", value->digits());    return this;    }    -  string(0..255) der_encode() +  string(0..255) get_der_content()    {    string(0..255) s;       if (value < 0)    {    Gmp.mpz n = [object(Gmp.mpz)](value +    pow(256, ([object(Gmp.mpz)](- value))->    size(256)));    s = n->digits(256);    if (!(s[0] & 0x80))    s = "\377" + s;    } else {    s = value->digits(256);    if (s[0] & 0x80)    s = "\0" + s;    } -  return build_der(s); +  +  return s;    }       this_object decode_primitive(string(0..255) contents, -  function(ADT.struct, +  function(Stdio.Buffer,    mapping(int:program(Object)):    Object)|void decoder,    mapping(int:program(Object))|void types) { -  record_der_contents(contents); +     value = Gmp.mpz(contents, 256);    if (contents[0] & 0x80) /* Negative */    value -= pow(256, sizeof(contents));    return this;    }       protected string _sprintf(int t) { -  return t=='O' && sprintf("%O(%d %s)", this_program, +  if(t!='O') return UNDEFINED; +  if(!value) return sprintf("%O(0)", this_program); +  return sprintf("%O(%d %s)", this_program,    value->size(), value->digits());    } -  - #ifdef COMPATIBILITY -  __deprecated__ string debug_string() { -  return sprintf("INTEGER (%d) %s", value->size(), value->digits()); +    } - #endif - } +       //! Enumerated object   class Enumerated   {    inherit Integer; -  constant tag = 10; -  constant type_name ="ENUMERATED"; +  int(1..) tag = 10; +  constant type_name = "ENUMERATED";   }    -  + class Real + { +  inherit Object; +  +  int(1..) tag = 9; +  constant type_name = "REAL"; +  +  float value; +  +  //! @ignore +  CODEC(float); +  //! @endignore +  +  string(0..255) get_der_content() +  { +  string v = sprintf("%F", value); +  switch(v) +  { +  case "\0\0\0\0" : return ""; // 0.0 +  case "\200\0\0\0" : return "\x43"; // -0.0 +  case "\177\200\0\0" : return "\x40"; // inf +  case "\377\200\0\0" : return "\x41"; // -inf +  +  case "\177\300\0\0" : // nan +  case "\377\300\0\0" : // -nan +  return "\x42"; +  } +  +  error("Encoding Real values not supported.\n"); +  } +  +  this_object decode_primitive(string(0..255) contents, +  function(Stdio.Buffer, +  mapping(int:program(Object)): +  Object) decoder, +  mapping(int:program(Object))|void types) { +  if( contents=="" ) { value = 0.0; return this; } +  int(0..255) first = contents[0]; +  switch( first ) +  { +  // SpecialRealValues +  case 0b01000000: value = Math.inf; return this; +  case 0b01000001: value = -Math.inf; return this; +  case 0b01000010: value = Math.nan; return this; +  case 0b01000011: value = -0.0; return this; +  +  // ISO 6093 +  case 0b00000001: error("ISO 6093 NR1 not supported.\n"); +  case 0b00000010: error("ISO 6093 NR2 not supported.\n"); +  case 0b00000011: error("ISO 6093 NR3 not supported.\n"); +  } +  switch( first & 0xc0 ) +  { +  case 0x00: +  error("Unknown real coding.\n"); +  case 0x40: +  error("Unknown SpecialRealValues code.\n"); +  } +  +  int neg = first & 0b01000000; +  int base; +  switch(first & 0b00110000) +  { +  case 0b00000000: base = 2; break; +  case 0b00010000: base = 8; break; +  case 0b00100000: base = 16; break; +  default: error("Unknown real base.\n"); +  } +  +  int(0..3) scaling = [int(0..3)]((first & 0b00001100) >> 2); +  +  int exp; +  int num; +  switch(first & 0b00000011) +  { +  case 0b00: +  sscanf(contents, "%*1c%+1c%+"+(sizeof(contents)-2)+"c", exp, num); +  break; +  case 0b01: +  sscanf(contents, "%*1c%+2c%+"+(sizeof(contents)-3)+"c", exp, num); +  break; +  case 0b10: +  sscanf(contents, "%*1c%+3c%+"+(sizeof(contents)-4)+"c", exp, num); +  break; +  case 0b11: +  int e_size = contents[1]; +  int n_size = sizeof(contents)-2-e_size; +  sscanf(contents, "%*2c%+"+e_size+"c%+"+n_size+"c", exp, num); +  break; +  } +  +  int mantissa = num * (1<<scaling); +  if( neg ) mantissa = -mantissa; +  value = mantissa * pow((float)base, exp); +  +  return this; +  } +  +  protected string _sprintf(int t) +  { +  return t=='O' && sprintf("%O(%O)", this_program, value); +  } + } +    //! Bit string object   class BitString   {    inherit Object; -  constant tag = 3; +  int(1..) tag = 3;    constant type_name = "BIT STRING";       //! value of object    string(0..255) value;    -  int unused = 0; +  int(0..7) unused = 0;       this_program init(string(0..255) s)    {    value = s;    return this;    }    -  string(0..255) der_encode() +  string(0..255) get_der_content()    { -  return build_der([string(0..255)]sprintf("%c%s", unused, value)); +  return [string(0..255)]sprintf("%c%s", unused, value);    }       //! Set the bitstring value as a string with @expr{"1"@} and    //! @expr{"0"@}.    this_program set_from_ascii(string(0..255) s)    {    array v = array_sscanf(s, "%8b"*(sizeof(s)/8)+"%b"); -  v[-1] = v[-1]<<((-sizeof(s))%8); +  v[-1] = v[-1]<<[int(0..7)]((-sizeof(s))%8);    value = (string(0..255))v;    set_length(sizeof(s));    return this;    }    -  //! Sets the length of the bit string to @[len] number of bits. -  int set_length(int len) { +  //! Sets the length of the bit string to @[len] number of bits. Will +  //! only work correctly on strings longer than @[len] bits. +  this_program set_length(int len) {    if (len)    {    value = value[..(len + 7)/8]; -  unused = (- len) % 8; -  value = [string(0..255)]sprintf("%s%c", value[..<1], value[-1] -  & ({ 0xff, 0xfe, 0xfc, 0xf8, -  0xf0, 0xe0, 0xc0, 0x80 })[unused]); +  unused = [int(0..7)]((- len) % 8); +  value[-1] &= 256-(1<<unused);    } else {    unused = 0;    value = "";    } -  +  return this;    }       this_program decode_primitive(string(0..255) contents, -  function(ADT.struct, +  function(Stdio.Buffer,    mapping(int:program(Object)):    Object)|void decoder,    mapping(int:program(Object))|void types) { -  record_der_contents(contents); +     if (!sizeof(contents))    return 0; -  unused = contents[0]; +     -  if (unused >= 8) +  if (contents[0] >= 8)    return 0; -  +  +  unused = [int(0..7)]contents[0];    value = contents[1..]; -  +  +  // Unused bits should be zero. I can't find anything in X.690 that +  // explicitly states this though. +  if (sizeof(value) && unused && value[-1]&(1<<unused)-1) +  return 0; +     return this;    }    -  +  void begin_decode_constructed(string raw) +  { +  unused = 0; +  value = ""; +  } +  +  void decode_constructed_element(int i, object(this_program) e) +  { +  if( unused ) error("Adding to a non-aligned bit stream.\n"); +  value += e->value; +  unused = e->unused; +  +  // Unused bits should be zero. I can't find anything in X.690 that +  // explicitly states this though. +  if (sizeof(value) && unused && value[-1]&(1<<unused)-1) +  error("Non-zero padding bits.\n"); +  } +     protected string _sprintf(int t) { -  +  if(t!='O') return UNDEFINED; +  if(!value) return sprintf("%O(0)", this_program);    int size = sizeof(value)*8-unused; -  return t=='O' && sprintf("%O(%d %0"+size+"s)", this_program, size, +  if(!unused) return sprintf("%O(%d %O)", this_program, size, value); +  return sprintf("%O(%d %0"+size+"s)", this_program, size,    ([object(Gmp.mpz)](Gmp.mpz(value, 256) >> unused))    ->digits(2));    }    - #ifdef COMPATIBILITY -  __deprecated__ string debug_string() { -  return sprintf("BIT STRING (%d) %s", -  sizeof(value) * 8 - unused, -  ([object(Gmp.mpz)](Gmp.mpz(value, 256) >> unused)) -  ->digits(2)); +  array _encode() +  { +  return ({ cls, tag, value, unused });    } - #endif +  +  void _decode(array(int|string(8bit)) x) +  { +  cls = [int(0..3)]x[0]; +  tag = [int(1..)]x[1]; +  value = [string(8bit)]x[2]; +  unused = [int(0..7)]x[3];    } -  + }      //! Octet string object   class OctetString   {    inherit String; -  constant tag = 4; +  int(1..) tag = 4;    constant type_name = "OCTET STRING";   }      //! Null object   class Null   {    inherit Object; -  constant tag = 5; +  int(1..) tag = 5;    constant type_name = "NULL";    -  string(0..255) der_encode() { return build_der(""); } -  +     this_program decode_primitive(string(0..255) contents, -  function(ADT.struct, +  function(Stdio.Buffer,    mapping(int:program(Object)):    Object)|void decoder,    mapping(int:program(Object))|void types) { -  record_der_contents(contents); +     return !sizeof(contents) && this;    }    - #ifdef COMPATIBILITY -  __deprecated__ string debug_string() { return "NULL"; } - #endif +  array _encode() +  { +  return ({ cls, tag });    }    -  +  void _decode(array(int) x) +  { +  cls = [int(0..3)]x[0]; +  tag = [int(1..)]x[1]; +  } + } +    //! Object identifier object   class Identifier   {    inherit Object; -  constant tag = 6; +  int(1..) tag = 6;    constant type_name = "OBJECT IDENTIFIER";       //! value of object    array(int) id;       this_program init(int ... args) {    if ( (sizeof(args) < 2)    || (args[0] > 2)    || (args[1] >= ( (args[0] < 2) ? 40 : 176) ))    error( "Invalid object identifier.\n" );    id = args;    return this;    }    -  mixed _encode() { return id; } -  void _decode(array(int) data) { id=data; } -  +     //! Returns a new @[Identifier] object with @[args] appended to the    //! ID path.    this_program append(int ... args) {    return this_program(@id, @args);    }    -  string(0..255) der_encode() +  string(0..255) get_der_content()    { -  return build_der([string(0..255)]sprintf("%s%@s", +  return [string(0..255)]sprintf("%s%@s",    to_base_128(40 * id[0] + id[1]), -  map(id[2..], to_base_128))); +  map(id[2..], to_base_128));    }       this_program decode_primitive(string(0..255) contents, -  function(ADT.struct, +  function(Stdio.Buffer,    mapping(int:program(Object)):    Object)|void decoder,    mapping(int:program(Object))|void types) { -  record_der_contents(contents); -  +     if (contents[0] < 120)    id = ({ contents[0] / 40, contents[0] % 40 });    else    id = ({ 2, contents[0] - 80 });    int index = 1;    while(index < sizeof(contents))    {    int element = 0;    do {    element = element << 7 | (contents[index] & 0x7f);    } while(contents[index++] & 0x80);    id += ({ element });    }    return this;    }    -  +  protected mixed cast(string t) +  { +  switch(t) +  { +  case "string": return (array(string))id * "."; +  case "array" : return id+({}); +  default: return UNDEFINED; +  } +  } +     protected string _sprintf(int t) { -  return t=='O' && sprintf("%O(%s)", this_program, (array(string))id*"."); +  if(t!='O') return UNDEFINED; +  if(!id) return sprintf("%O(0)", this_program); +  return sprintf("%O(%s)", this_program, (array(string))id*".");    }    - #ifdef COMPATIBILITY -  __deprecated__ string debug_string() { -  return "IDENTIFIER " + (array(string)) id * "."; +  array _encode() +  { +  return ({ cls, tag, id });    } - #endif +     -  int __hash() +  void _decode(array(int|array(int)) x)    { -  +  if( sizeof(x)!=3 || intp(x[2]) ) +  id = [array(int)]x; // Compat with old codec that didn't save cls/tag. +  else +  { +  cls = [int(0..3)]x[0]; +  tag = [int(1..)]x[1]; +  id = [array(int)]x[2]; +  } +  } +  +  protected int __hash() +  {    return hash(get_der());    }    -  int `==(mixed other) { +  protected int(0..1) `==(mixed other) {    return (objectp(other) &&    (this_program == object_program(other)) &&    equal(id, ([object(Identifier)]other)->id));    } -  +  +  protected int(0..1) `<(mixed other) { +  if( !objectp(other) || +  (this_program != object_program(other)) ) +  return 0; +  array oid = ([object(Identifier)]other)->id; +  for( int i; i<min(sizeof(id),sizeof(oid)); i++ ) +  { +  if( id[i] < oid[i] ) return 1; +  if( id[i] > oid[i] ) return 0;    } -  +  return sizeof(id) < sizeof(oid); +  } + }      //! Checks if a Pike string can be encoded with UTF8. That is   //! always the case...   int(1..1) asn1_utf8_valid (string s)   {    return 1;   }      //! UTF8 string object   //!   //! Character set: ISO/IEC 10646-1 (compatible with Unicode).   //! - //! Variable width encoding, see rfc2279. + //! Variable width encoding, see @rfc{2279@}.   class UTF8String   {    inherit String; -  constant tag = 12; +  int(1..) tag = 12;    constant type_name = "UTF8String";    -  string(0..255) der_encode() +  string(0..255) get_der_content()    { -  return build_der(string_to_utf8(value)); +  return string_to_utf8(value);    }       this_program decode_primitive(string(0..255) contents, -  function(ADT.struct, +  function(Stdio.Buffer,    mapping(int:program(Object)):    Object)|void decoder,    mapping(int:program(Object))|void types) {    der = contents;    if (catch {    value = utf8_to_string(contents);    })    return 0;       return this;    }   }      //! Sequence object   class Sequence   {    inherit Compound; -  constant tag = 16; +  int(1..) tag = 16;    constant type_name = "SEQUENCE";    -  string(0..255) der_encode() +  string(0..255) get_der_content()    {    WERROR("ASN1.Sequence: elements = '%O\n", elements);    array(string) a = elements->get_der();    WERROR("ASN1.Sequence: der_encode(elements) = '%O\n", a); -  return build_der([string(0..255)]`+("", @ a)); +  return [string(0..255)]`+("", @ a);    }       this_program decode_primitive(string(0..255) contents, -  function(ADT.struct, +  function(Stdio.Buffer,    mapping(int:program(Object)):    Object) decoder,    mapping(int:program(Object)) types) {    der = contents;    elements = ({}); -  ADT.struct struct = ADT.struct(contents); -  while (!struct->is_empty()) { -  elements += ({ decoder(struct, types) }); +  Stdio.Buffer data = Stdio.Buffer(contents); +  while (sizeof(data)) { +  elements += ({ decoder(data, types) });    }    return this;    }   }      //! Set object   class Set   {    inherit Compound; -  constant tag = 17; +  int(1..) tag = 17;    constant type_name = "SET";    -  int(-1..1) compare_octet_strings(string r, string s) { +  int(-1..1) compare_octet_strings(string r, string s) +  { +  if (r == s) return 0; +     for(int i = 0;; i++) {    if (i == sizeof(r)) -  return (i = sizeof(s)) ? 0 : 1; +  return (i = sizeof(s)) ? 0 : -1;    if (i == sizeof(s)) -  return -1; -  if (r[i] < s[i]) +     return 1; -  else if (r[i] > s[i]) +  if (r[i] < s[i])    return -1; -  +  else if (r[i] > s[i]) +  return 1;    }    }    -  string der_encode() { +  string get_der_content() {    WERROR("asn1_set->der: elements = '%O\n", elements);    array(string) a = elements->get_der();    WERROR("asn1_set->der: der_encode(elements) = '%O\n", a); -  return build_der([string(0..255)] +  return [string(0..255)]    `+("", @[array(string)] -  Array.sort_array(a, compare_octet_strings))); +  Array.sort_array(a, compare_octet_strings));    }   }    - Regexp asn1_printable_invalid_chars = Regexp("([^-A-Za-z0-9 '()+,./:=?])"); + protected Regexp asn1_printable_invalid_chars = Regexp("([^-A-Za-z0-9 '()+,./:=?])");      //! Checks if a Pike string can be encoded as a @[PrintableString].   int(0..1) asn1_printable_valid (string s) {    if (global.String.width(s)!=8) return 0;    return !asn1_printable_invalid_chars->match(s);   }      //! PrintableString object   class PrintableString   {    inherit String; -  constant tag = 19; +  int(1..) tag = 19;    constant type_name = "PrintableString";   }    - Regexp asn1_teletex_invalid_chars = Regexp ("([\\\\{}\240®©¬¦\255Ð])"); -  +    //! - int(0..1) asn1_teletex_valid (string s) - { -  if (global.String.width(s)!=8) -  // T.61 encoding of wide strings not implemented. -  return 0; -  return !asn1_teletex_invalid_chars->match (s); - } -  - //! TeletexString object - //! - //! Avoid this one; it seems to be common that this type is used to - //! label strings encoded with the ISO 8859-1 character set (use - //! asn1_broken_teletex_string for that). From - //! http://www.mindspring.com/~asn1/nlsasn.htm: - //! - //! /.../ Types GeneralString, VideotexString, TeletexString - //! (T61String), and GraphicString exist in earlier versions - //! [pre-1994] of ASN.1. They are considered difficult to use - //! correctly by applications providing national language support. - //! Varying degrees of application support for T61String values seems - //! to be most common in older applications. Correct support is made - //! more difficult, as character values available in type T61String - //! have changed with the addition of new register entries from the - //! 1984 through 1997 versions. - //! - //! This implementation is based on the description of T.61 and T.51 - //! in "Some functions for representing T.61 characters from the - //! X.500 Directory Service in ISO 8859 terminals (Version 0.2. July - //! 1994.)" by Enrique Silvestre Mora (mora@@si.uji.es), Universitat - //! Jaume I, Spain, found in the package - //! ftp://pereiii.uji.es/pub/uji-ftp/unix/ldap/iso-t61.translation.tar.Z - //! - //! The translation is only complete for 8-bit latin 1 strings. It - //! encodes strictly to T.61, but decodes from the superset T.51. - //! - //! @note - //! CCITT Recommendation T.61 is also known as ISO-IR 103:1985 - //! (graphic characters) and ISO-IR 106:1985 and ISO-IR 107:1985 - //! (control characters). - //! - //! @seealso - //! @[Charset] - class TeletexString - { -  inherit String; -  constant tag = 20; -  constant type_name = "TeletexString"; // Alias: T61String -  - #define ENC_ERR(char) char - #define DEC_ERR(str) str - #define DEC_COMB_MARK "\300" -  - #define GR(char) "\301" char /* Combining grave accent */ - #define AC(char) "\302" char /* Combining acute accent */ - #define CI(char) "\303" char /* Combining circumflex accent */ - #define TI(char) "\304" char /* Combining tilde */ - #define MA(char) "\305" char /* Combining macron */ - #define BR(char) "\306" char /* Combining breve */ - #define DA(char) "\307" char /* Combining dot above */ - #define DI(char) "\310" char /* Combining diaeresis */ - #define RA(char) "\312" char /* Combining ring above */ - #define CE(char) "\313" char /* Combining cedilla */ - #define UN(char) "\314" char /* Combining underscore (note 6) */ - #define DO(char) "\315" char /* Combining double acute accent */ - #define OG(char) "\316" char /* Combining ogonek */ - #define CA(char) "\317" char /* Combining caron */ -  -  constant encode_from = ({ -  /*"#", "$",*/ "¤", // Note 3 -  "\\", "{", "}", // Note 7 -  "\240", // No-break space (note 7) -  "×", // Multiplication sign -  "÷", // Division sign -  "¹", // Superscript one -  "®", // Registered sign (note 7) -  "©", // Copyright sign (note 7) -  "¬", // Not sign (note 7) -  "¦", // Broken bar (note 7) -  "Æ", // Latin capital ligature ae -  "ª", // Feminine ordinal indicator -  "Ø", // Latin capital letter o with stroke -  "º", // Masculine ordinal indicator -  "Þ", // Latin capital letter thorn -  "æ", // Latin small ligature ae -  "ð", // Latin small letter eth -  "ø", // Latin small letter o with stroke -  "ß", // Latin small letter sharp s -  "þ", // Latin small letter thorn -  "\255", // Soft hyphen (note 7) -  "Ð", // Latin capital letter eth (no equivalent) -  // Combinations -  "^", "`", "~", // Note 4 -  "´", "¨", "¯", "¸", -  "À", "Á", "Â", "Ã", "Ä", "Å", -  "à", "á", "â", "ã", "ä", "å", -  "Ç", -  "ç", -  "È", "É", "Ê", "Ë", -  "è", "é", "ê", "ë", -  "Ì", "Í", "Î", "Ï", -  "ì", "í", "î", "ï", -  "Ñ", -  "ñ", -  "Ò", "Ó", "Ô", "Õ", "Ö", -  "ò", "ó", "ô", "õ", "ö", -  "Ù", "Ú", "Û", "Ü", -  "ù", "ú", "û", "ü", -  "Ý", -  "ý", -  }); -  -  constant encode_to = ({ -  /*"#", "$",*/ "\250", // Note 3 -  ENC_ERR("\\"), ENC_ERR("{"), ENC_ERR("}"), // Note 7 -  ENC_ERR("\240"), // No-break space (note 7) -  "\264", // Multiplication sign -  "\270", // Division sign -  "\321", // Superscript one -  ENC_ERR("®"), // Registered sign (note 7) -  ENC_ERR("©"), // Copyright sign (note 7) -  ENC_ERR("¬"), // Not sign (note 7) -  ENC_ERR("¦"), // Broken bar (note 7) -  "\341", // Latin capital ligature ae -  "\343", // Feminine ordinal indicator -  "\351", // Latin capital letter o with stroke -  "\353", // Masculine ordinal indicator -  "\354", // Latin capital letter thorn -  "\361", // Latin small ligature ae -  "\363", // Latin small letter eth -  "\371", // Latin small letter o with stroke -  "\373", // Latin small letter sharp s -  "\374", // Latin small letter thorn -  ENC_ERR("\255"), // Soft hyphen (note 7) -  ENC_ERR("Ð"), // Latin capital letter eth (no equivalent) -  // Combinations -  CI(" "), GR(" "), TI(" "), // Note 4 -  AC(" "), DI(" "), MA(" "), CE(" "), -  GR("A"), AC("A"), CI("A"), TI("A"), DI("A"), RA("A"), -  GR("a"), AC("a"), CI("a"), TI("a"), DI("a"), RA("a"), -  CE("C"), -  CE("c"), -  GR("E"), AC("E"), CI("E"), DI("E"), -  GR("e"), AC("e"), CI("e"), DI("e"), -  GR("I"), AC("I"), CI("I"), DI("I"), -  GR("i"), AC("i"), CI("i"), DI("i"), -  TI("N"), -  TI("n"), -  GR("O"), AC("O"), CI("O"), TI("O"), DI("O"), -  GR("o"), AC("o"), CI("o"), TI("o"), DI("o"), -  GR("U"), AC("U"), CI("U"), DI("U"), -  GR("u"), AC("u"), CI("u"), DI("u"), -  GR("Y"), -  GR("y"), -  }); -  -  constant decode_from = ({ -  /*"#", "$",*/ "\244", "\246", "\250", // Note 3 -  /*"^", "`", "~",*/ // Note 4 -  "\251", // Left single quotation mark (note 7) -  "\252", // Left double quotation mark (note 7) -  "\254", // Leftwards arrow (note 7) -  "\255", // Upwards arrow (note 7) -  "\256", // Rightwards arrow (note 7) -  "\257", // Downwards arrow (note 7) -  "\264", // Multiplication sign -  "\270", // Division sign -  "\271", // Right single quotation mark (note 7) -  "\272", // Right double quotation mark (note 7) -  "\300", // Note 5 -  GR(""), // Combining grave accent -  AC(""), // Combining acute accent -  CI(""), // Combining circumflex accent -  TI(""), // Combining tilde -  MA(""), // Combining macron -  BR(""), // Combining breve -  DA(""), // Combining dot above -  DI(""), // Combining diaeresis -  "\311", // Note 5 -  RA(""), // Combining ring above -  CE(""), // Combining cedilla -  UN(""), // Combining underscore (note 6) -  DO(""), // Combining double acute accent -  OG(""), // Combining ogonek -  CA(""), // Combining caron -  "\320", // Em dash (note 7) -  "\321", // Superscript one -  "\322", // Registered sign (note 7) -  "\323", // Copyright sign (note 7) -  "\324", // Trade mark sign (note 7) -  "\325", // Eighth note (note 7) -  "\326", // Not sign (note 7) -  "\327", // Broken bar (note 7) -  "\330", "\331", "\332", "\333", // Note 2 -  "\334", // Vulgar fraction one eighth (note 7) -  "\335", // Vulgar fraction three eighths (note 7) -  "\336", // Vulgar fraction five eighths (note 7) -  "\337", // Vulgar fraction seven eighths (note 7) -  "\340", // Ohm sign -  "\341", // Latin capital ligature ae -  "\342", // Latin capital letter d with stroke -  "\343", // Feminine ordinal indicator -  "\344", // Latin capital letter h with stroke -  "\345", // Note 2 -  "\346", // Latin capital ligature ij -  "\347", // Latin capital letter l with middle dot -  "\350", // Latin capital letter l with stroke -  "\351", // Latin capital letter o with stroke -  "\352", // Latin capital ligature oe -  "\353", // Masculine ordinal indicator -  "\354", // Latin capital letter thorn -  "\355", // Latin capital letter t with stroke -  "\356", // Latin capital letter eng -  "\357", // Latin small letter n preceded by apostrophe -  "\360", // Latin small letter kra -  "\361", // Latin small ligature ae -  "\362", // Latin small letter d with stroke -  "\363", // Latin small letter eth -  "\364", // Latin small letter h with stroke -  "\365", // Latin small letter dotless i -  "\366", // Latin small ligature ij -  "\367", // Latin small letter l with middle dot -  "\370", // Latin small letter l with stroke -  "\371", // Latin small letter o with stroke -  "\372", // Latin small ligature oe -  "\373", // Latin small letter sharp s -  "\374", // Latin small letter thorn -  "\375", // Latin small letter t with stroke -  "\376", // Latin small letter eng -  "\377", // Soft hyphen (note 7) -  }); -  -  constant decode_to = ({ -  /*"#", "$",*/ "$", "#", "\244", // Note 3 -  /*"^", "`", "~",*/ // Note 4 -  DEC_ERR("\251"), // Left single quotation mark (note 7) -  DEC_ERR("\252"), // Left double quotation mark (note 7) -  DEC_ERR("\254"), // Leftwards arrow (note 7) -  DEC_ERR("\255"), // Upwards arrow (note 7) -  DEC_ERR("\256"), // Rightwards arrow (note 7) -  DEC_ERR("\257"), // Downwards arrow (note 7) -  "×", // Multiplication sign -  "÷", // Division sign -  DEC_ERR("\271"), // Right single quotation mark (note 7) -  DEC_ERR("\272"), // Right double quotation mark (note 7) -  DEC_ERR("\300"), // Note 5 -  DEC_COMB_MARK GR(""), // Combining grave accent -  DEC_COMB_MARK AC(""), // Combining acute accent -  DEC_COMB_MARK CI(""), // Combining circumflex accent -  DEC_COMB_MARK TI(""), // Combining tilde -  DEC_COMB_MARK MA(""), // Combining macron -  DEC_COMB_MARK BR(""), // Combining breve -  DEC_COMB_MARK DA(""), // Combining dot above -  DEC_COMB_MARK DI(""), // Combining diaeresis -  DEC_ERR("\311"), // Note 5 -  DEC_COMB_MARK RA(""), // Combining ring above -  DEC_COMB_MARK CE(""), // Combining cedilla -  DEC_COMB_MARK UN(""), // Combining underscore (note 6) -  DEC_COMB_MARK DO(""), // Combining double acute accent -  DEC_COMB_MARK OG(""), // Combining ogonek -  DEC_COMB_MARK CA(""), // Combining caron -  DEC_ERR("\320"), // Em dash (note 7) -  "¹", // Superscript one -  "®", // Registered sign (note 7) -  "©", // Copyright sign (note 7) -  DEC_ERR("\324"), // Trade mark sign (note 7) -  DEC_ERR("\325"), // Eighth note (note 7) -  "¬", // Not sign (note 7) -  "¦", // Broken bar (note 7) -  DEC_ERR("\330"), DEC_ERR("\331"), DEC_ERR("\332"), DEC_ERR("\333"), // Note 2 -  DEC_ERR("\334"), // Vulgar fraction one eighth (note 7) -  DEC_ERR("\335"), // Vulgar fraction three eighths (note 7) -  DEC_ERR("\336"), // Vulgar fraction five eighths (note 7) -  DEC_ERR("\337"), // Vulgar fraction seven eighths (note 7) -  DEC_ERR("\340"), // Ohm sign -  "Æ", // Latin capital ligature ae -  DEC_ERR("\342"), // Latin capital letter d with stroke -  "ª", // Feminine ordinal indicator -  DEC_ERR("\344"), // Latin capital letter h with stroke -  DEC_ERR("\345"), // Note 2 -  DEC_ERR("\346"), // Latin capital ligature ij -  DEC_ERR("\347"), // Latin capital letter l with middle dot -  DEC_ERR("\350"), // Latin capital letter l with stroke -  "Ø", // Latin capital letter o with stroke -  DEC_ERR("\352"), // Latin capital ligature oe -  "º", // Masculine ordinal indicator -  "Þ", // Latin capital letter thorn -  DEC_ERR("\355"), // Latin capital letter t with stroke -  DEC_ERR("\356"), // Latin capital letter eng -  DEC_ERR("\357"), // Latin small letter n preceded by apostrophe -  DEC_ERR("\360"), // Latin small letter kra -  "æ", // Latin small ligature ae -  DEC_ERR("\362"), // Latin small letter d with stroke -  "ð", // Latin small letter eth -  DEC_ERR("\364"), // Latin small letter h with stroke -  DEC_ERR("\365"), // Latin small letter dotless i -  DEC_ERR("\366"), // Latin small ligature ij -  DEC_ERR("\367"), // Latin small letter l with middle dot -  DEC_ERR("\370"), // Latin small letter l with stroke -  "ø", // Latin small letter o with stroke -  DEC_ERR("\372"), // Latin small ligature oe -  "ß", // Latin small letter sharp s -  "þ", // Latin small letter thorn -  DEC_ERR("\375"), // Latin small letter t with stroke -  DEC_ERR("\376"), // Latin small letter eng -  "\255", // Soft hyphen (note 7) -  }); -  -  constant decode_comb = ([ -  GR(" "): "`", -  AC(" "): "´", -  CI(" "): "^", -  TI(" "): "~", -  DI(" "): "¨", -  // RA(" "): DEC_ERR(RA(" ")), -  MA(" "): "¯", -  // BR(" "): DEC_ERR(BR(" ")), -  // DA(" "): DEC_ERR(DA(" ")), -  CE(" "): "¸", -  // DO(" "): DEC_ERR(DO(" ")), -  // OG(" "): DEC_ERR(OG(" ")), -  // CA(" "): DEC_ERR(CA(" ")), -  GR("A"): "À", AC("A"): "Á", CI("A"): "Â", TI("A"): "Ã", DI("A"): "Ä", RA("A"): "Å", -  GR("a"): "à", AC("a"): "á", CI("a"): "â", TI("a"): "ã", DI("a"): "ä", RA("a"): "å", -  CE("C"): "Ç", -  CE("c"): "ç", -  GR("E"): "È", AC("E"): "É", CI("E"): "Ê", DI("E"): "Ë", -  GR("e"): "è", AC("e"): "é", CI("e"): "ê", DI("e"): "ë", -  GR("I"): "Ì", AC("I"): "Í", CI("I"): "Î", DI("I"): "Ï", -  GR("i"): "ì", AC("i"): "í", CI("i"): "î", DI("i"): "ï", -  TI("N"): "Ñ", -  TI("n"): "ñ", -  GR("O"): "Ò", AC("O"): "Ó", CI("O"): "Ô", TI("O"): "Õ", DI("O"): "Ö", -  GR("o"): "ò", AC("o"): "ó", CI("o"): "ô", TI("o"): "õ", DI("o"): "ö", -  GR("U"): "Ù", AC("U"): "Ú", CI("U"): "Û", DI("U"): "Ü", -  GR("u"): "ù", AC("u"): "ú", CI("u"): "û", DI("u"): "ü", -  GR("Y"): "Ý", -  GR("y"): "ý", -  ]); -  -  /* Notes from Moras paper: -  -  (1) All characters in 0xC0-0xCF are non-spacing characters. They are -  all diacritical marks. To be represented stand-alone, they need to -  be followed by a SPACE (0x20). They can appear, also, before -  letters if the couple is one of the defined combinations. -  -  (2) Reserved for future standardization. -  -  (3) Current terminals may send and receive 0xA6 and 0xA4 for the NUMBER -  SIGN and DOLLAR SIGN, respectively. When receiving codes 0x23 and -  0x24, they may interpret them as NUMBER SIGN and CURRENCY SIGN, -  respectively. Future applications should code the NUMBER SIGN, -  DOLLAR SIGN and CURRENCY SIGN as 0x23, 0x24 and 0xA8, respectively. -  -  (4) Terminals should send only the codes 0xC1, 0xC3 and 0xC4, followed -  by SPACE (0x20) for stand-alone GRAVE ACCENT, CIRCUMFLEX ACCENT and -  TILDE, respectively. Nevertheless the terminal shall interpret the -  codes 0x60, 0x5E and 0x7E as GRAVE, CIRCUMFLEX and TILDE, -  respectively. -  -  (5) This code position is reserved and shall not be used. -  -  (6) It is recommended to implement the "underline" function by means of -  the control function SGR(4) instead of the "non-spacing underline" -  graphic character. -  -  (7) Not used in current teletex service (Recommendation T.61). -  */ -  - #undef GR - #undef AC - #undef CI - #undef TI - #undef MA - #undef BR - #undef DA - #undef DI - #undef RA - #undef CE - #undef UN - #undef DO - #undef OG - #undef CA -  -  string(0..255) der_encode() -  { -  return build_der([string(0..255)]replace(value, [array(string)]encode_from, -  [array(string(0..255))]encode_to)); -  } -  -  this_program decode_primitive (string(0..255) contents, -  function(ADT.struct, -  mapping(int:program(Object)): -  Object)|void decoder, -  mapping(int:program(Object))|void types) { -  der = contents; -  -  array(string) parts = -  replace (contents, [array(string)]decode_from, -  [array(string)]decode_to) / DEC_COMB_MARK; -  value = parts[0]; -  foreach (parts[1..], string part) -  value += (decode_comb[part[..1]] || DEC_ERR(part[..1])) + part[2..]; -  -  return this; -  } -  - #undef ENC_ERR - #undef DEC_ERR - #undef DEC_COMB_MARK - } -  - //! +    int(0..1) asn1_broken_teletex_valid (string s)   {    return global.String.width(s)==8;   }      //! (broken) TeletexString object   //!   //! Encodes and decodes latin1, but labels it TeletexString, as is   //! common in many broken programs (e.g. Netscape 4.0X).   class BrokenTeletexString   {    inherit String; -  constant tag = 20; +  int(0..) tag = 20;    constant type_name = "TeletexString"; // Alias: T61String   }    - Regexp asn1_IA5_invalid_chars = Regexp ("([\200-\377])"); + protected Regexp asn1_IA5_invalid_chars = Regexp ("([\200-\377])");      //!   int(0..1) asn1_IA5_valid (string s)   {    if (global.String.width(s)!=8) return 0;    return !asn1_printable_invalid_chars->match (s);   }      //! IA5 String object   //!   //! Character set: ASCII. Fixed width encoding with 1 octet per   //! character.   class IA5String   {    inherit String; -  constant tag = 22; +  int(1..) tag = 22;    constant type_name = "IA5STRING";   }      //!   class VisibleString {    inherit String; -  constant tag = 26; +  int(1..) tag = 26;    constant type_name = "VisibleString";   }    -  + //! UTCTime   //! -  + //! @rfc{2459:4.1.2.5.1@}   class UTC   {    inherit String; -  constant tag = 23; +  int(1..) tag = 23;    constant type_name = "UTCTime";    -  +  this_program init(int|string|Calendar.ISO_UTC.Second t) +  { +  if(intp(t)) +  set_posix([int]t); +  else if(objectp(t)) +  set_posix([object(Calendar.ISO_UTC.Second)]t); +  else +  value = [string]t; +  } +     this_program set_posix(int t)    { -  object second = Calendar.ISO.Second(t); +  return set_posix(Calendar.ISO_UTC.Second(t)); +  }    -  // FIXME: What is this based on? +  //! +  variant this_program set_posix(Calendar.ISO_UTC.Second second) +  { +  +  // RFC 2459 4.1.2.5.1: +  // +  // Where YY is greater than or equal to 50, the year shall be +  // interpreted as 19YY; and +  // +  // Where YY is less than 50, the year shall be interpreted as 20YY.    if (second->year_no() >= 2050)    error( "Times later than 2049 not supported.\n" ); -  +  if (second->year_no() < 1950) +  error( "Times earlier than 1950 not supported.\n" );       value = sprintf("%02d%02d%02d%02d%02d%02dZ",    [int]second->year_no() % 100,    [int]second->month_no(),    [int]second->month_day(),    [int]second->hour_no(),    [int]second->minute_no(),    [int]second->second_no());    return this;    }    -  +  //!    int get_posix()    {    if( !value || sizeof(value)!=13 ) error("Data not UTC date string.\n");       array t = (array(int))(value[..<1]/2);    if(t[0]>49)    t[0]+=1900;    else    t[0]+=2000;    -  return [int]Calendar.ISO.Second(@t)->unix_time(); +  return [int]Calendar.ISO_UTC.Second(@t)->unix_time();    }   }    -  + class GeneralizedTime + { +  inherit UTC; +  int(1..) tag = 24; +  constant type_name = "GeneralizedTime"; +  +  // We are currently not doing any management of fractions. X690 +  // states that fractions shouldn't have trailing zeroes, and should +  // be completely removed int the ".0" case. +  +  this_program set_posix(int t) +  { +  return set_posix(Calendar.ISO_UTC.Second(t)); +  } +     //! -  +  variant this_program set_posix(Calendar.ISO_UTC.Second second) +  { +  value = sprintf("%04d%02d%02d%02d%02d%02dZ", +  [int]second->year_no(), +  [int]second->month_no(), +  [int]second->month_day(), +  [int]second->hour_no(), +  [int]second->minute_no(), +  [int]second->second_no()); +  return this; +  } +  +  //! +  int get_posix() +  { +  if( !value || sizeof(value) < 15 ) +  error("Data not GeneralizedTime date string.\n"); +  array(int) t = array_sscanf(value, "%4d%2d%2d%2d%2d%2d"); +  return [int]Calendar.ISO_UTC.Second(@t)->unix_time(); +  } + } +  + //!   int(0..0) asn1_universal_valid (string s)   {    return 0; s; // Return 0 since the UniversalString isn't implemented.   }      //! Universal String object   //!   //! Character set: ISO/IEC 10646-1 (compatible with Unicode).   //! Fixed width encoding with 4 octets per character.   //!   //! @fixme   //! The encoding is very likely UCS-4, but that's not yet verified.   class UniversalString   {    inherit OctetString; -  constant tag = 28; +  int(1..) tag = 28;    constant type_name = "UniversalString";    -  string der_encode() { +  string get_der_content() {    error( "Encoding not implemented\n" );    }       this_program decode_primitive (string contents, -  function(ADT.struct, +  function(Stdio.Buffer,    mapping(int:program(Object)):    Object)|void decoder,    mapping(int:program(Object))|void types) {    error( "Decoding not implemented\n" ); contents;    }   }      //!   int(0..1) asn1_bmp_valid (string s)   {
pike.git/lib/modules/Standards.pmod/ASN1.pmod/Types.pmod:1233:      //! BMP String object   //!   //! Character set: ISO/IEC 10646-1 (compatible with Unicode).   //! Fixed width encoding with 2 octets per character.   //!   //! FIXME: The encoding is very likely UCS-2, but that's not yet verified.   class BMPString   {    inherit OctetString; -  constant tag = 30; +  int(1..) tag = 30;    constant type_name = "BMPString";    -  string der_encode() { -  return build_der (string_to_unicode (value)); +  string get_der_content() { +  return string_to_unicode (value);    }       this_program decode_primitive (string(0..255) contents, -  function(ADT.struct, +  function(Stdio.Buffer,    mapping(int:program(Object)):    Object)|void decoder,    mapping(int:program(Object))|void types) {    der = contents;    value = unicode_to_string (contents);    return this;    }   }      //! Meta-instances handle a particular explicit tag and set of types.   //! Once cloned this object works as a factory for Compound objects   //! with the cls and tag that the meta object was initialized with.   //!   //! @example   //! MetaExplicit m = MetaExplicit(1,2);   //! Compound c = m(Integer(3));   class MetaExplicit   { -  int real_tag; -  int real_cls; +  int(0..3) real_cls; +  int(1..) real_tag;       mapping(int:program(Object)) valid_types;       class `() {    inherit Compound;    constant type_name = "EXPLICIT";    constant constructed = 1;    -  int get_tag() { return real_tag; } -  int get_cls() { return real_cls; } +  int(0..3) get_cls() { return real_cls; } +  int(1..) get_tag() { return real_tag; }       Object contents;    -  +  array(Object) `elements() { return contents ? ({ contents }) : ({}); } +  void `elements=(array(Object) args) +  { +  if (sizeof(args) > 1) error("Invalid number of elements.\n"); +  contents = sizeof(args) && args[0]; +  } +  +  int `combined_tag() { +  return get_combined_tag(); +  } +     this_program init(Object o) {    contents = o;    return this;    }    -  string der_encode() { +  string get_der_content() {    WERROR("asn1_explicit->der: contents = '%O\n", contents); -  return build_der(contents->get_der()); +  return contents->get_der();    }       this_program decode_constructed_element(int i, Object e) {    if (i)    error("Unexpected index!\n");    contents = e;    return this;    }    -  this_program end_decode_constructed(int length) { -  if (length != 1) -  error("length != 1!\n"); -  return this; -  } -  +     mapping(int:program(Object)) element_types(int i,    mapping(int:program(Object)) types) {    if (i)    error("Unexpected index!\n");    return valid_types || types;    }       protected string _sprintf(int t) { -  return t=='O' && sprintf("%O(%s %d %O)", this_program, type_name, +  if (t != 'O') return UNDEFINED; +  if ((real_cls == 2) && (real_tag <= 3)) { +  // Special case for the convenience variants further below. +  return sprintf("%O.TaggedType%d(%O)", +  global::this, real_tag, contents); +  } +  return sprintf("%O(%s %d %O)", this_program, type_name,    real_tag, contents);    }    - #ifdef COMPATIBILITY -  __deprecated__ string debug_string() { -  return type_name + "[" + (int) real_tag + "]"; +  array _encode() +  { +  return ({ real_cls, real_tag, contents });    } - #endif +  +  void _decode(array(int|Object) x) +  { +  real_cls = [int(0..3)]x[0]; +  real_tag = [int(1..)]x[1]; +  contents = [object(Object)]x[2];    } -  +  }       //! -  void create(int cls, int tag, mapping(int:program(Object))|void types) { +  protected void create(int(0..3) cls, int(1..) tag, +  mapping(int:program(Object))|void types) {    real_cls = cls;    real_tag = tag;    valid_types = types;    } -  +  +  array _encode() +  { +  return ({ real_cls, real_tag, valid_types });    }    -  +  void _decode(array(int|mapping(int:program(Object))) x) +  { +  real_cls = [int(0..3)]x[0]; +  real_tag = [int(1..)]x[1]; +  valid_types = [mapping(int:program(Object))]x[2]; +  } + }    - #ifdef COMPATIBILITY - constant meta_explicit = MetaExplicit; - constant asn1_object = Object; - constant asn1_compound = Compound; - constant asn1_string = String; - constant asn1_boolean = Boolean; - constant asn1_integer = Integer; - constant asn1_enumerated = Enumerated; - constant asn1_bit_string = BitString; - constant asn1_octet_string = OctetString; - constant asn1_null = Null; - constant asn1_identifier = Identifier; - constant asn1_utf8_string = UTF8String; - constant asn1_sequence = Sequence; - constant asn1_set = Set; - constant asn1_printable_string = PrintableString; - constant asn1_teletex_string = TeletexString; - constant asn1_broken_teletex_string = BrokenTeletexString; - constant asn1_IA5_string = IA5String; - constant asn1_utc = UTC; - constant asn1_universal_string = UniversalString; - constant asn1_bmp_string = BMPString; - #endif + //! Some common explicit tags for convenience. + //! + //! These are typically used to indicate which + //! of several optional fields are present. + //! + //! @example + //! Eg @rfc{5915:3@}: + //! @code + //! ECPrivateKey ::= SEQUENCE { + //! version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), + //! privateKey OCTET STRING, + //! parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, + //! publicKey [1] BIT STRING OPTIONAL + //! } + //! @endcode + //! The presence of the fields @tt{parameters@} and @tt{publicKey@} above + //! are indicated with @[TaggedType0] and @[TaggedType1] respectively. + MetaExplicit TaggedType0 = MetaExplicit(2, 0); + MetaExplicit TaggedType1 = MetaExplicit(2, 1); + MetaExplicit TaggedType2 = MetaExplicit(2, 2); + MetaExplicit TaggedType3 = MetaExplicit(2, 3);