pike.git / lib / modules / Standards.pmod / X509.pmod

version» Context lines:

pike.git/lib/modules/Standards.pmod/X509.pmod:1:   #pike __REAL_VERSION__   //#pragma strict_types    - /* -  * Some random functions for creating RFC-2459 style X.509 certificates. -  * -  */ + //! Functions to generate and validate RFC2459 style X.509 v3 + //! certificates.      constant dont_dump_module = 1;    - #if constant(Standards.ASN1.Types.Sequence) && constant(Crypto.Hash) + #if constant(Crypto.Hash)      import Standards.ASN1.Types;   import Standards.PKCS;    - // Note: Redump this module if you change X509_DEBUG +    #ifdef X509_DEBUG - #define X509_WERR werror + #define DBG(X ...) werror(X)   #else - #define X509_WERR + #define DBG(X ...)   #endif      //!   constant CERT_TOO_OLD = 1;      //!   constant CERT_TOO_NEW = 2;      //!   constant CERT_INVALID = 3;
pike.git/lib/modules/Standards.pmod/X509.pmod:52:       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()));   }    - //! Returns a mapping similar to that returned by gmtime + //! Returns a mapping similar to that returned by gmtime. Returns + //! @expr{0@} on invalid dates. + //!   //! @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)   {    if ((asn1->type_name != "UTCTime")    || (sizeof(asn1->value) != 13))    return 0;       sscanf(asn1->value, "%[0-9]s%c", string s, int c);    if ( (sizeof(s) != 12) && (c != 'Z') )    return 0;    -  /* NOTE: This relies on pike-0.7 not interpreting leading zeros as -  * an octal prefix. */ +     mapping(string:int) m = mkmapping( ({ "year", "mon", "mday",    "hour", "min", "sec" }),    (array(int)) (s/2));       if (m->year < 50)    m->year += 100;    if ( (m->mon <= 0 ) || (m->mon > 12) )    return 0;    m->mon--;   
pike.git/lib/modules/Standards.pmod/X509.pmod:128:      Sequence rsa_md2_algorithm = Sequence( ({ Identifiers.rsa_md2_id, Null() }) );      Sequence rsa_md5_algorithm = Sequence( ({ Identifiers.rsa_md5_id, Null() }) );      Sequence rsa_sha1_algorithm = Sequence( ({ Identifiers.rsa_sha1_id,    Null() }) );      Sequence dsa_sha1_algorithm = Sequence( ({ Identifiers.dsa_sha_id }) );    - //! - Sequence make_tbs(object issuer, object algorithm, -  object subject, object keyinfo, -  object serial, int ttl, + //! Creates the ASN.1 TBSCertificate sequence (see RFC2459 section + //! 4.1) to be signed (TBS) by the CA. version is explicitly set to + //! v3, validity is calculated based on time and @[ttl], and + //! @[extensions] is optionally added to the sequence. issuerUniqueID + //! and subjectUniqueID are not supported. + Sequence make_tbs(Sequence issuer, Sequence algorithm, +  Sequence subject, Sequence keyinfo, +  Integer serial, int ttl,    array extensions)   {    int now = time();    Sequence validity = Sequence( ({ make_time(now), make_time(now + ttl) }) );       return (extensions    ? Sequence( ({ version_integer(Integer(2)), /* Version 3 */    serial,    algorithm,    issuer,
pike.git/lib/modules/Standards.pmod/X509.pmod:373:    }       if(([object(Sequence)]keyinfo->elements[0])->elements[0]->get_der()    == Identifiers.dsa_sha_id->get_der())    {    /* FIXME: Not implemented */    return 0;    }   }    - //! + //! Represents a TBSCertificate.   class TBSCertificate   {    //!    string der;       //!    int version;       //!    Gmp.mpz serial;
pike.git/lib/modules/Standards.pmod/X509.pmod:417:    BitString issuer_id;       //! @note    //! optional    BitString subject_id;       //! @note    //! optional    object extensions;    -  //! +  //! Populates the object from a certificate decoded into an ASN.1 +  //! 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)    {    der = asn1->get_der();    if (asn1->type_name != "SEQUENCE")    return 0;       array(Object) a = ([object(Sequence)]asn1)->elements; -  X509_WERR("TBSCertificate: sizeof(a) = %d\n", sizeof(a)); +  DBG("TBSCertificate: sizeof(a) = %d\n", sizeof(a));       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"))    return 0;       version = (int) a[0]->elements[0]->value + 1;    if ( (version < 2) || (version > 3))    return 0;    a = a[1..];    } else    version = 1;    -  X509_WERR("TBSCertificate: version = %d\n", version); +  DBG("TBSCertificate: version = %d\n", version);    if (a[0]->type_name != "INTEGER")    return 0;    serial = a[0]->value;    -  X509_WERR("TBSCertificate: serial = %s\n", (string) serial); +  DBG("TBSCertificate: serial = %s\n", (string) serial);       if ((a[1]->type_name != "SEQUENCE")    || !sizeof(a[1]->elements )    || (a[1]->elements[0]->type_name != "OBJECT IDENTIFIER"))    return 0;       algorithm = a[1];    -  X509_WERR("TBSCertificate: algorithm = %s\n", algorithm->debug_string()); +  DBG("TBSCertificate: algorithm = %s\n", algorithm->debug_string());       if (a[2]->type_name != "SEQUENCE")    return 0;    issuer = a[2];    -  X509_WERR("TBSCertificate: issuer = %s\n", issuer->debug_string()); +  DBG("TBSCertificate: issuer = %s\n", issuer->debug_string());       if ((a[3]->type_name != "SEQUENCE")    || (sizeof(a[3]->elements) != 2))    return 0;       array validity = a[3]->elements;       not_before = parse_time(validity[0]);    if (!not_before)    return 0;    -  X509_WERR("TBSCertificate: not_before = %O\n", not_before); +  DBG("TBSCertificate: not_before = %O\n", not_before);       not_after = parse_time(validity[1]);    if (!not_after)    return 0;    -  X509_WERR("TBSCertificate: not_after = %O\n", not_after); +  DBG("TBSCertificate: not_after = %O\n", not_after);       if (a[4]->type_name != "SEQUENCE")    return 0;    subject = a[4];    -  X509_WERR("TBSCertificate: keyinfo = %s\n", a[5]->debug_string()); +  DBG("TBSCertificate: keyinfo = %s\n", a[5]->debug_string());       public_key = make_verifier(a[5]);       if (!public_key)    return 0;    -  X509_WERR("TBSCertificate: parsed public key. type = %s\n", +  DBG("TBSCertificate: parsed public key. type = %s\n",    public_key->type);       int i = 6;    if (i == sizeof(a))    return this;       if (version < 2)    return 0;       if (! a[i]->constructed
pike.git/lib/modules/Standards.pmod/X509.pmod:536:    extensions = a[i];    i++;    if (i == sizeof(a))    return this;    }    /* Too many fields */    return 0;    }   }    - //! + //! Decodes a certificate and verifies that it is structually sound. + //! Returns a @[TBSCertificate] object if ok, otherwise @expr{0@}.   TBSCertificate decode_certificate(string|object cert)   {    if (stringp (cert)) cert = Standards.ASN1.Decode.simple_der_decode(cert);       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))
pike.git/lib/modules/Standards.pmod/X509.pmod:580:    object cert = Standards.ASN1.Decode.simple_der_decode(s);       TBSCertificate tbs = decode_certificate(cert);    if (!tbs) return 0;       object v;       if (tbs->issuer->get_der() == tbs->subject->get_der())    {    /* A self signed certificate */ -  X509_WERR("Self signed certificate\n"); +  DBG("Self signed certificate\n");    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;   }
pike.git/lib/modules/Standards.pmod/X509.pmod:692: Inside #if 0
   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"); +  DBG("a CA certificate does not have the CA basic constraint.\n");    m->error_code = CERT_UNAUTHORIZED_CA;    m->error_cert = idx;    return m;    }    }   #endif /* 0 */       if(idx == 0) // The root cert    {    v = authorities[tbs->issuer->get_der()];       // if we don't know the issuer of the root certificate, and we    // require trust, we're done.    if(!v && require_trust)    { -  X509_WERR("we require trust, but haven't got it.\n"); +  DBG("we require trust, but haven't got it.\n");    m->error_code = CERT_ROOT_UNTRUSTED;    m->error_cert = idx;    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"); +  DBG("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.    {    // is the certificate in effect (time-wise)?
pike.git/lib/modules/Standards.pmod/X509.pmod:754:    m->verified = 0;    m->error_code = CERT_TOO_OLD;    m->error_cert = idx;    return m;    }       // is the issuer of this certificate the subject of the previous    // (more rootward) certificate?    if(tbs->issuer->get_der() != chain_obj[idx-1]->subject->get_der())    { -  X509_WERR("issuer chain is broken!\n"); +  DBG("issuer chain is broken!\n");    m->verified = 0;    m->error_code = CERT_CHAIN_BROKEN;    m->error_cert = idx;    return m;    }    // the verifier for this certificate should be the public key of    // the previous certificate in the chain.    v = chain_obj[idx-1]->public_key;    }       if (v)    {    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"); +  DBG("signature is verified..\n");    m->verified = 1;       // if we're the root of the chain and we've verified, this is    // the authority.    if(idx == 0)    m->authority = tbs->issuer;       if(idx == sizeof(chain_cert)-1) m->cn = tbs->subject;    }    else    { -  X509_WERR("signature _not_ verified...\n"); +  DBG("signature _not_ verified...\n");    m->error_code = CERT_BAD_SIGNATURE;    m->error_cert = idx;    m->verified = 0;    return m;    }    }    }    return m;   }      #endif