Added support for CRL generation to x509 plugin
authorMartin Willi <martin@revosec.ch>
Fri, 21 May 2010 13:52:20 +0000 (15:52 +0200)
committerMartin Willi <martin@revosec.ch>
Fri, 21 May 2010 14:25:51 +0000 (16:25 +0200)
src/libstrongswan/credentials/builder.c
src/libstrongswan/credentials/builder.h
src/libstrongswan/plugins/x509/x509_crl.c
src/libstrongswan/plugins/x509/x509_crl.h
src/libstrongswan/plugins/x509/x509_plugin.c

index 8be1c15..cfb708e 100644 (file)
@@ -44,6 +44,7 @@ ENUM(builder_part_names, BUILD_FROM_FILE, BUILD_END,
        "BUILD_OCSP_ACCESS_LOCATIONS",
        "BUILD_PATHLEN",
        "BUILD_X509_FLAG",
+       "BUILD_REVOKED_ENUMERATOR",
        "BUILD_SMARTCARD_KEYID",
        "BUILD_SMARTCARD_PIN",
        "BUILD_RSA_MODULUS",
index 62a6ffa..ffb09f7 100644 (file)
@@ -101,6 +101,8 @@ enum builder_part_t {
        BUILD_PATHLEN,
        /** enforce an additional X509 flag, x509_flag_t */
        BUILD_X509_FLAG,
+       /** enumerator_t over (chunk_t serial, time_t date, crl_reason_t reason) */
+       BUILD_REVOKED_ENUMERATOR,
        /** key ID of a key on a smartcard, null terminated char* ([slot:]keyid) */
        BUILD_SMARTCARD_KEYID,
        /** pin to access a key on a smartcard, null terminated char* */
index e171e4c..f3d5c6d 100644 (file)
@@ -26,6 +26,7 @@ typedef struct revoked_t revoked_t;
 #include <asn1/asn1.h>
 #include <asn1/asn1_parser.h>
 #include <credentials/certificates/x509.h>
+#include <credentials/keys/private_key.h>
 #include <utils/linked_list.h>
 
 /**
@@ -119,6 +120,11 @@ struct private_x509_crl_t {
        chunk_t signature;
 
        /**
+        * has this CRL been generated
+        */
+       bool generated;
+
+       /**
         * reference counter
         */
        refcount_t ref;
@@ -236,7 +242,7 @@ static bool parse(private_x509_crl_t *this)
                                break;
                        case CRL_OBJ_REVOCATION_DATE:
                                revoked = malloc_thing(revoked_t);
-                               revoked->serial = userCertificate;
+                               revoked->serial = chunk_clone(userCertificate);
                                revoked->date = asn1_parse_time(object, level);
                                revoked->reason = CRL_REASON_UNSPECIFIED;
                                this->revoked->insert_last(this->revoked, (void *)revoked);
@@ -267,7 +273,6 @@ static bool parse(private_x509_crl_t *this)
                                        }
                                        else if (extn_oid == OID_AUTHORITY_KEY_ID)
                                        {
-
                                                this->authKeyIdentifier = x509_parse_authorityKeyIdentifier(object,
                                                                                                                level, &this->authKeySerialNumber);
                                        }
@@ -478,15 +483,30 @@ METHOD(certificate_t, equals, bool,
        return equal;
 }
 
+/**
+ * Destroy a revoked_t entry
+ */
+static void revoked_destroy(revoked_t *revoked)
+{
+       free(revoked->serial.ptr);
+       free(revoked);
+}
+
 METHOD(certificate_t, destroy, void,
        private_x509_crl_t *this)
 {
        if (ref_put(&this->ref))
        {
-               this->revoked->destroy_function(this->revoked, free);
+               this->revoked->destroy_function(this->revoked, (void*)revoked_destroy);
                DESTROY_IF(this->issuer);
                free(this->authKeyIdentifier.ptr);
                free(this->encoding.ptr);
+               if (this->generated)
+               {
+                       free(this->crlNumber.ptr);
+                       free(this->signature.ptr);
+                       free(this->tbsCertList.ptr);
+               }
                free(this);
        }
 }
@@ -561,3 +581,166 @@ x509_crl_t *x509_crl_load(certificate_type_t type, va_list args)
        return NULL;
 };
 
