a580e12000-09-27Fredrik Hübinette (Hubbe) #pike __REAL_VERSION__
a20af62000-09-26Fredrik Hübinette (Hubbe) 
cb74682000-05-25Andreas Sigfridsson /*
563bd72004-01-11Martin Nilsson  * $Id: X509.pmod,v 1.21 2004/01/11 00:40:49 nilsson Exp $
38333a1999-03-02Niels Möller  * * Some random functions for creating RFC-2459 style X.509 certificates. * */
cd16db2003-01-26Martin Nilsson #if constant(Standards.ASN1.Types.Sequence)
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
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 {
8887f02001-10-08Per Hedbor  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. */
6913ab1999-03-22Niels Möller  mapping m = mkmapping( ({ "year", "mon", "mday", "hour", "min", "sec" }),
5b546b1999-03-23Niels Möller  (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--;
0ecba92000-08-01Andreas Sigfridsson  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 
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 
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 //!
5ae6b81999-03-09Niels Möller string make_selfsigned_dsa_certificate(object dsa, int ttl, array name,
38333a1999-03-02Niels Möller  array|void extensions) {
cd16db2003-01-26Martin Nilsson  Integer serial = Integer(1); /* Hard coded serial number */
38333a1999-03-02Niels Möller  int now = time();
cd16db2003-01-26Martin Nilsson  Sequence validity = Sequence( ({ make_time(now), make_time(now + ttl) }) );
38333a1999-03-02Niels Möller 
cd16db2003-01-26Martin Nilsson  Sequence signature_algorithm = Sequence( ({ Identifiers.dsa_sha_id }) );
38333a1999-03-02Niels Möller 
cd16db2003-01-26Martin Nilsson  Sequence keyinfo = Sequence(
38333a1999-03-02Niels Möller  ({ /* Use an identifier with parameters */
5ae6b81999-03-09Niels Möller  DSA.algorithm_identifier(dsa),
cd16db2003-01-26Martin Nilsson  BitString(DSA.public_key(dsa)) }) );
38333a1999-03-02Niels Möller 
cd16db2003-01-26Martin Nilsson  Sequence dn = Certificate.build_distinguished_name(@name);
5ae6b81999-03-09Niels Möller 
cd16db2003-01-26Martin Nilsson  Sequence tbs = make_tbs(dn, signature_algorithm, dn, keyinfo, serial, ttl, extensions);
38333a1999-03-02Niels Möller 
cd16db2003-01-26Martin Nilsson  return Sequence(
38333a1999-03-02Niels Möller  ({ tbs,
627de51999-03-15Niels Möller  signature_algorithm,
cd16db2003-01-26Martin Nilsson  BitString(dsa->sign_ssl(tbs->get_der())) }))->get_der();
38333a1999-03-02Niels Möller }
cd16db2003-01-26Martin Nilsson //!
38333a1999-03-02Niels Möller string rsa_sign_digest(object rsa, object digest_id, string digest) {
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 //!
6913ab1999-03-22Niels Möller int rsa_verify_digest(object rsa, object digest_id, string digest, string s) {
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 //!
38333a1999-03-02Niels Möller string make_selfsigned_rsa_certificate(object rsa, int ttl, array name, array|void extensions) {
cd16db2003-01-26Martin Nilsson  Integer serial = Integer(1); /* Hard coded serial number */
38333a1999-03-02Niels Möller  int now = time();
cd16db2003-01-26Martin Nilsson  Sequence validity = Sequence( ({ make_time(now), make_time(now + ttl) }) );
38333a1999-03-02Niels Möller 
cd16db2003-01-26Martin Nilsson  Sequence signature_algorithm = Sequence( ({ Identifiers.rsa_sha1_id, Null() }) );
38333a1999-03-02Niels Möller 
cd16db2003-01-26Martin Nilsson  Sequence keyinfo = Sequence( ({ Sequence( ({ Identifiers.rsa_id, Null() }) ), BitString(RSA.public_key(rsa)) }) );
38333a1999-03-02Niels Möller 
cd16db2003-01-26Martin Nilsson  Sequence dn = Certificate.build_distinguished_name(@name);
38333a1999-03-02Niels Möller 
cd16db2003-01-26Martin Nilsson  Sequence tbs = make_tbs(dn, rsa_sha1_algorithm, dn, keyinfo, serial, ttl, extensions);
e528d42003-11-30Martin Nilsson 
cd16db2003-01-26Martin Nilsson  return Sequence(
38333a1999-03-02Niels Möller  ({ tbs,
5b546b1999-03-23Niels Möller  rsa_sha1_algorithm,
cd16db2003-01-26Martin Nilsson  BitString(rsa_sign_digest(rsa, Identifiers.sha1_id,
db20452003-12-03Martin Nilsson #if constant(Crypto.SHA.name)
e528d42003-11-30Martin Nilsson  Crypto.SHA.hash(tbs->get_der()) #else Crypto.sha()->update(tbs->get_der())->digest() #endif )) }) )->get_der();
38333a1999-03-02Niels Möller }
cd16db2003-01-26Martin Nilsson //!
6913ab1999-03-22Niels Möller class rsa_verifier { object rsa; constant type = "rsa";
cd16db2003-01-26Martin Nilsson  //!
6913ab1999-03-22Niels Möller  object 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  //!
6913ab1999-03-22Niels Möller  int verify(object 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,
db20452003-12-03Martin Nilsson #if constant(Crypto.MD5.name)
e528d42003-11-30Martin Nilsson  Crypto.MD5.hash(msg), #else
cd16db2003-01-26Martin Nilsson  Crypto.md5()->update(msg)->digest(),
e528d42003-11-30Martin Nilsson #endif
cd16db2003-01-26Martin Nilsson  signature); if (algorithm->get_der() == rsa_sha1_algorithm->get_der()) return rsa_verify_digest(rsa, Identifiers.sha1_id,
db20452003-12-03Martin Nilsson #if constant(Crypto.SHA.name)
e528d42003-11-30Martin Nilsson  Crypto.SHA.hash(msg), #else
cd16db2003-01-26Martin Nilsson  Crypto.sha()->update(msg)->digest(),
e528d42003-11-30Martin Nilsson #endif
cd16db2003-01-26Martin Nilsson  signature); if (algorithm->get_der() == rsa_md2_algorithm->get_der()) return rsa_verify_digest(rsa, Identifiers.md2_id,
db20452003-12-03Martin Nilsson #if constant(Crypto.MD2.name)
e528d42003-11-30Martin Nilsson  Crypto.MD2.hash(msg), #else
cd16db2003-01-26Martin Nilsson  Crypto.md2()->update(msg)->digest(),
e528d42003-11-30Martin Nilsson #endif
cd16db2003-01-26Martin Nilsson  signature); 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 { object dsa; constant type = "dsa"; object init(string key) { } } #endif
cd16db2003-01-26Martin Nilsson //! rsa_verifier make_verifier(object keyinfo)
6913ab1999-03-22Niels Möller { if ( (keyinfo->type_name != "SEQUENCE") || (sizeof(keyinfo->elements) != 2) || (keyinfo->elements[0]->type_name != "SEQUENCE") || !sizeof(keyinfo->elements[0]->elements) || (keyinfo->elements[1]->type_name != "BIT STRING") || keyinfo->elements[1]->unused) return 0; if (keyinfo->elements[0]->elements[0]->get_der() == Identifiers.rsa_id->get_der()) { if ( (sizeof(keyinfo->elements[0]->elements) != 2) || (keyinfo->elements[0]->elements[1]->get_der()
cd16db2003-01-26Martin Nilsson  != Null()->get_der()))
6913ab1999-03-22Niels Möller  return 0;
5b546b1999-03-23Niels Möller  return rsa_verifier()->init(keyinfo->elements[1]->value);
6913ab1999-03-22Niels Möller  }
cd16db2003-01-26Martin Nilsson  if(keyinfo->elements[0]->elements[0]->get_der() == 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 { string der; int version; object serial; object algorithm; /* Algorithm Identifier */ object issuer; mapping not_after; mapping not_before; object subject; object public_key; /* Optional */ object issuer_id; object subject_id; object extensions;
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 
cd16db2003-01-26Martin Nilsson  array a = asn1->elements; 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) 
cd16db2003-01-26Martin Nilsson //! Decodes a certificate chain, checks the signatures. Returns a mapping //! with the following contents, depending on the verification of the //! certificate chain: //! //! @mapping //! @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" //! DER-encoded name of the authority that verified the chain. //! @endmapping //! //! @param authorities //! A mapping from (DER-encoded) names to verifiers.
27677e2000-10-22Andreas Sigfridsson mapping verify_certificate_chain(array(string) cert_chain, mapping authorities) { mapping m = ([ ]); for(int i=0; i<sizeof(cert_chain); i++) { object cert = Standards.ASN1.Decode.simple_der_decode(cert_chain[i]); object(TBSCertificate) tbs = decode_certificate(cert); if (!tbs) return m; object v; if(i == sizeof(cert_chain)-1) // Last cert v = authorities[tbs->issuer->get_der()]; if (!v && tbs->issuer->get_der() == tbs->subject->get_der()) { /* A self signed certificate */ m->self_signed = 1; X509_WERR("Self signed certificate\n"); v = tbs->public_key; } else v = authorities[tbs->issuer->get_der()]; if (v && v->verify(cert->elements[1], cert->elements[0]->get_der(), cert->elements[2]->value) && tbs) { m->authority = tbs->issuer->get_der(); if(v == authorities[tbs->issuer->get_der()]) m->verified = 1; } } return m; }
ea382e2000-03-10Martin Nilsson #endif