cb74682000-05-25Andreas Sigfridsson /* * $Id: X509.pmod,v 1.9 2000/05/25 20:20:31 sigge Exp $
38333a1999-03-02Niels Möller  * * Some random functions for creating RFC-2459 style X.509 certificates. * */
92dbd31999-08-24Fredrik Hübinette (Hubbe) #if constant(Standards.ASN1.Types.asn1_sequence)
38333a1999-03-02Niels Möller import Standards.ASN1.Types; import Standards.PKCS; object make_time(int t) { mapping m = gmtime(t); if (m->year >= 150) throw( ({ "Tools.X509.make_time: " "Times later than 2049 not supported yet\n", backtrace() }) ); return asn1_utc(sprintf("%02d%02d%02d%02d%02d%02dZ", m->year % 100, m->mon + 1, m->mday, m->hour, m->min, m->sec)); }
6913ab1999-03-22Niels Möller /* Returns a mapping similar to that returned by gmtime */ mapping parse_time(object asn1) {
5b546b1999-03-23Niels Möller  if ((asn1->type_name != "UTCTime")
6913ab1999-03-22Niels Möller  || (strlen(asn1->value) != 13)) return 0; sscanf(asn1->value, "%[0-9]s%c", string s, int c); if ( (strlen(s) != 12) && (c != 'Z') ) 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--; if ( (m->mday <= 0) || (m->mday >= Calendar.ISO.Year(m->year + 1900) ->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; /* NOTE: Allows for lead seconds */ if ( (m->sec < 0) || (m->min > 60)) return 0; return m; } int time_compare(mapping t1, mapping t2) { foreach( ({ "year", "mon", "mday", "hour", "min", "sec" }), string name) { if (t1->name < t2->name) return -1; if (t1->name > t2->name) return 1; } return 0; } object extension_sequence = meta_explicit(2, 3); object version_integer = meta_explicit(2, 0);
38333a1999-03-02Niels Möller 
5b546b1999-03-23Niels Möller object rsa_md5_algorithm = asn1_sequence( ({ Identifiers.rsa_md5_id, asn1_null() }) ); object rsa_sha1_algorithm = asn1_sequence( ({ Identifiers.rsa_sha1_id, asn1_null() }) );
38333a1999-03-02Niels Möller object make_tbs(object issuer, object algorithm, object subject, object keyinfo, object serial, int ttl, array extensions) { int now = time(); object validity = asn1_sequence( ({ make_time(now), make_time(now + ttl) }) ); return (extensions
6913ab1999-03-22Niels Möller  ? asn1_sequence( ({ version_integer(asn1_integer(2)), /* Version 3 */
38333a1999-03-02Niels Möller  serial, algorithm, issuer, validity, subject, keyinfo, extension_sequence(extensions) }) ) : asn1_sequence( ({ serial, algorithm, issuer, validity, subject, keyinfo }) )); }
5ae6b81999-03-09Niels Möller string make_selfsigned_dsa_certificate(object dsa, int ttl, array name,
38333a1999-03-02Niels Möller  array|void extensions) { object serial = asn1_integer(1); /* Hard coded serial number */ int now = time(); object validity = asn1_sequence( ({ make_time(now), make_time(now + ttl) }) );
627de51999-03-15Niels Möller  object signature_algorithm = asn1_sequence( ({ Identifiers.dsa_sha_id }) );
38333a1999-03-02Niels Möller  object keyinfo = asn1_sequence( ({ /* Use an identifier with parameters */
5ae6b81999-03-09Niels Möller  DSA.algorithm_identifier(dsa), asn1_bit_string(DSA.public_key(dsa)) }) );
38333a1999-03-02Niels Möller 
5ae6b81999-03-09Niels Möller  object dn = Certificate.build_distinguished_name(@name); object tbs = make_tbs(dn, signature_algorithm, dn, keyinfo,
38333a1999-03-02Niels Möller  serial, ttl, extensions); return asn1_sequence( ({ tbs,
627de51999-03-15Niels Möller  signature_algorithm,
38333a1999-03-02Niels Möller  asn1_bit_string(dsa ->sign_ssl(tbs->get_der())) }))->get_der(); } string rsa_sign_digest(object rsa, object digest_id, string digest) { object digest_info = asn1_sequence( ({ asn1_sequence( ({ digest_id, asn1_null() }) ), asn1_octet_string(digest) }) ); return rsa->raw_sign(digest_info->get_der())->digits(256); }
6913ab1999-03-22Niels Möller  int rsa_verify_digest(object rsa, object digest_id, string digest, string s) { object digest_info = asn1_sequence( ({ asn1_sequence( ({ digest_id, asn1_null() }) ), asn1_octet_string(digest) }) ); return rsa->raw_verify(digest_info->get_der(), Gmp.mpz(s, 256)); }
38333a1999-03-02Niels Möller string make_selfsigned_rsa_certificate(object rsa, int ttl, array name, array|void extensions) { object serial = asn1_integer(1); /* Hard coded serial number */ int now = time(); object validity = asn1_sequence( ({ make_time(now), make_time(now + ttl) }) ); object signature_algorithm = asn1_sequence( ({ Identifiers.rsa_sha1_id, asn1_null() }) ); object keyinfo = asn1_sequence( ({ asn1_sequence( ({ Identifiers.rsa_id, asn1_null() }) ),
5ae6b81999-03-09Niels Möller  asn1_bit_string(RSA.public_key(rsa)) }) );
38333a1999-03-02Niels Möller  object dn = Certificate.build_distinguished_name(@name);
5b546b1999-03-23Niels Möller  object tbs = make_tbs(dn, rsa_sha1_algorithm,
38333a1999-03-02Niels Möller  dn, keyinfo, serial, ttl, extensions); return asn1_sequence( ({ tbs,
5b546b1999-03-23Niels Möller  rsa_sha1_algorithm,
38333a1999-03-02Niels Möller  asn1_bit_string(rsa_sign_digest(rsa, Identifiers.sha1_id, Crypto.sha()->update(tbs->get_der()) ->digest())) }) )->get_der(); }
6913ab1999-03-22Niels Möller class rsa_verifier { object rsa; constant type = "rsa"; object init(string key) { rsa = RSA.parse_public_key(key); return rsa && this_object(); } int verify(object algorithm, string msg, string signature) { {
5b546b1999-03-23Niels Möller  if (algorithm->get_der() == rsa_md5_algorithm->get_der())
6913ab1999-03-22Niels Möller  return rsa_verify_digest(rsa, Identifiers.md5_id, Crypto.md5()->update(msg)->digest(), signature);
5b546b1999-03-23Niels Möller  else if (algorithm->get_der() == rsa_sha1_algorithm->get_der())
6913ab1999-03-22Niels Möller  return rsa_verify_digest(rsa, Identifiers.sha1_id, Crypto.sha()->update(msg)->digest(), signature); else return 0; } } } #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 object make_verifier(object keyinfo) { 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() != asn1_null()->get_der())) return 0;
5b546b1999-03-23Niels Möller  return rsa_verifier()->init(keyinfo->elements[1]->value);
6913ab1999-03-22Niels Möller  } else if (keyinfo->elements[0]->elements[0]->get_der() == Identifiers.dsa_sha_id->get_der()) { /* FIXME: Not implemented */ return 0; } } 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; object init(object asn1) { der = asn1->get_der(); if (asn1->type_name != "SEQUENCE") return 0; array a = asn1->elements;
a15f121999-06-08Martin Stjernholm  //werror("TBSCertificate: sizeof(a) = %d\n", sizeof(a));
5b546b1999-03-23Niels Möller 
6913ab1999-03-22Niels Möller  if (sizeof(a) < 6) return 0; if (sizeof(a) > 6) { /* The optional version field must be present */ if (!a[0]->constructed
cb74682000-05-25Andreas Sigfridsson  || (a[0]->get_combined_tag() != make_combined_tag(2, 0))
6913ab1999-03-22Niels Möller  || (sizeof(a[0]->elements) != 1)
5b546b1999-03-23Niels Möller  || (a[0]->elements[0]->type_name != "INTEGER"))
6913ab1999-03-22Niels Möller  return 0; version = (int) a[0]->elements[0]->value + 1; if ( (version < 2) || (version > 3)) return 0; a = a[1..]; } else version = 1;
a15f121999-06-08Martin Stjernholm  //werror("TBSCertificate: version = %d\n", version);
5b546b1999-03-23Niels Möller  if (a[0]->type_name != "INTEGER")
6913ab1999-03-22Niels Möller  return 0; serial = a[0]->value;
5b546b1999-03-23Niels Möller 
a15f121999-06-08Martin Stjernholm  //werror("TBSCertificate: serial = %s\n", (string) serial);
6913ab1999-03-22Niels Möller 
5b546b1999-03-23Niels Möller  if ((a[1]->type_name != "SEQUENCE")
6913ab1999-03-22Niels Möller  || !sizeof(a[1]->elements )
5b546b1999-03-23Niels Möller  || (a[1]->elements[0]->type_name != "OBJECT IDENTIFIER"))
6913ab1999-03-22Niels Möller  return 0; algorithm = a[1];
a15f121999-06-08Martin Stjernholm  //werror("TBSCertificate: algorithm = %s\n", algorithm->debug_string());
5b546b1999-03-23Niels Möller  if (a[2]->type_name != "SEQUENCE")
6913ab1999-03-22Niels Möller  return 0; issuer = a[2];
a15f121999-06-08Martin Stjernholm  //werror("TBSCertificate: issuer = %s\n", issuer->debug_string());
5b546b1999-03-23Niels Möller  if ((a[3]->type_name != "SEQUENCE")
6913ab1999-03-22Niels Möller  || (sizeof(a[3]->elements) != 2)) return 0; array validity = a[3]->elements; not_before = parse_time(validity[0]); if (!not_before) return 0;
a15f121999-06-08Martin Stjernholm  //werror("TBSCertificate: not_before = %O\n", not_before);
5b546b1999-03-23Niels Möller 
6913ab1999-03-22Niels Möller  not_after = parse_time(validity[0]); if (!not_after) return 0;
5b546b1999-03-23Niels Möller 
a15f121999-06-08Martin Stjernholm  //werror("TBSCertificate: not_after = %O\n", not_after);
5b546b1999-03-23Niels Möller  if (a[4]->type_name != "SEQUENCE") return 0;
6913ab1999-03-22Niels Möller  subject = a[4];
5b546b1999-03-23Niels Möller 
a15f121999-06-08Martin Stjernholm  //werror("TBSCertificate: keyinfo = %s\n", a[5]->debug_string());
5b546b1999-03-23Niels Möller 
6913ab1999-03-22Niels Möller  public_key = make_verifier(a[5]); if (!public_key) return 0;
5b546b1999-03-23Niels Möller 
a15f121999-06-08Martin Stjernholm  //werror("TBSCertificate: parsed public key. type = %s\n", // public_key->type);
5b546b1999-03-23Niels Möller 
6913ab1999-03-22Niels Möller  int i = 6; if (i == sizeof(a)) return this_object(); if (version < 2) return 0; if (! a[i]->constructed && (a[i]->combined_tag == make_combined_tag(2, 1))) { issuer_id = asn1_bit_string()->decode_primitive(a[i]->raw); i++; if (i == sizeof(a)) return this_object(); } if (! a[i]->constructed && (a[i]->combined_tag == make_combined_tag(2, 2))) { subject_id = asn1_bit_string()->decode_primitive(a[i]->raw); i++; if (i == sizeof(a)) return this_object(); } if (a[i]->constructed && (a[i]->combined_tag == make_combined_tag(2, 3))) { extensions = a[i]; i++; if (i == sizeof(a)) return this_object(); } /* Too many fields */ return 0; } }
a15f121999-06-08Martin Stjernholm object 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; object(TBSCertificate) tbs = TBSCertificate()->init(cert->elements[0]);
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; } /* 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. */ object verify_certificate(string s, mapping authorities) { object cert = Standards.ASN1.Decode.simple_der_decode(s); object(TBSCertificate) tbs = decode_certificate(cert); if (!tbs) return 0;
6913ab1999-03-22Niels Möller  object v; if (tbs->issuer->get_der() == tbs->subject->get_der()) { /* A self signed certificate */
a15f121999-06-08Martin Stjernholm  //werror("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) 
ea382e2000-03-10Martin Nilsson #endif