+/**
+ * Read certificate status from enumerator, copy to crl
+ */
+static void read_revoked(private_x509_crl_t *crl, enumerator_t *enumerator)
+{
+       revoked_t *revoked;
+       chunk_t serial;
+       time_t date;
+       crl_reason_t reason;
+
+       while (enumerator->enumerate(enumerator, &serial, &date, &reason))
+       {
+               INIT(revoked,
+                       .serial = chunk_clone(serial),
+                       .date = date,
+                       .reason = reason,
+               );
+               crl->revoked->insert_last(crl->revoked, revoked);
+       }
+}
+
+/**
+ * Generate CRL encoding, sign CRL
+ */
+static bool generate(private_x509_crl_t *this, certificate_t *cert,
+                                        private_key_t *key, hash_algorithm_t digest_alg)
+{
+       chunk_t extensions = chunk_empty, certList = chunk_empty, serial;
+       enumerator_t *enumerator;
+       crl_reason_t reason;
+       time_t date;
+       x509_t *x509;
+
+       x509 = (x509_t*)cert;
+
+       this->issuer = cert->get_issuer(cert);
+       this->issuer = this->issuer->clone(this->issuer);
+
+       this->authKeyIdentifier = chunk_clone(x509->get_authKeyIdentifier(x509));
+
+       /* select signature scheme */
+       this->algorithm = hasher_signature_algorithm_to_oid(digest_alg,
+                                                                                                               key->get_type(key));
+       if (this->algorithm == OID_UNKNOWN)
+       {
+               return FALSE;
+       }
+
+       enumerator = create_enumerator(this);
+       while (enumerator->enumerate(enumerator, &serial, &date, &reason))
+       {
+               chunk_t revoked, entry_ext = chunk_empty;
+
+               if (reason != CRL_REASON_UNSPECIFIED)
+               {
+                       entry_ext = asn1_wrap(ASN1_SEQUENCE, "m",
+                                                       asn1_wrap(ASN1_SEQUENCE, "mm",
+                                                               asn1_build_known_oid(OID_CRL_REASON_CODE),
+                                                               asn1_wrap(ASN1_OCTET_STRING, "m",
+                                                                       asn1_wrap(ASN1_ENUMERATED, "c",
+                                                                               chunk_from_chars(reason)))));
+               }
+               revoked = asn1_wrap(ASN1_SEQUENCE, "mmm",
+                                                       asn1_integer("c", serial),
+                                                       asn1_from_time(&date, ASN1_UTCTIME),
+                                                       entry_ext);
+               certList = chunk_cat("mm", certList, revoked);
+       }
+       enumerator->destroy(enumerator);
+
+       extensions = asn1_wrap(ASN1_CONTEXT_C_0, "m",
+                                       asn1_wrap(ASN1_SEQUENCE, "mm",
+                                               asn1_wrap(ASN1_SEQUENCE, "mm",
+                                                       asn1_build_known_oid(OID_AUTHORITY_KEY_ID),
+                                                       asn1_wrap(ASN1_OCTET_STRING, "m",
+                                                               asn1_wrap(ASN1_SEQUENCE, "m",
+                                                                       asn1_wrap(ASN1_CONTEXT_S_0, "c",
+                                                                                         this->authKeyIdentifier)))),
+                                               asn1_wrap(ASN1_SEQUENCE, "mm",
+                                                       asn1_build_known_oid(OID_CRL_NUMBER),
+                                                       asn1_wrap(ASN1_OCTET_STRING, "m",
+                                                               asn1_integer("c", this->crlNumber))
+                                                       )
+                                               ));
+
+       this->tbsCertList = asn1_wrap(ASN1_SEQUENCE, "cmcmmmm",
+                                                       ASN1_INTEGER_1,
+                                                       asn1_algorithmIdentifier(this->algorithm),
+                                                       this->issuer->get_encoding(this->issuer),
+                                                       asn1_from_time(&this->thisUpdate, ASN1_UTCTIME),
+                                                       asn1_from_time(&this->nextUpdate, ASN1_UTCTIME),
+                                                       asn1_wrap(ASN1_SEQUENCE, "m", certList),
+                                                       extensions);
+
+       if (!key->sign(key, signature_scheme_from_oid(this->algorithm),
+                                  this->tbsCertList, &this->signature))
+       {
+               return FALSE;
+       }
+       this->encoding = asn1_wrap(ASN1_SEQUENCE, "cmm",
+                                                       this->tbsCertList,
+                                                       asn1_algorithmIdentifier(this->algorithm),
+                                                       asn1_bitstring("c", this->signature));
+       return TRUE;
+}
+
+/**
+ * See header.
+ */
+x509_crl_t *x509_crl_gen(certificate_type_t type, va_list args)
+{
+       hash_algorithm_t digest_alg = HASH_SHA1;
+       private_x509_crl_t *crl;
+       certificate_t *cert = NULL;
+       private_key_t *key = NULL;
+
+       crl = create_empty();
+       crl->generated = TRUE;
+       while (TRUE)
+       {
+               builder_part_t part = va_arg(args, builder_part_t);
+
+               switch (part)
+               {
+                       case BUILD_SIGNING_KEY:
+                               key = va_arg(args, private_key_t*);
+                               continue;
+                       case BUILD_SIGNING_CERT:
+                               cert = va_arg(args, certificate_t*);
+                               continue;
+                       case BUILD_NOT_BEFORE_TIME:
+                               crl->thisUpdate = va_arg(args, time_t);
+                               continue;
+                       case BUILD_NOT_AFTER_TIME:
+                               crl->nextUpdate = va_arg(args, time_t);
+                               continue;
+                       case BUILD_SERIAL:
+                               crl->crlNumber = va_arg(args, chunk_t);
+                               crl->crlNumber = chunk_clone(crl->crlNumber);
+                               continue;
+                       case BUILD_DIGEST_ALG:
+                               digest_alg = va_arg(args, int);
+                               continue;
+                       case BUILD_REVOKED_ENUMERATOR:
+                               read_revoked(crl, va_arg(args, enumerator_t*));
+                               continue;
+                       case BUILD_END:
+                               break;
+                       default:
+                               destroy(crl);
+                               return NULL;
+               }
+               break;
+       }
+
+       if (key && cert && cert->get_type(cert) == CERT_X509 &&
+               generate(crl, cert, key, digest_alg))
+       {
+               return &crl->public;
+       }
+       destroy(crl);
+       return NULL;
+}
index 8906501..e8fe74e 100644 (file)
@@ -46,4 +46,13 @@ struct x509_crl_t {
  */
 x509_crl_t *x509_crl_load(certificate_type_t type, va_list args);
 
+/**
+ * Generate a X.509 CRL.
+ *
+ * @param type         certificate type, CERT_X509_CRL only
+ * @param args         builder_part_t argument list
+ * @return                     X.509 CRL, NULL on failure
+ */
+x509_crl_t *x509_crl_gen(certificate_type_t type, va_list args);
+
 #endif /** X509_CRL_H_ @}*/
index e71c55e..8391781 100644 (file)
@@ -52,6 +52,8 @@ static void destroy(private_x509_plugin_t *this)
        lib->creds->remove_builder(lib->creds,
                                                           (builder_function_t)x509_crl_load);
        lib->creds->remove_builder(lib->creds,
+                                                          (builder_function_t)x509_crl_gen);
+       lib->creds->remove_builder(lib->creds,
                                                           (builder_function_t)x509_ocsp_request_gen);
        lib->creds->remove_builder(lib->creds,
                                                           (builder_function_t)x509_ocsp_response_load);
@@ -81,6 +83,8 @@ plugin_t *x509_plugin_create()
                                                        (builder_function_t)x509_ac_load);
        lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509_CRL,
                                                        (builder_function_t)x509_crl_load);
+       lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509_CRL,
+                                                       (builder_function_t)x509_crl_gen);
        lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509_OCSP_REQUEST,
                                                        (builder_function_t)x509_ocsp_request_gen);
        lib->creds->add_builder(lib->creds, CRED_CERTIFICATE, CERT_X509_OCSP_RESPONSE,