6e91d92002-12-05H. William Welliver III //! Encodes various asn.1 objects according to the Distinguished //! Encoding Rules (DER)
a580e12000-09-27Fredrik Hübinette (Hubbe) #pike __REAL_VERSION__
4e151b2008-05-02Martin Nilsson #pragma strict_types
a20af62000-09-26Fredrik Hübinette (Hubbe) 
3e031f1998-06-13Niels Möller #if 0 #define WERROR werror #else
fa323d2004-02-29Martin Nilsson #define WERROR(x ...)
3e031f1998-06-13Niels Möller #endif
1ec5d61999-03-22Niels Möller 
3980c72003-01-26Martin Nilsson // Helper functions
1ec5d61999-03-22Niels Möller 
53f1e62014-06-26Martin Nilsson //! Combines tag and class to a single integer, for internal uses.
17e7422003-01-26Martin Nilsson //!
6e91d92002-12-05H. William Welliver III //! @param cls
240d3e2014-06-10Martin Nilsson //! ASN1 type class (0..3).
6e91d92002-12-05H. William Welliver III //! @param tag
240d3e2014-06-10Martin Nilsson //! ASN1 type tag (1..).
6e91d92002-12-05H. William Welliver III //! @returns
240d3e2014-06-10Martin Nilsson //! The combined tag.
17e7422003-01-26Martin Nilsson //! @seealso
53f1e62014-06-26Martin Nilsson //! @[extract_tag], @[extract_cls]
e04d3b2015-09-26Martin Nilsson int(4..) make_combined_tag(int(0..3) cls, int(1..) tag) { return [int(4..)](tag << 2 | cls); }
1ec5d61999-03-22Niels Möller 
240d3e2014-06-10Martin Nilsson //! Extract ASN1 type tag from a combined tag.
17e7422003-01-26Martin Nilsson //! @seealso
53f1e62014-06-26Martin Nilsson //! @[make_combined_tag]
e04d3b2015-09-26Martin Nilsson int(0..) extract_tag(int(0..) i) { return i >> 2; }
6e91d92002-12-05H. William Welliver III 
240d3e2014-06-10Martin Nilsson //! Extract ASN1 type class from a combined tag.
17e7422003-01-26Martin Nilsson //! @seealso
53f1e62014-06-26Martin Nilsson //! @[make_combined_tag]
e04d3b2015-09-26Martin Nilsson int(0..3) extract_cls(int(0..) i) { return [int(0..3)](i & 3); }
1ec5d61999-03-22Niels Möller 
3980c72003-01-26Martin Nilsson  // Class definitions
e6945d2014-08-24Martin Nilsson #define CODEC(X) \ array _encode() { return ({ cls, tag, value }); } \ void _decode(array(X) x) { [ cls, tag, value ] = x; }
3980c72003-01-26Martin Nilsson //! Generic, abstract base class for ASN1 data types. class Object
3e031f1998-06-13Niels Möller {
e04d3b2015-09-26Martin Nilsson  int(0..3) cls = 0; int(1..) tag = 0;
3e031f1998-06-13Niels Möller  constant constructed = 0;
8856fc2014-02-21Henrik Grubbström (Grubba)  constant type_name = "";
775a1d2015-03-05Martin Nilsson  protected string(8bit) get_der_content()
8856fc2014-02-21Henrik Grubbström (Grubba)  { return ""; }
3980c72003-01-26Martin Nilsson  //! Get the class of this object. //! //! @returns //! The class of this object.
e04d3b2015-09-26Martin Nilsson  int(0..3) get_cls() { return cls; }
6e91d92002-12-05H. William Welliver III 
3980c72003-01-26Martin Nilsson  //! Get the tag for this object. //! //! @returns //! The tag for this object.
e04d3b2015-09-26Martin Nilsson  int(1..) get_tag() { return tag; }
6e91d92002-12-05H. William Welliver III 
3980c72003-01-26Martin Nilsson  //! Get the combined tag (tag + class) for this object. //! //! @returns //! the combined tag header
e04d3b2015-09-26Martin Nilsson  int(1..) get_combined_tag() {
8c92912014-01-19Henrik Grubbström (Grubba)  return make_combined_tag(get_cls(), get_tag());
3980c72003-01-26Martin Nilsson  }
17e7422003-01-26Martin Nilsson 
775a1d2015-03-05Martin Nilsson  protected string(0..255) der;
17e7422003-01-26Martin Nilsson  // Should be overridden by subclasses
12e4902008-04-22Henrik Grubbström (Grubba)  this_program decode_primitive(string contents,
cb65012014-10-01Martin Nilsson  function(Stdio.Buffer,
12e4902008-04-22Henrik Grubbström (Grubba)  mapping(int:program(Object)): Object) decoder, mapping(int:program(Object)) types);
842b3e2014-06-21Martin Nilsson  void begin_decode_constructed(string raw); void decode_constructed_element(int i, object e);
3e031f1998-06-13Niels Möller 
c485aa2003-01-27Martin Nilsson  mapping(int:program(Object)) element_types(int i, mapping(int:program(Object)) types) {
7991f12008-01-05Henrik Grubbström (Grubba)  return types; i;
c485aa2003-01-27Martin Nilsson  }
7991f12008-01-05Henrik Grubbström (Grubba)  this_program init(mixed ... args) { return this; args; }
3980c72003-01-26Martin Nilsson 
240d3e2014-06-10Martin Nilsson  protected string(0..255) to_base_128(int n)
d74f032013-12-08Henrik Grubbström (Grubba)  {
240d3e2014-06-10Martin Nilsson  string(0..255) ret = [string(0..127)]sprintf("%c", n&0x7f); n >>= 7; while( n )
3e031f1998-06-13Niels Möller  {
240d3e2014-06-10Martin Nilsson  ret = [string(0..255)]sprintf("%c", (n&0x7f) | 0x80) + ret;
3980c72003-01-26Martin Nilsson  n >>= 7;
3e031f1998-06-13Niels Möller  }
240d3e2014-06-10Martin Nilsson  return ret;
3980c72003-01-26Martin Nilsson  }
17e7422003-01-26Martin Nilsson 
240d3e2014-06-10Martin Nilsson  protected string(0..255) encode_tag()
d74f032013-12-08Henrik Grubbström (Grubba)  {
38c87e2015-09-26Martin Nilsson  int(0..3) cls = get_cls(); int(1..) tag = get_tag();
3980c72003-01-26Martin Nilsson  if (tag < 31)
d74f032013-12-08Henrik Grubbström (Grubba)  return [string(0..255)]sprintf("%c", (cls << 6) | (constructed << 5) | tag);
3980c72003-01-26Martin Nilsson 
d74f032013-12-08Henrik Grubbström (Grubba)  return [string(0..255)]sprintf("%c%s", (cls << 6) | (constructed << 5) | 0x1f, to_base_128(tag) );
3980c72003-01-26Martin Nilsson  }
3e031f1998-06-13Niels Möller 
240d3e2014-06-10Martin Nilsson  protected string(0..255) encode_length(int|object len)
d74f032013-12-08Henrik Grubbström (Grubba)  {
3980c72003-01-26Martin Nilsson  if (len < 0x80)
d74f032013-12-08Henrik Grubbström (Grubba)  return [string(0..255)]sprintf("%c", len);
3980c72003-01-26Martin Nilsson  string s = Gmp.mpz(len)->digits(256); if (sizeof(s) >= 0x80) error("Max length exceeded.\n" );
d74f032013-12-08Henrik Grubbström (Grubba)  return [string(0..255)]sprintf("%c%s", sizeof(s) | 0x80, s);
3980c72003-01-26Martin Nilsson  }
17e7422003-01-26Martin Nilsson 
240d3e2014-06-10Martin Nilsson  protected string(0..255) build_der(string(0..255) contents)
d74f032013-12-08Henrik Grubbström (Grubba)  { string(0..255) data = encode_tag() + encode_length(sizeof(contents)) + contents;
fa323d2004-02-29Martin Nilsson  WERROR("build_der: %O\n", data);
3980c72003-01-26Martin Nilsson  return data; }
3e031f1998-06-13Niels Möller 
3980c72003-01-26Martin Nilsson  //! Get the DER encoded version of this object. //! //! @returns //! DER encoded representation of this object.
d74f032013-12-08Henrik Grubbström (Grubba)  string(0..255) get_der() {
4940182015-03-07Martin Nilsson  return build_der(get_der_content());
3980c72003-01-26Martin Nilsson  }
3e031f1998-06-13Niels Möller 
33dd5f2014-02-11Henrik Grubbström (Grubba)  protected void create(mixed ...args) {
fa323d2004-02-29Martin Nilsson  WERROR("asn1_object[%s]->create\n", type_name);
3980c72003-01-26Martin Nilsson  if (sizeof(args)) init(@args); }
3e031f1998-06-13Niels Möller }
6e91d92002-12-05H. William Welliver III //! Compound object primitive
3980c72003-01-26Martin Nilsson class Compound
3e031f1998-06-13Niels Möller {
3980c72003-01-26Martin Nilsson  inherit Object;
3e031f1998-06-13Niels Möller  constant constructed = 1;
6e91d92002-12-05H. William Welliver III 
53f1e62014-06-26Martin Nilsson  //! Contents of compound object.
0324132004-01-27Martin Nilsson  array(Object) elements = ({ });
3e031f1998-06-13Niels Möller 
3980c72003-01-26Martin Nilsson  this_program init(array args) {
fa323d2004-02-29Martin Nilsson  WERROR("asn1_compound[%s]->init(%O)\n", type_name, args);
3980c72003-01-26Martin Nilsson  foreach(args, mixed o) if (!objectp(o))
6725f52013-11-22Martin Nilsson  error( "Non-object argument %O\n", o );
009d772004-02-22Martin Nilsson  elements = [array(Object)]args;
fa323d2004-02-29Martin Nilsson  WERROR("asn1_compound: %O\n", elements);
563bd72004-01-11Martin Nilsson  return this;
3980c72003-01-26Martin Nilsson  }
3e031f1998-06-13Niels Möller 
842b3e2014-06-21Martin Nilsson  void begin_decode_constructed(string(0..255) raw) {
fa323d2004-02-29Martin Nilsson  WERROR("asn1_compound[%s]->begin_decode_constructed\n", type_name);
3980c72003-01-26Martin Nilsson  }
3e031f1998-06-13Niels Möller 
842b3e2014-06-21Martin Nilsson  void decode_constructed_element(int i, object e) {
fa323d2004-02-29Martin Nilsson  WERROR("asn1_compound[%s]->decode_constructed_element(%O)\n", type_name, e);
3980c72003-01-26Martin Nilsson  if (i != sizeof(elements)) error("Unexpected index!\n"); elements += ({ e }); }
17e7422003-01-26Martin Nilsson 
d01fbe2013-08-30Martin Nilsson  protected mixed `[](mixed index) { if( intp(index) ) return elements[index]; return ::`[]([string]index); } protected int _sizeof() { return sizeof(elements); }
36261f2013-03-01Chris Angelico  protected string _sprintf(int t,mapping(string:int)|void params) { if (params) ++params->indent; else params=([]);
eac0f72013-11-28Martin Nilsson  return t=='O' && sprintf("%O(%*O)", this_program, params, elements);
3980c72003-01-26Martin Nilsson  }
3e031f1998-06-13Niels Möller 
e6945d2014-08-24Martin Nilsson  array _encode() { return ({ cls, tag, elements }); } void _decode(array(int|array(Object)) x) {
e04d3b2015-09-26Martin Nilsson  cls = [int(0..3)]x[0]; tag = [int(1..)]x[1]; elements = [array(Object)]x[2];
e6945d2014-08-24Martin Nilsson  }
3e031f1998-06-13Niels Möller }
6e91d92002-12-05H. William Welliver III //! string object primitive
3980c72003-01-26Martin Nilsson class String
3e031f1998-06-13Niels Möller {
3980c72003-01-26Martin Nilsson  inherit Object;
6e91d92002-12-05H. William Welliver III 
3980c72003-01-26Martin Nilsson  //! value of object
3e031f1998-06-13Niels Möller  string value;
10d6cd2014-08-25Per Hedbor  //! @ignore
e6945d2014-08-24Martin Nilsson  CODEC(string);
10d6cd2014-08-25Per Hedbor  //! @endignore
3e031f1998-06-13Niels Möller 
d74f032013-12-08Henrik Grubbström (Grubba)  this_program init(string(0..255) s) {
3980c72003-01-26Martin Nilsson  value = s;
563bd72004-01-11Martin Nilsson  return this;
3980c72003-01-26Martin Nilsson  }
3e031f1998-06-13Niels Möller 
8856fc2014-02-21Henrik Grubbström (Grubba)  string(0..255) get_der_content() { return [string(0..255)]value;
3980c72003-01-26Martin Nilsson  }
3e031f1998-06-13Niels Möller 
d74f032013-12-08Henrik Grubbström (Grubba)  this_program decode_primitive(string(0..255) contents,
cb65012014-10-01Martin Nilsson  function(Stdio.Buffer,
12e4902008-04-22Henrik Grubbström (Grubba)  mapping(int:program(Object)): Object)|void decoder, mapping(int:program(Object))|void types) {
3980c72003-01-26Martin Nilsson  value = contents;
563bd72004-01-11Martin Nilsson  return this;
3980c72003-01-26Martin Nilsson  }
842b3e2014-06-21Martin Nilsson  void begin_decode_constructed(string raw) { value = ""; } void decode_constructed_element(int i, object(this_program) e) { value += e->value; }
9eaf1d2008-06-28Martin Nilsson  protected string _sprintf(int t) {
6725f52013-11-22Martin Nilsson  return t=='O' && sprintf("%O(%O)", this_program, value);
3980c72003-01-26Martin Nilsson  }
3e031f1998-06-13Niels Möller }
6e91d92002-12-05H. William Welliver III //! boolean object
3980c72003-01-26Martin Nilsson class Boolean
3e031f1998-06-13Niels Möller {
3980c72003-01-26Martin Nilsson  inherit Object;
e6945d2014-08-24Martin Nilsson 
e04d3b2015-09-26Martin Nilsson  int(1..) tag = 1;
3e031f1998-06-13Niels Möller  constant type_name = "BOOLEAN";
3980c72003-01-26Martin Nilsson  //! value of object
3e031f1998-06-13Niels Möller  int value;
10d6cd2014-08-25Per Hedbor  //! @ignore
e6945d2014-08-24Martin Nilsson  CODEC(int);
10d6cd2014-08-25Per Hedbor  //! @endignore
17e7422003-01-26Martin Nilsson 
12e4902008-04-22Henrik Grubbström (Grubba)  this_program init(int x) { value = x; return this; }
3e031f1998-06-13Niels Möller 
53f1e62014-06-26Martin Nilsson  // While every non-zero value is true, the canonical true is 0xff.
8856fc2014-02-21Henrik Grubbström (Grubba)  string(0..255) get_der_content() { return value ? "\377" : "\0";
12e4902008-04-22Henrik Grubbström (Grubba)  }
3980c72003-01-26Martin Nilsson 
d74f032013-12-08Henrik Grubbström (Grubba)  this_program decode_primitive(string(0..255) contents,
cb65012014-10-01Martin Nilsson  function(Stdio.Buffer,
12e4902008-04-22Henrik Grubbström (Grubba)  mapping(int:program(Object)): Object)|void decoder, mapping(int:program(Object))|void types) {
b935cc2014-06-10Martin Nilsson  if( contents=="" ) error("Illegal boolean value.\n");
12e4902008-04-22Henrik Grubbström (Grubba)  value = (contents != "\0");
563bd72004-01-11Martin Nilsson  return this;
3980c72003-01-26Martin Nilsson  }
9eaf1d2008-06-28Martin Nilsson  protected string _sprintf(int t) {
3980c72003-01-26Martin Nilsson  return t=='O' && sprintf("%O(%s)", this_program, (value?"TRUE":"FALSE")); }
3e031f1998-06-13Niels Möller }
3980c72003-01-26Martin Nilsson 
17e7422003-01-26Martin Nilsson //! Integer object
6e91d92002-12-05H. William Welliver III //! All integers are represented as bignums, for simplicity
3980c72003-01-26Martin Nilsson class Integer
3e031f1998-06-13Niels Möller {
3980c72003-01-26Martin Nilsson  inherit Object;
e6945d2014-08-24Martin Nilsson 
e04d3b2015-09-26Martin Nilsson  int(1..) tag = 2;
3e031f1998-06-13Niels Möller  constant type_name = "INTEGER";
17e7422003-01-26Martin Nilsson 
3980c72003-01-26Martin Nilsson  //! value of object Gmp.mpz value;
10d6cd2014-08-25Per Hedbor  //! @ignore
e6945d2014-08-24Martin Nilsson  CODEC(Gmp.mpz);
10d6cd2014-08-25Per Hedbor  //! @endignore
3e031f1998-06-13Niels Möller 
3980c72003-01-26Martin Nilsson  this_object init(int|object n) { value = Gmp.mpz(n);
fa323d2004-02-29Martin Nilsson  WERROR("i = %s\n", value->digits());
563bd72004-01-11Martin Nilsson  return this;
3980c72003-01-26Martin Nilsson  }
3e031f1998-06-13Niels Möller 
8856fc2014-02-21Henrik Grubbström (Grubba)  string(0..255) get_der_content()
d74f032013-12-08Henrik Grubbström (Grubba)  { string(0..255) s;
17e7422003-01-26Martin Nilsson 
3980c72003-01-26Martin Nilsson  if (value < 0)
3e031f1998-06-13Niels Möller  {
009d772004-02-22Martin Nilsson  Gmp.mpz n = [object(Gmp.mpz)](value + pow(256, ([object(Gmp.mpz)](- value))-> size(256)));
3980c72003-01-26Martin Nilsson  s = n->digits(256); if (!(s[0] & 0x80)) s = "\377" + s; } else { s = value->digits(256); if (s[0] & 0x80) s = "\0" + s;
3e031f1998-06-13Niels Möller  }
8856fc2014-02-21Henrik Grubbström (Grubba)  return s;
3980c72003-01-26Martin Nilsson  }
17e7422003-01-26Martin Nilsson 
d74f032013-12-08Henrik Grubbström (Grubba)  this_object decode_primitive(string(0..255) contents,
cb65012014-10-01Martin Nilsson  function(Stdio.Buffer,
12e4902008-04-22Henrik Grubbström (Grubba)  mapping(int:program(Object)): Object)|void decoder, mapping(int:program(Object))|void types) {
3980c72003-01-26Martin Nilsson  value = Gmp.mpz(contents, 256); if (contents[0] & 0x80) /* Negative */ value -= pow(256, sizeof(contents));
563bd72004-01-11Martin Nilsson  return this;
3980c72003-01-26Martin Nilsson  }
3e031f1998-06-13Niels Möller 
9eaf1d2008-06-28Martin Nilsson  protected string _sprintf(int t) {
26d0c42014-06-21Martin Nilsson  if(t!='O') return UNDEFINED; if(!value) return sprintf("%O(0)", this_program); return sprintf("%O(%d %s)", this_program, value->size(), value->digits());
3980c72003-01-26Martin Nilsson  }
3e031f1998-06-13Niels Möller }
6e91d92002-12-05H. William Welliver III  //! Enumerated object
3980c72003-01-26Martin Nilsson class Enumerated
47b5911999-02-19Niels Möller {
3980c72003-01-26Martin Nilsson  inherit Integer;
e04d3b2015-09-26Martin Nilsson  int(1..) tag = 10;
74fdce2014-06-21Martin Nilsson  constant type_name = "ENUMERATED"; } class Real { inherit Object;
e6945d2014-08-24Martin Nilsson 
e04d3b2015-09-26Martin Nilsson  int(1..) tag = 9;
74fdce2014-06-21Martin Nilsson  constant type_name = "REAL"; float value;
10d6cd2014-08-25Per Hedbor  //! @ignore
e6945d2014-08-24Martin Nilsson  CODEC(float);
10d6cd2014-08-25Per Hedbor  //! @endignore
74fdce2014-06-21Martin Nilsson  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,
cb65012014-10-01Martin Nilsson  function(Stdio.Buffer,
74fdce2014-06-21Martin Nilsson  mapping(int:program(Object)): Object) decoder, mapping(int:program(Object))|void types) { if( contents=="" ) { value = 0.0; return this; }
6799472015-09-25Martin Nilsson  int(0..255) first = contents[0];
74fdce2014-06-21Martin Nilsson  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"); }
6799472015-09-25Martin Nilsson  int(0..3) scaling = [int(0..3)]((first & 0b00001100) >> 2);
74fdce2014-06-21Martin Nilsson  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; }
778dd22014-07-15Martin Nilsson  protected string _sprintf(int t) { return t=='O' && sprintf("%O(%O)", this_program, value); }
47b5911999-02-19Niels Möller }
3e031f1998-06-13Niels Möller 
6e91d92002-12-05H. William Welliver III //! Bit string object
3980c72003-01-26Martin Nilsson class BitString
3e031f1998-06-13Niels Möller {
3980c72003-01-26Martin Nilsson  inherit Object;
e04d3b2015-09-26Martin Nilsson  int(1..) tag = 3;
3e031f1998-06-13Niels Möller  constant type_name = "BIT STRING";
6e91d92002-12-05H. William Welliver III 
3980c72003-01-26Martin Nilsson  //! value of object
d74f032013-12-08Henrik Grubbström (Grubba)  string(0..255) value;
6e91d92002-12-05H. William Welliver III 
6799472015-09-25Martin Nilsson  int(0..7) unused = 0;
17e7422003-01-26Martin Nilsson 
d74f032013-12-08Henrik Grubbström (Grubba)  this_program init(string(0..255) s) {
12e4902008-04-22Henrik Grubbström (Grubba)  value = s; return this; }
3e031f1998-06-13Niels Möller 
8856fc2014-02-21Henrik Grubbström (Grubba)  string(0..255) get_der_content()
d74f032013-12-08Henrik Grubbström (Grubba)  {
8856fc2014-02-21Henrik Grubbström (Grubba)  return [string(0..255)]sprintf("%c%s", unused, value);
3980c72003-01-26Martin Nilsson  }
3e031f1998-06-13Niels Möller 
78e4182004-02-22Martin Nilsson  //! Set the bitstring value as a string with @expr{"1"@} and //! @expr{"0"@}.
d74f032013-12-08Henrik Grubbström (Grubba)  this_program set_from_ascii(string(0..255) s) {
78e4182004-02-22Martin Nilsson  array v = array_sscanf(s, "%8b"*(sizeof(s)/8)+"%b");
6799472015-09-25Martin Nilsson  v[-1] = v[-1]<<[int(0..7)]((-sizeof(s))%8);
d74f032013-12-08Henrik Grubbström (Grubba)  value = (string(0..255))v;
78e4182004-02-22Martin Nilsson  set_length(sizeof(s)); return this; }
f02e6f2014-04-05Martin Nilsson  //! Sets the length of the bit string to @[len] number of bits. Will //! only work correctly on strings longer than @[len] bits.
74b5f02014-04-05Martin Nilsson  this_program set_length(int len) {
3980c72003-01-26Martin Nilsson  if (len)
3e031f1998-06-13Niels Möller  {
3980c72003-01-26Martin Nilsson  value = value[..(len + 7)/8];
6799472015-09-25Martin Nilsson  unused = [int(0..7)]((- len) % 8);
f02e6f2014-04-05Martin Nilsson  value[-1] &= 256-(1<<unused);
3980c72003-01-26Martin Nilsson  } else { unused = 0; value = "";
3e031f1998-06-13Niels Möller  }
74b5f02014-04-05Martin Nilsson  return this;
3980c72003-01-26Martin Nilsson  }
17e7422003-01-26Martin Nilsson 
d74f032013-12-08Henrik Grubbström (Grubba)  this_program decode_primitive(string(0..255) contents,
cb65012014-10-01Martin Nilsson  function(Stdio.Buffer,
12e4902008-04-22Henrik Grubbström (Grubba)  mapping(int:program(Object)): Object)|void decoder, mapping(int:program(Object))|void types) {
3980c72003-01-26Martin Nilsson  if (!sizeof(contents)) return 0;
6799472015-09-25Martin Nilsson  if (contents[0] >= 8)
3980c72003-01-26Martin Nilsson  return 0;
5a3ed72015-01-19Martin Nilsson 
6799472015-09-25Martin Nilsson  unused = [int(0..7)]contents[0];
3980c72003-01-26Martin Nilsson  value = contents[1..];
5a3ed72015-01-19Martin Nilsson  // 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;
563bd72004-01-11Martin Nilsson  return this;
3980c72003-01-26Martin Nilsson  }
842b3e2014-06-21Martin Nilsson  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;
5a3ed72015-01-19Martin Nilsson  // 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");
842b3e2014-06-21Martin Nilsson  }
9eaf1d2008-06-28Martin Nilsson  protected string _sprintf(int t) {
86fa1b2014-05-20Martin Nilsson  if(t!='O') return UNDEFINED;
26d0c42014-06-21Martin Nilsson  if(!value) return sprintf("%O(0)", this_program); int size = sizeof(value)*8-unused;
86fa1b2014-05-20Martin Nilsson  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));
3980c72003-01-26Martin Nilsson  }
e6945d2014-08-24Martin Nilsson  array _encode() { return ({ cls, tag, value, unused }); } void _decode(array(int|string(8bit)) x) {
e04d3b2015-09-26Martin Nilsson  cls = [int(0..3)]x[0]; tag = [int(1..)]x[1]; value = [string(8bit)]x[2]; unused = [int(0..7)]x[3];
e6945d2014-08-24Martin Nilsson  }
3e031f1998-06-13Niels Möller }
6e91d92002-12-05H. William Welliver III //! Octet string object
3980c72003-01-26Martin Nilsson class OctetString
3e031f1998-06-13Niels Möller {
3980c72003-01-26Martin Nilsson  inherit String;
e04d3b2015-09-26Martin Nilsson  int(1..) tag = 4;
3e031f1998-06-13Niels Möller  constant type_name = "OCTET STRING"; }
6e91d92002-12-05H. William Welliver III //! Null object
3980c72003-01-26Martin Nilsson class Null
3e031f1998-06-13Niels Möller {
3980c72003-01-26Martin Nilsson  inherit Object;
e04d3b2015-09-26Martin Nilsson  int(1..) tag = 5;
3e031f1998-06-13Niels Möller  constant type_name = "NULL";
17e7422003-01-26Martin Nilsson 
d74f032013-12-08Henrik Grubbström (Grubba)  this_program decode_primitive(string(0..255) contents,
cb65012014-10-01Martin Nilsson  function(Stdio.Buffer,
12e4902008-04-22Henrik Grubbström (Grubba)  mapping(int:program(Object)): Object)|void decoder, mapping(int:program(Object))|void types) {
563bd72004-01-11Martin Nilsson  return !sizeof(contents) && this;
3980c72003-01-26Martin Nilsson  }
3e031f1998-06-13Niels Möller 
e6945d2014-08-24Martin Nilsson  array _encode() { return ({ cls, tag }); } void _decode(array(int) x) {
e04d3b2015-09-26Martin Nilsson  cls = [int(0..3)]x[0]; tag = [int(1..)]x[1];
e6945d2014-08-24Martin Nilsson  }
3e031f1998-06-13Niels Möller }
6e91d92002-12-05H. William Welliver III //! Object identifier object
3980c72003-01-26Martin Nilsson class Identifier
3e031f1998-06-13Niels Möller {
3980c72003-01-26Martin Nilsson  inherit Object;
e04d3b2015-09-26Martin Nilsson  int(1..) tag = 6;
3e031f1998-06-13Niels Möller  constant type_name = "OBJECT IDENTIFIER";
17e7422003-01-26Martin Nilsson 
3980c72003-01-26Martin Nilsson  //! value of object
3e031f1998-06-13Niels Möller  array(int) id;
3980c72003-01-26Martin Nilsson  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;
563bd72004-01-11Martin Nilsson  return this;
3980c72003-01-26Martin Nilsson  }
3e031f1998-06-13Niels Möller 
86e5af2004-02-22Martin Nilsson  //! Returns a new @[Identifier] object with @[args] appended to the //! ID path.
3980c72003-01-26Martin Nilsson  this_program append(int ... args) {
563bd72004-01-11Martin Nilsson  return this_program(@id, @args);
3980c72003-01-26Martin Nilsson  }
17e7422003-01-26Martin Nilsson 
8856fc2014-02-21Henrik Grubbström (Grubba)  string(0..255) get_der_content()
d74f032013-12-08Henrik Grubbström (Grubba)  {
8856fc2014-02-21Henrik Grubbström (Grubba)  return [string(0..255)]sprintf("%s%@s", to_base_128(40 * id[0] + id[1]), map(id[2..], to_base_128));
3980c72003-01-26Martin Nilsson  }
3e031f1998-06-13Niels Möller 
d74f032013-12-08Henrik Grubbström (Grubba)  this_program decode_primitive(string(0..255) contents,
cb65012014-10-01Martin Nilsson  function(Stdio.Buffer,
12e4902008-04-22Henrik Grubbström (Grubba)  mapping(int:program(Object)): Object)|void decoder, mapping(int:program(Object))|void types) {
3980c72003-01-26Martin Nilsson  if (contents[0] < 120) id = ({ contents[0] / 40, contents[0] % 40 }); else id = ({ 2, contents[0] - 80 }); int index = 1; while(index < sizeof(contents))
3e031f1998-06-13Niels Möller  {
3980c72003-01-26Martin Nilsson  int element = 0; do { element = element << 7 | (contents[index] & 0x7f); } while(contents[index++] & 0x80); id += ({ element });
3e031f1998-06-13Niels Möller  }
563bd72004-01-11Martin Nilsson  return this;
3980c72003-01-26Martin Nilsson  }
3e031f1998-06-13Niels Möller 
3213f92014-08-25Martin Nilsson  protected mixed cast(string t) { switch(t) { case "string": return (array(string))id * "."; case "array" : return id+({}); default: return UNDEFINED; } }
9eaf1d2008-06-28Martin Nilsson  protected string _sprintf(int t) {
26d0c42014-06-21Martin Nilsson  if(t!='O') return UNDEFINED; if(!id) return sprintf("%O(0)", this_program); return sprintf("%O(%s)", this_program, (array(string))id*".");
3980c72003-01-26Martin Nilsson  }
e6945d2014-08-24Martin Nilsson  array _encode() { return ({ cls, tag, id }); } 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
e04d3b2015-09-26Martin Nilsson  { cls = [int(0..3)]x[0]; tag = [int(1..)]x[1]; id = [array(int)]x[2]; }
e6945d2014-08-24Martin Nilsson  }
c0903c2014-04-25Martin Nilsson  protected int __hash()
0a38772004-01-26H. William Welliver III  { return hash(get_der()); }
c0903c2014-04-25Martin Nilsson  protected int(0..1) `==(mixed other) {
3980c72003-01-26Martin Nilsson  return (objectp(other) &&
563bd72004-01-11Martin Nilsson  (this_program == object_program(other)) &&
009d772004-02-22Martin Nilsson  equal(id, ([object(Identifier)]other)->id));
3980c72003-01-26Martin Nilsson  }
c0903c2014-04-25Martin Nilsson  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); }
3e031f1998-06-13Niels Möller }
3980c72003-01-26Martin Nilsson //! Checks if a Pike string can be encoded with UTF8. That is //! always the case... int(1..1) asn1_utf8_valid (string s)
a6914b1999-06-07Martin Stjernholm {
d74f032013-12-08Henrik Grubbström (Grubba)  return 1;
a6914b1999-06-07Martin Stjernholm }
6e91d92002-12-05H. William Welliver III //! UTF8 string object //! //! Character set: ISO/IEC 10646-1 (compatible with Unicode). //!
dc93732015-08-22Martin Nilsson //! Variable width encoding, see @rfc{2279@}.
3980c72003-01-26Martin Nilsson class UTF8String
a6914b1999-06-07Martin Stjernholm {
3980c72003-01-26Martin Nilsson  inherit String;
e04d3b2015-09-26Martin Nilsson  int(1..) tag = 12;
a6914b1999-06-07Martin Stjernholm  constant type_name = "UTF8String";
8856fc2014-02-21Henrik Grubbström (Grubba)  string(0..255) get_der_content()
d74f032013-12-08Henrik Grubbström (Grubba)  {
8856fc2014-02-21Henrik Grubbström (Grubba)  return string_to_utf8(value);
3980c72003-01-26Martin Nilsson  }
a6914b1999-06-07Martin Stjernholm 
12e4902008-04-22Henrik Grubbström (Grubba)  this_program decode_primitive(string(0..255) contents,
cb65012014-10-01Martin Nilsson  function(Stdio.Buffer,
12e4902008-04-22Henrik Grubbström (Grubba)  mapping(int:program(Object)): Object)|void decoder, mapping(int:program(Object))|void types) {
983ea12013-12-04Martin Nilsson  der = contents;
3980c72003-01-26Martin Nilsson  if (catch { value = utf8_to_string(contents); }) return 0;
17e7422003-01-26Martin Nilsson 
563bd72004-01-11Martin Nilsson  return this;
3980c72003-01-26Martin Nilsson  } }
a6914b1999-06-07Martin Stjernholm 
6e91d92002-12-05H. William Welliver III //! Sequence object
3980c72003-01-26Martin Nilsson class Sequence
3e031f1998-06-13Niels Möller {
3980c72003-01-26Martin Nilsson  inherit Compound;
e04d3b2015-09-26Martin Nilsson  int(1..) tag = 16;
3e031f1998-06-13Niels Möller  constant type_name = "SEQUENCE";
17e7422003-01-26Martin Nilsson 
8856fc2014-02-21Henrik Grubbström (Grubba)  string(0..255) get_der_content()
d74f032013-12-08Henrik Grubbström (Grubba)  {
fa323d2004-02-29Martin Nilsson  WERROR("ASN1.Sequence: elements = '%O\n", elements);
3980c72003-01-26Martin Nilsson  array(string) a = elements->get_der();
fa323d2004-02-29Martin Nilsson  WERROR("ASN1.Sequence: der_encode(elements) = '%O\n", a);
8856fc2014-02-21Henrik Grubbström (Grubba)  return [string(0..255)]`+("", @ a);
3980c72003-01-26Martin Nilsson  }
12e4902008-04-22Henrik Grubbström (Grubba) 
d74f032013-12-08Henrik Grubbström (Grubba)  this_program decode_primitive(string(0..255) contents,
cb65012014-10-01Martin Nilsson  function(Stdio.Buffer,
12e4902008-04-22Henrik Grubbström (Grubba)  mapping(int:program(Object)): Object) decoder, mapping(int:program(Object)) types) {
983ea12013-12-04Martin Nilsson  der = contents;
12e4902008-04-22Henrik Grubbström (Grubba)  elements = ({});
cb65012014-10-01Martin Nilsson  Stdio.Buffer data = Stdio.Buffer(contents);
e7e02a2014-09-14Martin Nilsson  while (sizeof(data)) { elements += ({ decoder(data, types) });
12e4902008-04-22Henrik Grubbström (Grubba)  } return this; }
3e031f1998-06-13Niels Möller }
6e91d92002-12-05H. William Welliver III //! Set object
3980c72003-01-26Martin Nilsson class Set
3e031f1998-06-13Niels Möller {
3980c72003-01-26Martin Nilsson  inherit Compound;
e04d3b2015-09-26Martin Nilsson  int(1..) tag = 17;
3e031f1998-06-13Niels Möller  constant type_name = "SET";
17e7422003-01-26Martin Nilsson 
ee60602014-02-20Henrik Grubbström (Grubba)  int(-1..1) compare_octet_strings(string r, string s) { if (r == s) return 0;
3980c72003-01-26Martin Nilsson  for(int i = 0;; i++) { if (i == sizeof(r))
ee60602014-02-20Henrik Grubbström (Grubba)  return (i = sizeof(s)) ? 0 : -1;
3980c72003-01-26Martin Nilsson  if (i == sizeof(s)) return 1;
ee60602014-02-20Henrik Grubbström (Grubba)  if (r[i] < s[i])
3980c72003-01-26Martin Nilsson  return -1;
ee60602014-02-20Henrik Grubbström (Grubba)  else if (r[i] > s[i]) return 1;
3e031f1998-06-13Niels Möller  }
3980c72003-01-26Martin Nilsson  }
3e031f1998-06-13Niels Möller 
8856fc2014-02-21Henrik Grubbström (Grubba)  string get_der_content() {
fa323d2004-02-29Martin Nilsson  WERROR("asn1_set->der: elements = '%O\n", elements);
3980c72003-01-26Martin Nilsson  array(string) a = elements->get_der();
fa323d2004-02-29Martin Nilsson  WERROR("asn1_set->der: der_encode(elements) = '%O\n", a);
8856fc2014-02-21Henrik Grubbström (Grubba)  return [string(0..255)] `+("", @[array(string)] Array.sort_array(a, compare_octet_strings));
3980c72003-01-26Martin Nilsson  }
a6914b1999-06-07Martin Stjernholm }
b7bb642014-06-26Martin Nilsson protected Regexp asn1_printable_invalid_chars = Regexp("([^-A-Za-z0-9 '()+,./:=?])");
a6914b1999-06-07Martin Stjernholm 
3980c72003-01-26Martin Nilsson //! 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);
a6914b1999-06-07Martin Stjernholm }
6e91d92002-12-05H. William Welliver III //! PrintableString object
3980c72003-01-26Martin Nilsson class PrintableString
3e031f1998-06-13Niels Möller {
3980c72003-01-26Martin Nilsson  inherit String;
e04d3b2015-09-26Martin Nilsson  int(1..) tag = 19;
3e031f1998-06-13Niels Möller  constant type_name = "PrintableString"; }
3980c72003-01-26Martin Nilsson //! int(0..1) asn1_broken_teletex_valid (string s)
a6914b1999-06-07Martin Stjernholm {
3980c72003-01-26Martin Nilsson  return global.String.width(s)==8;
a6914b1999-06-07Martin Stjernholm }
6e91d92002-12-05H. William Welliver III //! (broken) TeletexString object //! //! Encodes and decodes latin1, but labels it TeletexString, as is //! common in many broken programs (e.g. Netscape 4.0X).
3980c72003-01-26Martin Nilsson class BrokenTeletexString
a6914b1999-06-07Martin Stjernholm {
3980c72003-01-26Martin Nilsson  inherit String;
58aad12014-08-10Henrik Grubbström (Grubba)  int(0..) tag = 20;
a6914b1999-06-07Martin Stjernholm  constant type_name = "TeletexString"; // Alias: T61String }
b7bb642014-06-26Martin Nilsson protected Regexp asn1_IA5_invalid_chars = Regexp ("([\200-\377])");
a6914b1999-06-07Martin Stjernholm 
3980c72003-01-26Martin Nilsson //! int(0..1) asn1_IA5_valid (string s)
a6914b1999-06-07Martin Stjernholm {
3980c72003-01-26Martin Nilsson  if (global.String.width(s)!=8) return 0;
a6914b1999-06-07Martin Stjernholm  return !asn1_printable_invalid_chars->match (s);
3e031f1998-06-13Niels Möller }
6e91d92002-12-05H. William Welliver III //! IA5 String object //! //! Character set: ASCII. Fixed width encoding with 1 octet per //! character.
3980c72003-01-26Martin Nilsson class IA5String
3e031f1998-06-13Niels Möller {
3980c72003-01-26Martin Nilsson  inherit String;
e04d3b2015-09-26Martin Nilsson  int(1..) tag = 22;
3e031f1998-06-13Niels Möller  constant type_name = "IA5STRING"; }
53df712003-01-26Martin Nilsson  //!
ffbc622003-01-28Martin Nilsson class VisibleString { inherit String;
e04d3b2015-09-26Martin Nilsson  int(1..) tag = 26;
ffbc622003-01-28Martin Nilsson  constant type_name = "VisibleString"; }
eb16ad2014-05-14Henrik Grubbström (Grubba) //! UTCTime
ffbc622003-01-28Martin Nilsson //!
0c4ea52015-08-22Martin Nilsson //! @rfc{2459:4.1.2.5.1@}
3980c72003-01-26Martin Nilsson class UTC
3e031f1998-06-13Niels Möller {
3980c72003-01-26Martin Nilsson  inherit String;
e04d3b2015-09-26Martin Nilsson  int(1..) tag = 23;
3e031f1998-06-13Niels Möller  constant type_name = "UTCTime";
6725f52013-11-22Martin Nilsson 
b45e9c2014-09-29Martin Nilsson  this_program init(int|string|Calendar.ISO_UTC.Second t)
ac7d632014-07-16Martin Nilsson  { if(intp(t)) set_posix([int]t);
b45e9c2014-09-29Martin Nilsson  else if(objectp(t)) set_posix([object(Calendar.ISO_UTC.Second)]t);
ac7d632014-07-16Martin Nilsson  else value = [string]t; }
6725f52013-11-22Martin Nilsson  this_program set_posix(int t) {
b45e9c2014-09-29Martin Nilsson  return set_posix(Calendar.ISO_UTC.Second(t)); } //! variant this_program set_posix(Calendar.ISO_UTC.Second second) {
6725f52013-11-22Martin Nilsson 
eb16ad2014-05-14Henrik Grubbström (Grubba)  // 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.
6725f52013-11-22Martin Nilsson  if (second->year_no() >= 2050) error( "Times later than 2049 not supported.\n" );
eb16ad2014-05-14Henrik Grubbström (Grubba)  if (second->year_no() < 1950) error( "Times earlier than 1950 not supported.\n" );
6725f52013-11-22Martin Nilsson  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; }
eb16ad2014-05-14Henrik Grubbström (Grubba)  //!
6725f52013-11-22Martin Nilsson  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;
e2f0772014-03-02Marcus Comstedt  return [int]Calendar.ISO_UTC.Second(@t)->unix_time();
6725f52013-11-22Martin Nilsson  }
3e031f1998-06-13Niels Möller }
11471a2014-09-29Martin Nilsson class GeneralizedTime { inherit UTC;
e04d3b2015-09-26Martin Nilsson  int(1..) tag = 24;
11471a2014-09-29Martin Nilsson  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) {
b45e9c2014-09-29Martin Nilsson  return set_posix(Calendar.ISO_UTC.Second(t)); } //! variant this_program set_posix(Calendar.ISO_UTC.Second second) {
11471a2014-09-29Martin Nilsson  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(); } }
3980c72003-01-26Martin Nilsson //! int(0..0) asn1_universal_valid (string s)
a6914b1999-06-07Martin Stjernholm {
7991f12008-01-05Henrik Grubbström (Grubba)  return 0; s; // Return 0 since the UniversalString isn't implemented.
a6914b1999-06-07Martin Stjernholm }
6e91d92002-12-05H. William Welliver III //! 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.
3980c72003-01-26Martin Nilsson class UniversalString
a6914b1999-06-07Martin Stjernholm {
3980c72003-01-26Martin Nilsson  inherit OctetString;
e04d3b2015-09-26Martin Nilsson  int(1..) tag = 28;
a6914b1999-06-07Martin Stjernholm  constant type_name = "UniversalString";
8856fc2014-02-21Henrik Grubbström (Grubba)  string get_der_content() {
3980c72003-01-26Martin Nilsson  error( "Encoding not implemented\n" );
a6914b1999-06-07Martin Stjernholm  }
12e4902008-04-22Henrik Grubbström (Grubba)  this_program decode_primitive (string contents,
cb65012014-10-01Martin Nilsson  function(Stdio.Buffer,
12e4902008-04-22Henrik Grubbström (Grubba)  mapping(int:program(Object)): Object)|void decoder, mapping(int:program(Object))|void types) {
7991f12008-01-05Henrik Grubbström (Grubba)  error( "Decoding not implemented\n" ); contents;
a6914b1999-06-07Martin Stjernholm  } }
3980c72003-01-26Martin Nilsson //! int(0..1) asn1_bmp_valid (string s)
a6914b1999-06-07Martin Stjernholm {
3980c72003-01-26Martin Nilsson  return global.String.width(s)<32;
a6914b1999-06-07Martin Stjernholm }
6e91d92002-12-05H. William Welliver III //! 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.
3980c72003-01-26Martin Nilsson class BMPString
a6914b1999-06-07Martin Stjernholm {
3980c72003-01-26Martin Nilsson  inherit OctetString;
e04d3b2015-09-26Martin Nilsson  int(1..) tag = 30;
a6914b1999-06-07Martin Stjernholm  constant type_name = "BMPString";
8856fc2014-02-21Henrik Grubbström (Grubba)  string get_der_content() { return string_to_unicode (value);
a6914b1999-06-07Martin Stjernholm  }
12e4902008-04-22Henrik Grubbström (Grubba)  this_program decode_primitive (string(0..255) contents,
cb65012014-10-01Martin Nilsson  function(Stdio.Buffer,
12e4902008-04-22Henrik Grubbström (Grubba)  mapping(int:program(Object)): Object)|void decoder, mapping(int:program(Object))|void types) {
983ea12013-12-04Martin Nilsson  der = contents;
a6914b1999-06-07Martin Stjernholm  value = unicode_to_string (contents);
563bd72004-01-11Martin Nilsson  return this;
a6914b1999-06-07Martin Stjernholm  } }
3980c72003-01-26Martin Nilsson //! Meta-instances handle a particular explicit tag and set of types.
dd85c02013-08-16Martin Nilsson //! Once cloned this object works as a factory for Compound objects //! with the cls and tag that the meta object was initialized with.
6e91d92002-12-05H. William Welliver III //!
dd85c02013-08-16Martin Nilsson //! @example //! MetaExplicit m = MetaExplicit(1,2); //! Compound c = m(Integer(3));
3980c72003-01-26Martin Nilsson class MetaExplicit
3e031f1998-06-13Niels Möller {
e04d3b2015-09-26Martin Nilsson  int(0..3) real_cls; int(1..) real_tag;
17e7422003-01-26Martin Nilsson 
c485aa2003-01-27Martin Nilsson  mapping(int:program(Object)) valid_types;
3e031f1998-06-13Niels Möller 
3980c72003-01-26Martin Nilsson  class `() { inherit Compound; constant type_name = "EXPLICIT"; constant constructed = 1;
17e7422003-01-26Martin Nilsson 
e04d3b2015-09-26Martin Nilsson  int(0..3) get_cls() { return real_cls; } int(1..) get_tag() { return real_tag; }
17e7422003-01-26Martin Nilsson 
3980c72003-01-26Martin Nilsson  Object contents;
3e031f1998-06-13Niels Möller 
8c92912014-01-19Henrik Grubbström (Grubba)  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(); }
3980c72003-01-26Martin Nilsson  this_program init(Object o) { contents = o;
563bd72004-01-11Martin Nilsson  return this;
3980c72003-01-26Martin Nilsson  }
17e7422003-01-26Martin Nilsson 
8856fc2014-02-21Henrik Grubbström (Grubba)  string get_der_content() {
fa323d2004-02-29Martin Nilsson  WERROR("asn1_explicit->der: contents = '%O\n", contents);
8856fc2014-02-21Henrik Grubbström (Grubba)  return contents->get_der();
3e031f1998-06-13Niels Möller  }
3980c72003-01-26Martin Nilsson  this_program decode_constructed_element(int i, Object e) { if (i) error("Unexpected index!\n"); contents = e;
563bd72004-01-11Martin Nilsson  return this;
3980c72003-01-26Martin Nilsson  }
c485aa2003-01-27Martin Nilsson  mapping(int:program(Object)) element_types(int i, mapping(int:program(Object)) types) {
3980c72003-01-26Martin Nilsson  if (i) error("Unexpected index!\n"); return valid_types || types; }
9eaf1d2008-06-28Martin Nilsson  protected string _sprintf(int t) {
bc5ae92014-01-18Henrik Grubbström (Grubba)  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);
3980c72003-01-26Martin Nilsson  }
e6945d2014-08-24Martin Nilsson  array _encode() { return ({ real_cls, real_tag, contents }); } void _decode(array(int|Object) x) {
e04d3b2015-09-26Martin Nilsson  real_cls = [int(0..3)]x[0]; real_tag = [int(1..)]x[1]; contents = [object(Object)]x[2];
e6945d2014-08-24Martin Nilsson  }
3980c72003-01-26Martin Nilsson  }
17e7422003-01-26Martin Nilsson 
dd85c02013-08-16Martin Nilsson  //!
e04d3b2015-09-26Martin Nilsson  protected void create(int(0..3) cls, int(1..) tag,
33dd5f2014-02-11Henrik Grubbström (Grubba)  mapping(int:program(Object))|void types) {
3980c72003-01-26Martin Nilsson  real_cls = cls; real_tag = tag; valid_types = types; }
e6945d2014-08-24Martin Nilsson  array _encode() { return ({ real_cls, real_tag, valid_types }); } void _decode(array(int|mapping(int:program(Object))) x) {
e04d3b2015-09-26Martin Nilsson  real_cls = [int(0..3)]x[0]; real_tag = [int(1..)]x[1]; valid_types = [mapping(int:program(Object))]x[2];
e6945d2014-08-24Martin Nilsson  }
3e031f1998-06-13Niels Möller }
d9b4021999-08-06Fredrik Hübinette (Hubbe) 
bc5ae92014-01-18Henrik Grubbström (Grubba) //! Some common explicit tags for convenience. //! //! These are typically used to indicate which //! of several optional fields are present. //! //! @example
0c4ea52015-08-22Martin Nilsson //! Eg @rfc{5915:3@}:
bc5ae92014-01-18Henrik Grubbström (Grubba) //! @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);