diff --git a/lib/modules/Standards.pmod/X509.pmod b/lib/modules/Standards.pmod/X509.pmod
index c4646b4ac7da211c62213aee4ef5069159d85b57..30572ce458e539e139ee2bdba34db357b9914899 100644
--- a/lib/modules/Standards.pmod/X509.pmod
+++ b/lib/modules/Standards.pmod/X509.pmod
@@ -143,9 +143,6 @@ variant Sequence make_tbs(Sequence issuer, Sequence algorithm,
 Sequence sign_tbs(Sequence|TBSCertificate tbs,
 		  Crypto.Sign sign, Crypto.Hash hash)
 {
-  if (tbs->get_asn1) {
-    tbs = ([object(TBSCertificate)]tbs)->get_asn1();
-  }
   return Sequence(({ [object(Sequence)]tbs,
 		     sign->pkcs_signature_algorithm_id(hash),
 		     BitString(sign->pkcs_sign(tbs->get_der(), hash)),
@@ -370,77 +367,312 @@ protected Verifier make_verifier(Object _keyinfo)
 //! Represents a TBSCertificate.
 class TBSCertificate
 {
-  //!
-  string der;
+  inherit Sequence;
 
-  //!  
-  int version;
+  protected string internal_der;
 
   //!
-  Gmp.mpz serial;
-  
+  void `der=(string asn1)
+  {
+    internal_der = UNDEFINED;
+    if (init(Standards.ASN1.Decode.simple_der_decode(asn1))) {
+      internal_der = asn1;
+    }
+  }
+  string `der()
+  {
+    if (internal_der) return internal_der;
+    return internal_der = get_der();
+  }
+
   //!
-  Sequence algorithm;  /* Algorithm Identifier */
+  void `version=(int v)
+  {
+    internal_der = UNDEFINED;
+    if (v == 1) {
+      if (sizeof(elements) > 6) {
+	elements = elements[1..6];
+	issuer_pos = subject_pos = extensions_pos = 0;
+      }
+    } else if (sizeof(elements) == 6) {
+      elements = ({ version_integer(Integer(v-1)) }) + elements;
+    } else {
+      elements[0] = version_integer(Integer(v-1));
+    }
+  }
+  int `version()
+  {
+    if (sizeof(elements) == 6) return 1;
+    return (int)elements[0][0]->value + 1;
+  }
 
+  //! @param index
+  //!   Index in a v1 certificate.
   //!
-  Sequence issuer;
+  //! @param val
+  //!   New value for index.
+  protected void low_set(int index, Sequence|Integer val)
+  {
+    internal_der = UNDEFINED;
+    if (sizeof(elements) > 6) index++;
+    elements[index] = val;
+  }
+
+  protected Sequence|Integer low_get(int index)
+  {
+    if (sizeof(elements) > 6) index++;
+    return elements[index];
+  }
 
   //!
-  int not_after;
+  void `serial=(Gmp.mpz|int s)
+  {
+    low_set(0, Integer(s));
+  }
+  Gmp.mpz `serial()
+  {
+    Integer s = low_get(0);
+    return s->value;
+  }
+
+  //! Algorithm Identifier.
+  void `algorithm=(Sequence a)
+  {
+    low_set(1, a);
+  }
+  Sequence `algorithm()
+  {
+    return low_get(1);
+  }
+
+  //! Certificate issuer.
+  void `issuer=(Sequence i)
+  {
+    low_set(2, i);
+  }
+  Sequence `issuer()
+  {
+    return low_get(2);
+  }
 
   //!
-  int not_before;
+  void `not_before=(int t)
+  {
+    Sequence validity = low_get(3);
+    validity->elements[0] = UTC()->set_posix(t);
+    internal_der = UNDEFINED;
+  }
+  int `not_before()
+  {
+    Sequence validity = low_get(3);
+    return validity[0]->get_posix();
+  }
 
   //!
-  Sequence subject;
+  void `not_after=(int t)
+  {
+    Sequence validity = low_get(3);
+    validity->elements[1] = UTC()->set_posix(t);
+    internal_der = UNDEFINED;
+  }
+  int `not_after()
+  {
+    Sequence validity = low_get(3);
+    return validity[1]->get_posix();
+  }
 
   //!
-  Verifier public_key;
+  void `subject=(Sequence s)
+  {
+    low_set(4, s);
+  }
+  Sequence `subject()
+  {
+    return low_get(4);
+  }
+
+  protected Verifier internal_public_key;
+
+  //!
+  void `public_key=(Verifier v)
+  {
+    internal_public_key = v;
+    low_set(5, v->pkc->pkcs_public_key());
+  }
+  Verifier `public_key()
+  {
+    return internal_public_key;
+  }
 
   /* Optional */
 
+  protected int issuer_pos;
+  protected int subject_pos;
+  protected int extensions_pos;
+
   //! @note
   //! optional
-  BitString issuer_id;
-  
+  void `issuer_id=(BitString i)
+  {
+    internal_der = UNDEFINED;
+    if (!i) {
+      if (!issuer_pos) return;
+      elements = elements[..6] + elements[8..];
+      issuer_pos = 0;
+      if (subject_pos) subject_pos--;
+      if (extensions_pos) extensions_pos--;
+      return;
+    }
+    TaggedType1 tti = TaggedType1(i);
+    if (!issuer_pos) {
+      if (version < 2) version = 2;
+      issuer_pos = 7;
+      elements = elements[..6] + ({ tti }) + elements[7..];
+      if (subject_pos) subject_pos++;
+      if (extensions_pos) extensions_pos++;
+      return;
+    }
+    elements[issuer_pos] = tti;
+  }
+  BitString `issuer_id()
+  {
+    if (issuer_pos) return elements[issuer_pos][0];
+    return UNDEFINED;
+  }
+
   //! @note
   //! optional
-  BitString subject_id;
+  void `subject_id=(BitString s)
+  {
+    internal_der = UNDEFINED;
+    if (!s) {
+      if (!subject_pos) return;
+      elements = elements[..subject_pos -1] + elements[subject_pos+1..];
+      subject_pos = 0;
+      if (extensions_pos) extensions_pos--;
+      return;
+    }
+    TaggedType2 tts = TaggedType2(s);
+    if (!subject_pos) {
+      if (version < 2) version = 2;
+      subject_pos = (issuer_pos || 6) + 1;
+      elements = elements[..subject_pos-1] + ({ tts }) +
+	elements[subject_pos..];
+      if (extensions_pos) extensions_pos++;
+      return;
+    }
+    elements[subject_pos] = tts;
+  }
+  BitString `subject_id()
+  {
+    if (subject_pos) return elements[subject_pos][0];
+    return UNDEFINED;
+  }
 
   //! The raw ASN.1 objects from which @[extensions] and @[critical]
   //! have been generated.
   //!
   //! @note
   //! optional
-  Sequence raw_extensions;
+  void `raw_extensions=(Sequence r)
+  {
+    internal_der = UNDEFINED;
+    internal_extensions = ([]);
+    internal_critical = (<>);
+    mapping(string:Object) extensions = ([]);
+    multiset critical = (<>);
+
+    if (!r) {
+      if (!extensions_pos) return;
+      elements = elements[..extensions_pos-1];
+      extensions_pos = 0;
+      return;
+    }
+
+    foreach(r->elements, Object _ext)
+    {
+      if( _ext->type_name != "SEQUENCE" ||
+	  sizeof(_ext)<2 || sizeof(_ext)>3 )
+      {
+	DBG("TBSCertificate: Bad extensions structure.\n");
+	return 0;
+      }
+      Sequence ext = [object(Sequence)]_ext;
+      if( ext[0]->type_name != "OBJECT IDENTIFIER" ||
+	  ext[-1]->type_name != "OCTET STRING" )
+      {
+	DBG("TBSCertificate: Bad extensions structure.\n");
+	return 0;
+      }
+      DBG("TBSCertificate: extension: %O\n", ext[0]);
+      string id = ext[0]->get_der();
+
+      if( extensions[id] )
+      {
+	DBG("TBSCertificate: extension %O sent twice.\n");
+	return 0;
+      }
+
+      extensions[ id ] =
+        Standards.ASN1.Decode.simple_der_decode(ext->elements[-1]->value);
+      if(sizeof(ext)==3)
+      {
+	if( ext[1]->type_name != "BOOLEAN" ) return 0;
+	if( ext[1]->value ) critical[id]=1;
+      }
+    }
+
+    if (extensions_pos) {
+      if (version < 3) version = 3;
+      extensions_pos = sizeof(elements);
+      elements = elements + ({ TaggedType3(r) });
+    } else {
+      elements[extensions_pos] = TaggedType3(r);
+    }
+
+    internal_extensions = extensions;
+    internal_critical = critical;
+  }
+  Sequence `raw_extensions()
+  {
+    if (extensions_pos) return elements[extensions_pos][0];
+    return UNDEFINED;
+  }
 
   //! @note
   //! optional
-  mapping(string:Object) extensions = ([]);
+  protected mapping(string:Object) internal_extensions = ([]);
+  mapping(string:Object) `extensions()
+  {
+    return internal_extensions;
+  }
 
   //! @note
   //! optional
-  multiset critical = (<>);
+  protected multiset internal_critical = (<>);
+  multiset `critical()
+  {
+    return internal_critical;
+  }
 
-  //! Get the ASN.1 representation of the TBSCertificate.
-  //!
-  //! @note
-  //!   This recreates the ASN.1 from the field values
-  //!   in the object.
-  //!
-  //! @note
-  //!   The @[version] field is currently ignored, and will
-  //!   be set according to the presence of @[raw_extensions].
-  //!
-  //!   This means that it may differ from the DER in @[der].
-  Sequence get_asn1()
+  protected void create(Sequence|void asn1)
   {
-    return make_tbs(issuer, algorithm, subject,
-		    public_key->pkc->pkcs_public_key(),
-		    Integer(serial),
-		    Sequence(({ UTC()->set_posix(not_before),
-				UTC()->set_posix(not_after) })),
-		    (raw_extensions && raw_extensions->elements) || UNDEFINED);
+    // Initialize to defaults.
+    elements = ({
+      Integer(0),					// serialNumber
+      Null,						// signature
+      Sequence(({})),					// issuer
+      Sequence(({ UTC()->set_posix(-0x8000000),
+		  UTC()->set_posix(0x7fffffff) })),	// validity
+      Sequence(({})),					// subject
+      Null,						// subjectPublicKeyInfo
+    });
+
+    if (asn1) {
+      if (!init(asn1)) {
+	error("Invalid ASN.1 structure for a TBSCertificate.\n");
+      }
+    }
   }
 
   protected mixed cast(string to)
@@ -506,18 +738,24 @@ class TBSCertificate
   //! Object. Returns the object on success, otherwise @expr{0@}. You
   //! probably want to call @[decode_certificate] or even
   //! @[verify_certificate].
-  this_program init(Object asn1)
+  this_program init(array(Object)|Object asn1)
   {
-    der = asn1->get_der();
-    if (asn1->type_name != "SEQUENCE")
-      return 0;
+    array(Object) a;
+    if (objectp(asn1)) {
+      if (asn1->type_name != "SEQUENCE")
+	return 0;
 
-    array(Object) a = ([object(Sequence)]asn1)->elements;
+      a = ([object(Sequence)]asn1)->elements;
+    } else {
+      a = [array(Object)]asn1;
+    }
     DBG("TBSCertificate: sizeof(a) = %d\n", sizeof(a));
       
     if (sizeof(a) < 6)
       return 0;
 
+    int version = 1;
+
     if (sizeof(a) > 6)
     {
       /* The optional version field must be present */
@@ -531,10 +769,11 @@ class TBSCertificate
       if ( (version < 2) || (version > 3))
 	return 0;
       a = a[1..];
-    } else
-      version = 1;
+    }
     DBG("TBSCertificate: version = %d\n", version);
 
+    this_program::version = version;
+
     if (a[0]->type_name != "INTEGER")
       return 0;
     serial = a[0]->value;
@@ -558,17 +797,15 @@ class TBSCertificate
       return 0;
     array validity = a[3]->elements;
 
-    catch {
-      not_before = validity[0]->get_posix();
-    };
-    if (!not_before)
+    if (catch {
+	not_before = validity[0]->get_posix();
+      })
       return 0;
     DBG("TBSCertificate: not_before = %O\n", not_before);
 
-    catch {
-      not_after = validity[1]->get_posix();
-    };
-    if (!not_after)
+    if (catch {
+	not_after = validity[1]->get_posix();
+      })
       return 0;
     DBG("TBSCertificate: not_after = %O\n", not_after);
 
@@ -586,74 +823,37 @@ class TBSCertificate
         public_key->type);
 
     int i = 6;
-    if (i == sizeof(a))
-      return this;
-
-    if (version < 2)
-      return 0;
 
-    if (! a[i]->constructed
-	&& (a[i]->combined_tag == make_combined_tag(2, 1)))
-    {
-      issuer_id = BitString()->decode_primitive(a[i]->raw);
-      DBG("TBSCertificate: issuer_id = %O\n", issuer_id);
-      i++;
-      if (i == sizeof(a))
-	return this;
-    }
-    if (! a[i]->constructed
-	&& (a[i]->combined_tag == make_combined_tag(2, 2)))
-    {
-      subject_id = BitString()->decode_primitive(a[i]->raw);
-      DBG("TBSCertificate: subject_id = %O\n", subject_id);
-      i++;
-      if (i == sizeof(a))
-	return this;
-    }
-    if (a[i]->constructed
-	&& (a[i]->combined_tag == make_combined_tag(2, 3))
-        && sizeof(a[i])==1
-        && a[i][0]->type_name == "SEQUENCE")
+    if (version >= 2)
     {
-      raw_extensions = a[i][0];
-      extensions = ([]);
-      foreach(raw_extensions->elements, Object _ext)
+      if ((i < sizeof(a)) && !a[i]->constructed &&
+	  (a[i]->combined_tag == make_combined_tag(2, 1)))
       {
-        if( _ext->type_name != "SEQUENCE" ||
-            sizeof(_ext)<2 || sizeof(_ext)>3 )
-        {
-          DBG("TBSCertificate: Bad extensions structure.\n");
-          return 0;
-        }
-        Sequence ext = [object(Sequence)]_ext;
-        if( ext[0]->type_name != "OBJECT IDENTIFIER" ||
-            ext[-1]->type_name != "OCTET STRING" )
-        {
-          DBG("TBSCertificate: Bad extensions structure.\n");
-          return 0;
-        }
-        DBG("TBSCertificate: extension: %O\n", ext[0]);
-        string id = ext[0]->get_der();
-
-        if( extensions[id] )
-        {
-          DBG("TBSCertificate: extension %O sent twice.\n");
-          return 0;
-        }
-
-        extensions[ id ] =
-          Standards.ASN1.Decode.simple_der_decode(ext->elements[-1]->value);
-        if(sizeof(ext)==3)
-        {
-          if( ext[1]->type_name != "BOOLEAN" ) return 0;
-          if( ext[1]->value ) critical[id]=1;
-        }
+	issuer_id = BitString()->decode_primitive(a[i]->raw);
+	DBG("TBSCertificate: issuer_id = %O\n", issuer_id);
+	i++;
+      }
+      if ((i < sizeof(a)) && !a[i]->constructed &&
+	  (a[i]->combined_tag == make_combined_tag(2, 2)))
+      {
+	subject_id = BitString()->decode_primitive(a[i]->raw);
+	DBG("TBSCertificate: subject_id = %O\n", subject_id);
+	i++;
+	if (i == sizeof(a))
+	  return this;
       }
-
-      i++;
-      if (i == sizeof(a))
-	return this;
     }
+    if (version >= 3) {
+      if ((i < sizeof(a)) && a[i]->constructed &&
+	  (a[i]->combined_tag == make_combined_tag(2, 3)) &&
+	  sizeof(a[i])==1 &&
+	  a[i][0]->type_name == "SEQUENCE") {
+	raw_extensions = a[i][0];
+      }
+    }
+    internal_der = asn1->get_der();
+    if (i == sizeof(a))
+      return this;
     /* Too many fields */
     return 0;
   }