a580e12000-09-27Fredrik Hübinette (Hubbe) #pike __REAL_VERSION__
0324132004-01-27Martin Nilsson //#pragma strict_types
a20af62000-09-26Fredrik Hübinette (Hubbe) 
cb74682000-05-25Andreas Sigfridsson /*
38333a1999-03-02Niels Möller  * Some random functions for creating RFC-2459 style X.509 certificates. * */
2019a02004-03-17Martin Nilsson constant dont_dump_module = 1;
b127592004-02-29Martin Nilsson #if constant(Standards.ASN1.Types.Sequence) && constant(Crypto.Hash)
92dbd31999-08-24Fredrik Hübinette (Hubbe) 
38333a1999-03-02Niels Möller import Standards.ASN1.Types; import Standards.PKCS;
0ecba92000-08-01Andreas Sigfridsson // Note: Redump this module if you change X509_DEBUG #ifdef X509_DEBUG #define X509_WERR werror #else #define X509_WERR #endif
875a0c2004-02-04H. William Welliver III //! constant CERT_TOO_OLD = 1; //! constant CERT_TOO_NEW = 2; //! constant CERT_INVALID = 3; //! constant CERT_CHAIN_BROKEN = 4; //! constant CERT_ROOT_UNTRUSTED = 5; //! constant CERT_BAD_SIGNATURE = 6;
ebb5be2004-03-22H. William Welliver III //! constant CERT_UNAUTHORIZED_CA = 7;
cd16db2003-01-26Martin Nilsson //! Creates a @[Standards.ASN1.Types.UTC] object from the posix //! time @[t]. UTC make_time(int t)
38333a1999-03-02Niels Möller {
674a2d2004-09-06Henrik Grubbström (Grubba)  object /*Calendar.Second*/ second = Calendar["Second"](t)->set_timezone("UTC");
38333a1999-03-02Niels Möller 
9e60132001-10-08Per Hedbor  if (second->year_no() >= 2050)
cd16db2003-01-26Martin Nilsson  error( "Times later than 2049 not supported yet\n" ); return UTC(sprintf("%02d%02d%02d%02d%02d%02dZ", second->year_no() % 100, second->month_no(), second->month_day(), second->hour_no(), second->minute_no(), second->second_no()));
38333a1999-03-02Niels Möller }
cd16db2003-01-26Martin Nilsson //! Returns a mapping similar to that returned by gmtime //! @returns //! @mapping //! @member int "year" //! @member int "mon" //! @member int "mday" //! @member int "hour" //! @member int "min" //! @member int "sec" //! @endmapping mapping(string:int) parse_time(UTC asn1)
6913ab1999-03-22Niels Möller {
5b546b1999-03-23Niels Möller  if ((asn1->type_name != "UTCTime")
ead9722003-01-20Martin Nilsson  || (sizeof(asn1->value) != 13))
6913ab1999-03-22Niels Möller  return 0; sscanf(asn1->value, "%[0-9]s%c", string s, int c);
ead9722003-01-20Martin Nilsson  if ( (sizeof(s) != 12) && (c != 'Z') )
6913ab1999-03-22Niels Möller  return 0;
5b546b1999-03-23Niels Möller  /* NOTE: This relies on pike-0.7 not interpreting leading zeros as * an octal prefix. */
0324132004-01-27Martin Nilsson  mapping(string:int) m = mkmapping( ({ "year", "mon", "mday", "hour", "min", "sec" }), (array(int)) (s/2));
6913ab1999-03-22Niels Möller  if (m->year < 50)
ea382e2000-03-10Martin Nilsson  m->year += 100;
6913ab1999-03-22Niels Möller  if ( (m->mon <= 0 ) || (m->mon > 12) ) return 0; m->mon--;
674a2d2004-09-06Henrik Grubbström (Grubba)  if ( (m->mday <= 0) || (m->mday > Calendar["ISO"]["Year"](m->year + 1900)
6913ab1999-03-22Niels Möller  ->month(m->mon + 1)->number_of_days())) return 0; if ( (m->hour < 0) || (m->hour > 23)) return 0; if ( (m->min < 0) || (m->min > 59)) return 0;
0ecba92000-08-01Andreas Sigfridsson  /* NOTE: Allows for leap seconds */ if ( (m->sec < 0) || (m->sec > 60))
6913ab1999-03-22Niels Möller  return 0; return m; }
cd16db2003-01-26Martin Nilsson //! Comparision function between two "date" mappings of the //! kind that @[parse_time] returns. int(-1..1) time_compare(mapping(string:int) t1, mapping(string:int) t2)
6913ab1999-03-22Niels Möller { foreach( ({ "year", "mon", "mday", "hour", "min", "sec" }), string name)
8887f02001-10-08Per Hedbor  if (t1[name] < t2[name]) return -1; else if (t1[name] > t2[name]) return 1;
6913ab1999-03-22Niels Möller  return 0; }
38333a1999-03-02Niels Möller 
cd16db2003-01-26Martin Nilsson MetaExplicit extension_sequence = MetaExplicit(2, 3); MetaExplicit version_integer = MetaExplicit(2, 0);
0ecba92000-08-01Andreas Sigfridsson 
566f582011-01-27Henrik Grubbström (Grubba) Sequence rsa_public_key = Sequence( ({ Identifiers.rsa_id, Null() }));
cd16db2003-01-26Martin Nilsson Sequence rsa_md2_algorithm = Sequence( ({ Identifiers.rsa_md2_id, Null() }) );
5b546b1999-03-23Niels Möller 
cd16db2003-01-26Martin Nilsson Sequence rsa_md5_algorithm = Sequence( ({ Identifiers.rsa_md5_id, Null() }) );
5b546b1999-03-23Niels Möller 
cd16db2003-01-26Martin Nilsson Sequence rsa_sha1_algorithm = Sequence( ({ Identifiers.rsa_sha1_id, Null() }) );
5b546b1999-03-23Niels Möller 
566f582011-01-27Henrik Grubbström (Grubba) Sequence dsa_sha1_algorithm = Sequence( ({ Identifiers.dsa_sha_id }) );
cd16db2003-01-26Martin Nilsson //! Sequence make_tbs(object issuer, object algorithm,
38333a1999-03-02Niels Möller  object subject, object keyinfo, object serial, int ttl, array extensions) { int now = time();
cd16db2003-01-26Martin Nilsson  Sequence validity = Sequence( ({ make_time(now), make_time(now + ttl) }) );
38333a1999-03-02Niels Möller  return (extensions
cd16db2003-01-26Martin Nilsson  ? Sequence( ({ version_integer(Integer(2)), /* Version 3 */ serial, algorithm, issuer, validity, subject, keyinfo, extension_sequence(extensions) }) ) : Sequence( ({ serial, algorithm, issuer, validity, subject, keyinfo }) ));
38333a1999-03-02Niels Möller }
cd16db2003-01-26Martin Nilsson //!
566f582011-01-27Henrik Grubbström (Grubba) //! @param issuer //! Distinguished name for the issuer. //! //! @param rsa //! RSA parameters for the issuer. //! //! @param subject //! Distinguished name for the subject. //! //! @param public_key //! DER-encoded integer. //! See @[Standards.PKCS.DSA.public_key()]. //! //! @param serial //! Serial number for this key and issuer. //! //! @param ttl //! Validity time in seconds for this signature to be valid. //! //! @param extensions //! Set of extensions. //! //! @returns //! Returns a DER-encoded certificate. string dsa_sign_key(Sequence issuer, Crypto.DSA dsa, Sequence subject, string public_key, int serial, int ttl, array|void extensions) { Sequence tbs = make_tbs(issuer, dsa_sha1_algorithm, subject, Sequence(({ DSA.algorithm_identifier(dsa), BitString(public_key) }) ), Integer(serial), ttl, extensions); string digest = tbs->get_der(); return Sequence(({ tbs, dsa_sha1_algorithm, BitString(dsa->sign_ssl(digest)) }))->get_der(); } //!
34ec152004-02-07Martin Nilsson string make_selfsigned_dsa_certificate(Crypto.DSA dsa, int ttl, array name,
38333a1999-03-02Niels Möller  array|void extensions) {
566f582011-01-27Henrik Grubbström (Grubba)  int serial = (int)Gmp.bignum(Standards.UUID.make_version1(-1)->encode(), 256);
38333a1999-03-02Niels Möller 
cd16db2003-01-26Martin Nilsson  Sequence dn = Certificate.build_distinguished_name(@name);
566f582011-01-27Henrik Grubbström (Grubba)  return dsa_sign_key(dn, dsa, dn, DSA.public_key(dsa), serial, ttl, extensions);
38333a1999-03-02Niels Möller }
cd16db2003-01-26Martin Nilsson //!
34adca2004-02-03Martin Nilsson string rsa_sign_digest(Crypto.RSA rsa, object digest_id, string digest)
38333a1999-03-02Niels Möller {
cd16db2003-01-26Martin Nilsson  Sequence digest_info = Sequence( ({ Sequence( ({ digest_id, Null() }) ), OctetString(digest) }) );
38333a1999-03-02Niels Möller  return rsa->raw_sign(digest_info->get_der())->digits(256); }
6913ab1999-03-22Niels Möller 
cd16db2003-01-26Martin Nilsson //!
34adca2004-02-03Martin Nilsson int(0..1) rsa_verify_digest(Crypto.RSA rsa, object digest_id,
0324132004-01-27Martin Nilsson  string digest, string s)
6913ab1999-03-22Niels Möller {
cd16db2003-01-26Martin Nilsson  Sequence digest_info = Sequence( ({ Sequence( ({ digest_id, Null() }) ), OctetString(digest) }) );
6913ab1999-03-22Niels Möller  return rsa->raw_verify(digest_info->get_der(), Gmp.mpz(s, 256)); }
cd16db2003-01-26Martin Nilsson //!
566f582011-01-27Henrik Grubbström (Grubba) //! @param issuer //! Distinguished name for the issuer. //! //! @param rsa //! RSA parameters for the issuer. //! //! @param subject //! Distinguished name for the issuer. //! //! @param public_key //! DER-encoded RSAPublicKey structure. //! See @[Standards.PKCS.RSA.public_key()]. //! //! @param serial //! Serial number for this key and subject. //! //! @param ttl //! Validity time in seconds for this signature to be valid. //! //! @param extensions //! Set of extensions. //! //! @returns //! Returns a DER-encoded certificate. string rsa_sign_key(Sequence issuer, Crypto.RSA rsa, Sequence subject, string public_key, int serial, int ttl, array|void extensions) { Sequence tbs = make_tbs(issuer, rsa_sha1_algorithm, subject, Sequence(({ rsa_public_key, BitString(public_key) }) ), Integer(serial), ttl, extensions); string digest = Crypto.SHA1.hash(tbs->get_der()); return Sequence(({ tbs, rsa_sha1_algorithm, BitString(rsa_sign_digest(rsa, Identifiers.sha1_id, digest)) }))->get_der(); } //!
34adca2004-02-03Martin Nilsson string make_selfsigned_rsa_certificate(Crypto.RSA rsa, int ttl, array name,
38333a1999-03-02Niels Möller  array|void extensions) {
566f582011-01-27Henrik Grubbström (Grubba)  int serial = (int)Gmp.bignum(Standards.UUID.make_version1(-1)->encode(), 256);
38333a1999-03-02Niels Möller 
cd16db2003-01-26Martin Nilsson  Sequence dn = Certificate.build_distinguished_name(@name);
566f582011-01-27Henrik Grubbström (Grubba)  return rsa_sign_key(dn, rsa, dn, RSA.public_key(rsa), serial, ttl, extensions);
38333a1999-03-02Niels Möller }
5716682004-01-25Martin Nilsson class Verifier { constant type = "none"; int(0..1) verify(object,string,string); this_program init(string key);
34adca2004-02-03Martin Nilsson  optional Crypto.RSA rsa; // Ugly
5716682004-01-25Martin Nilsson }
cd16db2003-01-26Martin Nilsson //!
6913ab1999-03-22Niels Möller class rsa_verifier {
5716682004-01-25Martin Nilsson  inherit Verifier;
34adca2004-02-03Martin Nilsson  Crypto.RSA rsa;
6913ab1999-03-22Niels Möller  constant type = "rsa";
cd16db2003-01-26Martin Nilsson  //!
5716682004-01-25Martin Nilsson  this_program init(string key) {
cd16db2003-01-26Martin Nilsson  rsa = RSA.parse_public_key(key);
563bd72004-01-11Martin Nilsson  return rsa && this;
cd16db2003-01-26Martin Nilsson  }
0ecba92000-08-01Andreas Sigfridsson 
cd16db2003-01-26Martin Nilsson  //!
0324132004-01-27Martin Nilsson  int(0..1) verify(Sequence algorithm, string msg, string signature)
cd16db2003-01-26Martin Nilsson  { if (algorithm->get_der() == rsa_md5_algorithm->get_der()) return rsa_verify_digest(rsa, Identifiers.md5_id,
e528d42003-11-30Martin Nilsson  Crypto.MD5.hash(msg),
cd16db2003-01-26Martin Nilsson  signature); if (algorithm->get_der() == rsa_sha1_algorithm->get_der()) return rsa_verify_digest(rsa, Identifiers.sha1_id,
df64692004-02-05Martin Nilsson  Crypto.SHA1.hash(msg),
cd16db2003-01-26Martin Nilsson  signature);
f9770e2004-03-19Martin Nilsson #if constant(Crypto.MD2.hash)
cd16db2003-01-26Martin Nilsson  if (algorithm->get_der() == rsa_md2_algorithm->get_der()) return rsa_verify_digest(rsa, Identifiers.md2_id,
e528d42003-11-30Martin Nilsson  Crypto.MD2.hash(msg),
cd16db2003-01-26Martin Nilsson  signature);
f9770e2004-03-19Martin Nilsson #endif
cd16db2003-01-26Martin Nilsson  return 0; }
6913ab1999-03-22Niels Möller } #if 0 /* FIXME: This is a little more difficult, as the dsa-parameters are * sometimes taken from the CA, and not present in the keyinfo. */
a15f121999-06-08Martin Stjernholm class dsa_verifier
6913ab1999-03-22Niels Möller {
5716682004-01-25Martin Nilsson  inherit Verifier;
6913ab1999-03-22Niels Möller  object dsa; constant type = "dsa"; object init(string key) { } } #endif
cd16db2003-01-26Martin Nilsson //!
0324132004-01-27Martin Nilsson Verifier make_verifier(Object _keyinfo)
6913ab1999-03-22Niels Möller {
0324132004-01-27Martin Nilsson  if( _keyinfo->type_name != "SEQUENCE" ) return 0; Sequence keyinfo = [object(Sequence)]_keyinfo;
6913ab1999-03-22Niels Möller  if ( (keyinfo->type_name != "SEQUENCE") || (sizeof(keyinfo->elements) != 2) || (keyinfo->elements[0]->type_name != "SEQUENCE")
0324132004-01-27Martin Nilsson  || !sizeof(([object(Sequence)]keyinfo->elements[0])->elements)
6913ab1999-03-22Niels Möller  || (keyinfo->elements[1]->type_name != "BIT STRING") || keyinfo->elements[1]->unused) return 0;
0324132004-01-27Martin Nilsson  if (([object(Sequence)]keyinfo->elements[0])->elements[0]->get_der()
6913ab1999-03-22Niels Möller  == Identifiers.rsa_id->get_der()) {
0324132004-01-27Martin Nilsson  if ( (sizeof(([object(Sequence)]keyinfo->elements[0])->elements) != 2) || (([object(Sequence)]keyinfo->elements[0])->elements[1]->get_der()
cd16db2003-01-26Martin Nilsson  != Null()->get_der()))
6913ab1999-03-22Niels Möller  return 0;
0324132004-01-27Martin Nilsson  return rsa_verifier()->init(([object(Sequence)]keyinfo->elements[1]) ->value);
6913ab1999-03-22Niels Möller  }
cd16db2003-01-26Martin Nilsson 
0324132004-01-27Martin Nilsson  if(([object(Sequence)]keyinfo->elements[0])->elements[0]->get_der()
cd16db2003-01-26Martin Nilsson  == Identifiers.dsa_sha_id->get_der())
6913ab1999-03-22Niels Möller  { /* FIXME: Not implemented */ return 0; } }
cd16db2003-01-26Martin Nilsson //!
6913ab1999-03-22Niels Möller class TBSCertificate {
ebb5be2004-03-22H. William Welliver III  //!
6913ab1999-03-22Niels Möller  string der;
ebb5be2004-03-22H. William Welliver III  //!
6913ab1999-03-22Niels Möller  int version;
ebb5be2004-03-22H. William Welliver III  //!
5ffbc42004-01-30Martin Nilsson  Gmp.mpz serial;
ebb5be2004-03-22H. William Welliver III  //!
5ffbc42004-01-30Martin Nilsson  Sequence algorithm; /* Algorithm Identifier */
ebb5be2004-03-22H. William Welliver III  //!
5ffbc42004-01-30Martin Nilsson  Sequence issuer;
ebb5be2004-03-22H. William Welliver III  //!
6913ab1999-03-22Niels Möller  mapping not_after;
ebb5be2004-03-22H. William Welliver III  //!
6913ab1999-03-22Niels Möller  mapping not_before;
ebb5be2004-03-22H. William Welliver III  //!
5ffbc42004-01-30Martin Nilsson  Sequence subject;
ebb5be2004-03-22H. William Welliver III  //!
5716682004-01-25Martin Nilsson  Verifier public_key;
6913ab1999-03-22Niels Möller  /* Optional */
ebb5be2004-03-22H. William Welliver III  //! @note //! optional
5ffbc42004-01-30Martin Nilsson  BitString issuer_id;
ebb5be2004-03-22H. William Welliver III  //! @note //! optional
5ffbc42004-01-30Martin Nilsson  BitString subject_id;
ebb5be2004-03-22H. William Welliver III  //! @note //! optional
6913ab1999-03-22Niels Möller  object extensions;
ebb5be2004-03-22H. William Welliver III  //!
cd16db2003-01-26Martin Nilsson  this_program init(Object asn1) { der = asn1->get_der(); if (asn1->type_name != "SEQUENCE") return 0;
6913ab1999-03-22Niels Möller 
0324132004-01-27Martin Nilsson  array(Object) a = ([object(Sequence)]asn1)->elements;
cd16db2003-01-26Martin Nilsson  X509_WERR("TBSCertificate: sizeof(a) = %d\n", sizeof(a));
5b546b1999-03-23Niels Möller 
cd16db2003-01-26Martin Nilsson  if (sizeof(a) < 6) return 0; if (sizeof(a) > 6) { /* The optional version field must be present */ if (!a[0]->constructed || (a[0]->get_combined_tag() != make_combined_tag(2, 0)) || (sizeof(a[0]->elements) != 1) || (a[0]->elements[0]->type_name != "INTEGER"))
6913ab1999-03-22Niels Möller  return 0;
cd16db2003-01-26Martin Nilsson  version = (int) a[0]->elements[0]->value + 1; if ( (version < 2) || (version > 3))
6913ab1999-03-22Niels Möller  return 0;
cd16db2003-01-26Martin Nilsson  a = a[1..]; } else version = 1; X509_WERR("TBSCertificate: version = %d\n", version); if (a[0]->type_name != "INTEGER") return 0; serial = a[0]->value;
5b546b1999-03-23Niels Möller 
cd16db2003-01-26Martin Nilsson  X509_WERR("TBSCertificate: serial = %s\n", (string) serial);
6913ab1999-03-22Niels Möller 
cd16db2003-01-26Martin Nilsson  if ((a[1]->type_name != "SEQUENCE") || !sizeof(a[1]->elements ) || (a[1]->elements[0]->type_name != "OBJECT IDENTIFIER")) return 0;
6913ab1999-03-22Niels Möller 
cd16db2003-01-26Martin Nilsson  algorithm = a[1];
6913ab1999-03-22Niels Möller 
cd16db2003-01-26Martin Nilsson  X509_WERR("TBSCertificate: algorithm = %s\n", algorithm->debug_string());
5b546b1999-03-23Niels Möller 
cd16db2003-01-26Martin Nilsson  if (a[2]->type_name != "SEQUENCE") return 0; issuer = a[2];
6913ab1999-03-22Niels Möller 
cd16db2003-01-26Martin Nilsson  X509_WERR("TBSCertificate: issuer = %s\n", issuer->debug_string());
5b546b1999-03-23Niels Möller 
cd16db2003-01-26Martin Nilsson  if ((a[3]->type_name != "SEQUENCE") || (sizeof(a[3]->elements) != 2)) return 0;
6913ab1999-03-22Niels Möller 
cd16db2003-01-26Martin Nilsson  array validity = a[3]->elements;
6913ab1999-03-22Niels Möller 
cd16db2003-01-26Martin Nilsson  not_before = parse_time(validity[0]); if (!not_before) return 0;
6913ab1999-03-22Niels Möller 
cd16db2003-01-26Martin Nilsson  X509_WERR("TBSCertificate: not_before = %O\n", not_before);
5b546b1999-03-23Niels Möller 
cd16db2003-01-26Martin Nilsson  not_after = parse_time(validity[1]); if (!not_after) return 0;
5b546b1999-03-23Niels Möller 
cd16db2003-01-26Martin Nilsson  X509_WERR("TBSCertificate: not_after = %O\n", not_after);
5b546b1999-03-23Niels Möller 
cd16db2003-01-26Martin Nilsson  if (a[4]->type_name != "SEQUENCE") return 0; subject = a[4];
5b546b1999-03-23Niels Möller 
cd16db2003-01-26Martin Nilsson  X509_WERR("TBSCertificate: keyinfo = %s\n", a[5]->debug_string());
5b546b1999-03-23Niels Möller 
cd16db2003-01-26Martin Nilsson  public_key = make_verifier(a[5]);
5b546b1999-03-23Niels Möller 
cd16db2003-01-26Martin Nilsson  if (!public_key) return 0;
5b546b1999-03-23Niels Möller 
cd16db2003-01-26Martin Nilsson  X509_WERR("TBSCertificate: parsed public key. type = %s\n", public_key->type);
6913ab1999-03-22Niels Möller 
cd16db2003-01-26Martin Nilsson  int i = 6; if (i == sizeof(a))
563bd72004-01-11Martin Nilsson  return this;
6913ab1999-03-22Niels Möller 
cd16db2003-01-26Martin Nilsson  if (version < 2)
6913ab1999-03-22Niels Möller  return 0;
cd16db2003-01-26Martin Nilsson  if (! a[i]->constructed && (a[i]->combined_tag == make_combined_tag(2, 1))) { issuer_id = BitString()->decode_primitive(a[i]->raw); i++; if (i == sizeof(a))
563bd72004-01-11Martin Nilsson  return this;
6913ab1999-03-22Niels Möller  }
cd16db2003-01-26Martin Nilsson  if (! a[i]->constructed && (a[i]->combined_tag == make_combined_tag(2, 2))) { subject_id = BitString()->decode_primitive(a[i]->raw); i++; if (i == sizeof(a))
563bd72004-01-11Martin Nilsson  return this;
cd16db2003-01-26Martin Nilsson  } if (a[i]->constructed && (a[i]->combined_tag == make_combined_tag(2, 3))) { extensions = a[i]; i++; if (i == sizeof(a))
563bd72004-01-11Martin Nilsson  return this;
cd16db2003-01-26Martin Nilsson  } /* Too many fields */ return 0; } }
6913ab1999-03-22Niels Möller 
cd16db2003-01-26Martin Nilsson //! TBSCertificate decode_certificate(string|object cert)
6913ab1999-03-22Niels Möller {
a15f121999-06-08Martin Stjernholm  if (stringp (cert)) cert = Standards.ASN1.Decode.simple_der_decode(cert);
6913ab1999-03-22Niels Möller  if (!cert || (cert->type_name != "SEQUENCE") || (sizeof(cert->elements) != 3) || (cert->elements[0]->type_name != "SEQUENCE") || (cert->elements[1]->type_name != "SEQUENCE") || (!sizeof(cert->elements[1]->elements)) || (cert->elements[1]->elements[0]->type_name != "OBJECT IDENTIFIER") || (cert->elements[2]->type_name != "BIT STRING") || cert->elements[2]->unused) return 0;
cd16db2003-01-26Martin Nilsson  TBSCertificate tbs = TBSCertificate()->init(cert->elements[0]);
6913ab1999-03-22Niels Möller 
5b546b1999-03-23Niels Möller  if (!tbs || (cert->elements[1]->get_der() != tbs->algorithm->get_der()))
6913ab1999-03-22Niels Möller  return 0;
a15f121999-06-08Martin Stjernholm  return tbs; }
cd16db2003-01-26Martin Nilsson //! Decodes a certificate, checks the signature. Returns the //! TBSCertificate structure, or 0 if decoding or verification failes. //! //! Authorities is a mapping from (DER-encoded) names to a verifiers. //! //! @note //! This function allows self-signed certificates, and it doesn't //! check that names or extensions make sense. TBSCertificate verify_certificate(string s, mapping authorities)
a15f121999-06-08Martin Stjernholm { object cert = Standards.ASN1.Decode.simple_der_decode(s);
cd16db2003-01-26Martin Nilsson  TBSCertificate tbs = decode_certificate(cert);
a15f121999-06-08Martin Stjernholm  if (!tbs) return 0;
6913ab1999-03-22Niels Möller  object v; if (tbs->issuer->get_der() == tbs->subject->get_der()) { /* A self signed certificate */
0ecba92000-08-01Andreas Sigfridsson  X509_WERR("Self signed certificate\n");
6913ab1999-03-22Niels Möller  v = tbs->public_key; } else v = authorities[tbs->issuer->get_der()]; return v && v->verify(cert->elements[1], cert->elements[0]->get_der(), cert->elements[2]->value) && tbs; }
92dbd31999-08-24Fredrik Hübinette (Hubbe) 
875a0c2004-02-04H. William Welliver III //! Decodes a certificate chain, checks the signatures. Verifies that the //! chain is unbroken, and that all certificates are in effect //! (time-wise.) //! //! Returns a mapping with the following contents, depending //! on the verification of the certificate chain:
cd16db2003-01-26Martin Nilsson //! //! @mapping
875a0c2004-02-04H. William Welliver III //! @member int "error_code" //! Error describing type of verification failure, if verification failed. //! May be one of the following: @[CERT_TOO_NEW], @[CERT_TOO_OLD],
ebb5be2004-03-22H. William Welliver III //! @[CERT_ROOT_UNTRUSTED], @[CERT_BAD_SIGNATURE], @[CERT_INVALID], //! @[CERT_UNAUTHORIZED_CA] or @[CERT_CHAIN_BROKEN]
875a0c2004-02-04H. William Welliver III //! @member int "error_cert" //! Index number of the certificate that caused the verification failure.
cd16db2003-01-26Martin Nilsson //! @member int(0..1) "self_signed" //! Non-zero if the certificate is self-signed. //! @member int(0..1) "verified" //! Non-zero if the certificate is verified. //! @member string "authority"
3243a32004-02-05Martin Nilsson //! @[Standards.ASN1.Sequence] of the authority RDN that verified //! the chain.
7680a32004-01-29H. William Welliver III //! @member string "cn"
3243a32004-02-05Martin Nilsson //! @[Standards.ASN1.Sequence] of the common name RDN of the leaf //! certificate.
cd16db2003-01-26Martin Nilsson //! @endmapping //!
7680a32004-01-29H. William Welliver III //! @param cert_chain
bb53b12012-05-20Martin Nilsson //! An array of certificates, with the relative-root last. Each //! certificate should be a DER-encoded certificate.
cd16db2003-01-26Martin Nilsson //! @param authorities //! A mapping from (DER-encoded) names to verifiers.
ebb5be2004-03-22H. William Welliver III //! @param require_trust
3243a32004-02-05Martin Nilsson //! Require that the certificate be traced to an authority, even if //! it is self signed.
7680a32004-01-29H. William Welliver III //!
3243a32004-02-05Martin Nilsson //! See @[Standards.PKCS.Certificate.get_dn_string] for converting the //! RDN to an X500 style string. mapping verify_certificate_chain(array(string) cert_chain, mapping authorities, int|void require_trust)
27677e2000-10-22Andreas Sigfridsson {
7680a32004-01-29H. William Welliver III 
27677e2000-10-22Andreas Sigfridsson  mapping m = ([ ]);
bb53b12012-05-20Martin Nilsson  int len = sizeof(cert_chain); array chain_obj = allocate(len); array chain_cert = allocate(len);
875a0c2004-02-04H. William Welliver III  foreach(cert_chain; int idx; string c)
27677e2000-10-22Andreas Sigfridsson  {
7680a32004-01-29H. William Welliver III  object cert = Standards.ASN1.Decode.simple_der_decode(c); TBSCertificate tbs = decode_certificate(cert);
875a0c2004-02-04H. William Welliver III  if(!tbs) { m->error_code = CERT_INVALID; m->error_cert = idx; return m; }
bb53b12012-05-20Martin Nilsson  int idx = len-idx-1; chain_cert[idx] = cert; chain_obj[idx] = tbs;
7680a32004-01-29H. William Welliver III  }
27677e2000-10-22Andreas Sigfridsson 
7680a32004-01-29H. William Welliver III  foreach(chain_obj; int idx; TBSCertificate tbs) {
27677e2000-10-22Andreas Sigfridsson  object v;
376afd2004-03-25H. William Welliver III  #if 0
44ad482004-03-25H. William Welliver III  // NOTE: disabled due to unreliable presence of cA constraint. //
ebb5be2004-03-22H. William Welliver III  // if we are a CA certificate (we don't care about the end cert) // make sure the CA constraint is set. // // should we be considering self signed certificates? if(idx != (sizeof(chain_obj)-1)) { int caok = 0; if(tbs->extensions && sizeof(tbs->extensions)) {
44ad482004-03-25H. William Welliver III  werror("have extensions.\n");
ebb5be2004-03-22H. William Welliver III  foreach(tbs->extensions->elements[0]->elements, Sequence c) {
44ad482004-03-25H. William Welliver III  werror("checking each element...\n");
ebb5be2004-03-22H. William Welliver III  if(c->elements[0] == Identifiers.ce_id->append(19)) {
44ad482004-03-25H. William Welliver III  werror("have a basic constraints element.\n");
ebb5be2004-03-22H. William Welliver III  foreach(c->elements[1..], Sequence v) { werror("checking for boolean: " + v->type_name + " " + v->value + "\n"); if(v->type_name == "BOOLEAN" && v->value == 1) caok = 1; } } } } if(! caok) { X509_WERR("a CA certificate does not have the CA basic constraint.\n"); m->error_code = CERT_UNAUTHORIZED_CA; m->error_cert = idx; return m; } }
376afd2004-03-25H. William Welliver III #endif /* 0 */
7680a32004-01-29H. William Welliver III  if(idx == 0) // The root cert {
27677e2000-10-22Andreas Sigfridsson  v = authorities[tbs->issuer->get_der()];
7680a32004-01-29H. William Welliver III 
3243a32004-02-05Martin Nilsson  // if we don't know the issuer of the root certificate, and we // require trust, we're done.
7680a32004-01-29H. William Welliver III  if(!v && require_trust) { X509_WERR("we require trust, but haven't got it.\n");
875a0c2004-02-04H. William Welliver III  m->error_code = CERT_ROOT_UNTRUSTED; m->error_cert = idx;
7680a32004-01-29H. William Welliver III  return m; } // is the root self signed? if (tbs->issuer->get_der() == tbs->subject->get_der()) { /* A self signed certificate */ m->self_signed = 1; X509_WERR("Self signed certificate\n"); // always trust our own authority first, even if it is self signed. if(!v) v = tbs->public_key; } } else // otherwise, we make sure the chain is unbroken.
27677e2000-10-22Andreas Sigfridsson  {
875a0c2004-02-04H. William Welliver III  // is the certificate in effect (time-wise)? int my_time = time(); // first check not_before. we want the current time to be later. if(my_time < mktime(tbs->not_before)) { m->verified = 0; m->error_code = CERT_TOO_NEW; m->error_cert = idx; return m; } // first check not_after. we want the current time to be earlier. if(my_time > mktime(tbs->not_after)) { m->verified = 0; m->error_code = CERT_TOO_OLD; m->error_cert = idx; return m; }
3243a32004-02-05Martin Nilsson  // is the issuer of this certificate the subject of the previous // (more rootward) certificate?
7680a32004-01-29H. William Welliver III  if(tbs->issuer->get_der() != chain_obj[idx-1]->subject->get_der()) { X509_WERR("issuer chain is broken!\n");
875a0c2004-02-04H. William Welliver III  m->verified = 0; m->error_code = CERT_CHAIN_BROKEN; m->error_cert = idx;
7680a32004-01-29H. William Welliver III  return m; }
3243a32004-02-05Martin Nilsson  // the verifier for this certificate should be the public key of // the previous certificate in the chain.
7680a32004-01-29H. William Welliver III  v = chain_obj[idx-1]->public_key;
27677e2000-10-22Andreas Sigfridsson  }
bb53b12012-05-20Martin Nilsson  if (v)
27677e2000-10-22Andreas Sigfridsson  {
bb53b12012-05-20Martin Nilsson  if( v->verify(chain_cert[idx]->elements[1], chain_cert[idx]->elements[0]->get_der(), chain_cert[idx]->elements[2]->value) && tbs) { X509_WERR("signature is verified..\n"); m->verified = 1;
7680a32004-01-29H. William Welliver III 
bb53b12012-05-20Martin Nilsson  // if we're the root of the chain and we've verified, this is // the authority. if(idx == 0) m->authority = tbs->issuer;
7680a32004-01-29H. William Welliver III 
bb53b12012-05-20Martin Nilsson  if(idx == sizeof(chain_cert)-1) m->cn = tbs->subject; } else { X509_WERR("signature _not_ verified...\n"); m->error_code = CERT_BAD_SIGNATURE; m->error_cert = idx; m->verified = 0; return m; }
27677e2000-10-22Andreas Sigfridsson  } } return m; }
ea382e2000-03-10Martin Nilsson #endif