removed TODO reminder
[strongswan.git] / src / libstrongswan / plugins / x509 / x509_cert.c
index 860006f..b8df5ad 100644 (file)
@@ -33,8 +33,8 @@
 #include <asn1/oid.h>
 #include <asn1/asn1.h>
 #include <asn1/asn1_parser.h>
-#include <asn1/pem.h>
 #include <crypto/hashers/hasher.h>
+#include <credentials/keys/private_key.h>
 #include <utils/linked_list.h>
 #include <utils/identification.h>
 
@@ -138,7 +138,7 @@ struct private_x509_cert_t {
        /**
         * Authority Key Identifier
         */
-       identification_t *authKeyIdentifier;
+       chunk_t authKeyIdentifier;
        
        /**
         * Authority Key Serial Number
@@ -421,13 +421,13 @@ static const asn1Object_t authKeyIdentifierObjects[] = {
 /**
  * Extracts an authoritykeyIdentifier
  */
-identification_t* x509_parse_authorityKeyIdentifier(chunk_t blob, int level0,
+chunk_t x509_parse_authorityKeyIdentifier(chunk_t blob, int level0,
                                                                                                chunk_t *authKeySerialNumber)
 {
        asn1_parser_t *parser;
        chunk_t object;
        int objectID;
-       identification_t *authKeyIdentifier = NULL;
+       chunk_t authKeyIdentifier = chunk_empty;
        
        *authKeySerialNumber = chunk_empty;
        
@@ -439,8 +439,7 @@ identification_t* x509_parse_authorityKeyIdentifier(chunk_t blob, int level0,
                switch (objectID) 
                {
                        case AUTH_KEY_ID_KEY_ID:
-                               authKeyIdentifier = identification_create_from_encoding(
-                                                                                               ID_PUBKEY_SHA1, object); 
+                               authKeyIdentifier = chunk_clone(object);
                                break;
                        case AUTH_KEY_ID_CERT_ISSUER:
                                /* TODO: x509_parse_generalNames(object, level+1, TRUE); */
@@ -729,7 +728,6 @@ static bool parse_certificate(private_x509_cert_t *this)
                                                KEY_ANY, BUILD_BLOB_ASN1_DER, object, BUILD_END);
                                if (this->public_key == NULL)
                                {
-                                       DBG1("could not create public key");
                                        goto end;
                                }
                                break;
@@ -848,10 +846,12 @@ static id_match_t has_subject(private_x509_cert_t *this, identification_t *subje
        enumerator_t *enumerator;
        id_match_t match, best;
        
-       if (this->encoding_hash.ptr && subject->get_type(subject) == ID_CERT_DER_SHA1 &&
-               chunk_equals(this->encoding_hash, subject->get_encoding(subject)))
+       if (this->encoding_hash.ptr && subject->get_type(subject) == ID_KEY_ID)
        {
-               return ID_MATCH_PERFECT;
+               if (chunk_equals(this->encoding_hash, subject->get_encoding(subject)))
+               {
+                       return ID_MATCH_PERFECT;
+               }
        }
        
        best = this->subject->matches(this->subject, subject);
@@ -861,11 +861,11 @@ static id_match_t has_subject(private_x509_cert_t *this, identification_t *subje
                match = current->matches(current, subject);
                if (match > best)
                {
-                       best = match;   
+                       best = match;
                }
        }
        enumerator->destroy(enumerator);
-       return best;    
+       return best;
 }
 
 /**
@@ -909,32 +909,14 @@ static bool issued_by(private_x509_cert_t *this, certificate_t *issuer)
        {
                return FALSE;
        }
-       /* TODO: generic OID to scheme mapper? */
-       switch (this->algorithm)
-       {
-               case OID_MD5_WITH_RSA:
-                       scheme = SIGN_RSA_EMSA_PKCS1_MD5;
-                       break;
-               case OID_SHA1_WITH_RSA:
-                       scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
-                       break;
-               case OID_SHA256_WITH_RSA:
-                       scheme = SIGN_RSA_EMSA_PKCS1_SHA256;
-                       break;
-               case OID_SHA384_WITH_RSA:
-                       scheme = SIGN_RSA_EMSA_PKCS1_SHA384;
-                       break;
-               case OID_SHA512_WITH_RSA:
-                       scheme = SIGN_RSA_EMSA_PKCS1_SHA512;
-                       break;
-               case OID_ECDSA_WITH_SHA1:
-                       scheme = SIGN_ECDSA_WITH_SHA1;
-                       break;
-               default:
-                       return FALSE;
-       }
+
+       /* get the public key of the issuer */
        key = issuer->get_public_key(issuer);
-       if (key == NULL)
+
+       /* determine signature scheme */
+       scheme = signature_scheme_from_oid(this->algorithm);
+
+       if (scheme == SIGN_UNKNOWN || key == NULL)
        {
                return FALSE;
        }
@@ -1059,7 +1041,7 @@ static chunk_t get_serial(private_x509_cert_t *this)
 /**
  * Implementation of x509_t.get_authKeyIdentifier.
  */
-static identification_t *get_authKeyIdentifier(private_x509_cert_t *this)
+static chunk_t get_authKeyIdentifier(private_x509_cert_t *this)
 {
        return this->authKeyIdentifier;
 }
@@ -1102,7 +1084,7 @@ static void destroy(private_x509_cert_t *this)
                DESTROY_IF(this->issuer);
                DESTROY_IF(this->subject);
                DESTROY_IF(this->public_key);
-               DESTROY_IF(this->authKeyIdentifier);
+               chunk_free(&this->authKeyIdentifier);
                chunk_free(&this->encoding);
                chunk_free(&this->encoding_hash);
                if (!this->parsed)
@@ -1122,22 +1104,22 @@ static private_x509_cert_t* create_empty(void)
 {
        private_x509_cert_t *this = malloc_thing(private_x509_cert_t);
        
-       this->public.interface.interface.get_type = (certificate_type_t (*)(certificate_t *this))get_type;
-       this->public.interface.interface.get_subject = (identification_t* (*)(certificate_t *this))get_subject;
-       this->public.interface.interface.get_issuer = (identification_t* (*)(certificate_t *this))get_issuer;
-       this->public.interface.interface.has_subject = (id_match_t (*)(certificate_t*, identification_t *subject))has_subject;
-       this->public.interface.interface.has_issuer = (id_match_t (*)(certificate_t*, identification_t *issuer))has_issuer;
-       this->public.interface.interface.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer))issued_by;
-       this->public.interface.interface.get_public_key = (public_key_t* (*)(certificate_t *this))get_public_key;
-       this->public.interface.interface.get_validity = (bool (*)(certificate_t*, time_t *when, time_t *, time_t*))get_validity;
-       this->public.interface.interface.is_newer = (bool (*)(certificate_t*,certificate_t*))is_newer;
-       this->public.interface.interface.get_encoding = (chunk_t (*)(certificate_t*))get_encoding;
-       this->public.interface.interface.equals = (bool (*)(certificate_t*, certificate_t *other))equals;
-       this->public.interface.interface.get_ref = (certificate_t* (*)(certificate_t *this))get_ref;
-       this->public.interface.interface.destroy = (void (*)(certificate_t *this))destroy;
+       this->public.interface.interface.get_type = (certificate_type_t (*) (certificate_t*))get_type;
+       this->public.interface.interface.get_subject = (identification_t* (*) (certificate_t*))get_subject;
+       this->public.interface.interface.get_issuer = (identification_t* (*) (certificate_t*))get_issuer;
+       this->public.interface.interface.has_subject = (id_match_t (*) (certificate_t*, identification_t*))has_subject;
+       this->public.interface.interface.has_issuer = (id_match_t (*) (certificate_t*, identification_t*))has_issuer;
+       this->public.interface.interface.issued_by = (bool (*) (certificate_t*, certificate_t*))issued_by;
+       this->public.interface.interface.get_public_key = (public_key_t* (*) (certificate_t*))get_public_key;
+       this->public.interface.interface.get_validity = (bool (*) (certificate_t*, time_t*, time_t*, time_t*))get_validity;
+       this->public.interface.interface.is_newer = (bool (*) (certificate_t*,certificate_t*))is_newer;
+       this->public.interface.interface.get_encoding = (chunk_t (*) (certificate_t*))get_encoding;
+       this->public.interface.interface.equals = (bool (*)(certificate_t*, certificate_t*))equals;
+       this->public.interface.interface.get_ref = (certificate_t* (*)(certificate_t*))get_ref;
+       this->public.interface.interface.destroy = (void (*)(certificate_t*))destroy;
        this->public.interface.get_flags = (x509_flag_t (*)(x509_t*))get_flags;
        this->public.interface.get_serial = (chunk_t (*)(x509_t*))get_serial;
-       this->public.interface.get_authKeyIdentifier = (identification_t* (*)(x509_t*))get_authKeyIdentifier;
+       this->public.interface.get_authKeyIdentifier = (chunk_t (*)(x509_t*))get_authKeyIdentifier;
        this->public.interface.create_subjectAltName_enumerator = (enumerator_t* (*)(x509_t*))create_subjectAltName_enumerator;
        this->public.interface.create_crl_uri_enumerator = (enumerator_t* (*)(x509_t*))create_crl_uri_enumerator;
        this->public.interface.create_ocsp_uri_enumerator = (enumerator_t* (*)(x509_t*))create_ocsp_uri_enumerator;
@@ -1156,7 +1138,7 @@ static private_x509_cert_t* create_empty(void)
        this->crl_uris = linked_list_create();
        this->ocsp_uris = linked_list_create();
        this->subjectKeyID = chunk_empty;
-       this->authKeyIdentifier = NULL;
+       this->authKeyIdentifier = chunk_empty;
        this->authKeySerialNumber = chunk_empty;
        this->algorithm = 0;
        this->signature = chunk_empty;
@@ -1176,6 +1158,7 @@ static private_x509_cert_t *create_from_chunk(chunk_t chunk)
        private_x509_cert_t *this = create_empty();
        
        this->encoding = chunk;
+       this->parsed = TRUE;
        if (!parse_certificate(this))
        {
                destroy(this);
@@ -1189,42 +1172,15 @@ static private_x509_cert_t *create_from_chunk(chunk_t chunk)
        }
        
        hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
-       if (hasher != NULL)
+       if (hasher == NULL)
        {
-               hasher->allocate_hash(hasher, this->encoding, &this->encoding_hash);
-               hasher->destroy(hasher);
-       }
-       else
-       {
-               DBG1("  unable to create hash of certificate, SHA1 not supported");             
+               DBG1("  unable to create hash of certificate, SHA1 not supported");     
+               destroy(this);
+               return NULL;    
        }
+       hasher->allocate_hash(hasher, this->encoding, &this->encoding_hash);
+       hasher->destroy(hasher);
        
-       this->parsed = TRUE;
-       return this;
-}
-
-/**
- * create an X.509 certificate from a file
- */
-static private_x509_cert_t *create_from_file(char *path)
-{
-       bool pgp = FALSE;
-       chunk_t chunk;
-       private_x509_cert_t *this;
-       
-       if (!pem_asn1_load_file(path, NULL, &chunk, &pgp))
-       {
-               return NULL;
-       }
-
-       this = create_from_chunk(chunk);
-
-       if (this == NULL)
-       {
-               DBG1("  could not parse loaded certificate file '%s'",path);
-               return NULL;
-       }
-       DBG1("  loaded certificate file '%s'",  path);
        return this;
 }
 
@@ -1243,6 +1199,8 @@ struct private_builder_t {
        certificate_t *sign_cert;
        /** private key to sign, if we generate a new cert */
        private_key_t *sign_key;
+       /** digest algorithm to be used for signature */
+       hash_algorithm_t digest_alg;
 };
 
 /**
@@ -1252,7 +1210,7 @@ static bool generate(private_builder_t *this)
 {
        chunk_t extensions = chunk_empty;
        identification_t *issuer, *subject;
-       chunk_t key_info, key;
+       chunk_t key_info;
        signature_scheme_t scheme;
        hasher_t *hasher;
        
@@ -1280,7 +1238,7 @@ static bool generate(private_builder_t *this)
                this->cert->notBefore = time(NULL);
        }
        if (!this->cert->notAfter)
-       {       /* defaults to 1 years from now on */
+       {       /* defaults to 1 year from now */
                this->cert->notAfter = this->cert->notBefore + 60 * 60 * 24 * 365;
        }
        this->cert->flags = this->flags;
@@ -1288,33 +1246,67 @@ static bool generate(private_builder_t *this)
        switch (this->sign_key->get_type(this->sign_key))
        {
                case KEY_RSA:
-                       this->cert->algorithm = OID_SHA1_WITH_RSA;
-                       scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
+                       switch (this->digest_alg)
+                       {
+                               case HASH_MD5:
+                                       this->cert->algorithm = OID_MD5_WITH_RSA;
+                                       break;
+                               case HASH_SHA1:
+                                       this->cert->algorithm = OID_SHA1_WITH_RSA;
+                                       break;
+                               case HASH_SHA224:
+                                       this->cert->algorithm = OID_SHA224_WITH_RSA;
+                                       break;
+                               case HASH_SHA256:
+                                       this->cert->algorithm = OID_SHA256_WITH_RSA;
+                                       break;
+                               case HASH_SHA384:
+                                       this->cert->algorithm = OID_SHA384_WITH_RSA;
+                                       break;
+                               case HASH_SHA512:
+                                       this->cert->algorithm = OID_SHA512_WITH_RSA;
+                                       break;
+                               default:
+                                       return FALSE;
+                       }
+                       break;
+               case KEY_ECDSA:
+                       switch (this->digest_alg)
+                       {
+                               case HASH_SHA1:
+                                       this->cert->algorithm = OID_ECDSA_WITH_SHA1;
+                                       break;
+                               case HASH_SHA256:
+                                       this->cert->algorithm = OID_ECDSA_WITH_SHA256;
+                                       break;
+                               case HASH_SHA384:
+                                       this->cert->algorithm = OID_ECDSA_WITH_SHA384;
+                                       break;
+                               case HASH_SHA512:
+                                       this->cert->algorithm = OID_ECDSA_WITH_SHA512;
+                                       break;
+                               default:
+                                       return FALSE;
+                       }
                        break;
                default:
                        return FALSE;
        }
-       
-       switch (this->cert->public_key->get_type(this->cert->public_key))
+       scheme = signature_scheme_from_oid(this->cert->algorithm);
+
+       if (!this->cert->public_key->get_encoding(this->cert->public_key,
+                                                                                         KEY_PUB_SPKI_ASN1_DER, &key_info))
        {
-               case KEY_RSA:
-                       key = this->cert->public_key->get_encoding(this->cert->public_key);
-                       key_info = asn1_wrap(ASN1_SEQUENCE, "cm",
-                                                       asn1_algorithmIdentifier(OID_RSA_ENCRYPTION), 
-                                                       asn1_bitstring("m", key));      
-                       break;
-               default:
-                       return FALSE;
+               return FALSE;
        }
-       
        if (this->cert->subjectAltNames->get_count(this->cert->subjectAltNames))
        {
                /* TODO: encode subjectAltNames */
        }
        
-       this->cert->tbsCertificate = asn1_wrap(ASN1_SEQUENCE, "mmccmcmm", 
+       this->cert->tbsCertificate = asn1_wrap(ASN1_SEQUENCE, "mmmcmcmm", 
                asn1_simple_object(ASN1_CONTEXT_C_0, ASN1_INTEGER_2),
-               asn1_simple_object(ASN1_INTEGER, this->cert->serialNumber),
+               asn1_integer("c", this->cert->serialNumber),
                asn1_algorithmIdentifier(this->cert->algorithm),
                issuer->get_encoding(issuer),
                asn1_wrap(ASN1_SEQUENCE, "mm",
@@ -1328,7 +1320,7 @@ static bool generate(private_builder_t *this)
        {
                return FALSE;
        }
-       this->cert->encoding = asn1_wrap(ASN1_SEQUENCE, "ccm",
+       this->cert->encoding = asn1_wrap(ASN1_SEQUENCE, "cmm",
                                                                this->cert->tbsCertificate,
                                                                asn1_algorithmIdentifier(this->cert->algorithm),
                                                                asn1_bitstring("c", this->cert->signature));
@@ -1350,33 +1342,22 @@ static bool generate(private_builder_t *this)
 static private_x509_cert_t *build(private_builder_t *this)
 {
        private_x509_cert_t *cert;
-       x509_flag_t flags;
        
-       if (this->cert && !this->cert->encoding.ptr)
+       if (this->cert)
        {
-               if (!this->sign_key || !this->cert ||
-                       !generate(this))
-               {
-                       destroy(this->cert);
-                       free(this);
-                       return NULL;
+               this->cert->flags |= this->flags;
+               if (!this->cert->encoding.ptr)
+               {       /* generate a new certificate */
+                       if (!this->sign_key || !generate(this))
+                       {
+                               destroy(this->cert);
+                               free(this);
+                               return NULL;
+                       }
                }
        }
        cert = this->cert;
-       flags =  this->flags;
        free(this);
-       if (cert == NULL)
-       {
-               return NULL;
-       }
-       
-       if ((flags & X509_CA) && !(cert->flags & X509_CA))
-       {
-               DBG1("  ca certificate must have ca basic constraint set, discarded");
-               destroy(cert);
-               return NULL;
-       }
-       cert->flags |= flags;
        return cert;
 }
 
@@ -1392,9 +1373,6 @@ static void add(private_builder_t *this, builder_part_t part, ...)
        va_start(args, part);
        switch (part)
        {
-               case BUILD_FROM_FILE:
-                       this->cert = create_from_file(va_arg(args, char*));
-                       break;
                case BUILD_BLOB_ASN1_DER:
                        chunk = va_arg(args, chunk_t);
                        this->cert = create_from_chunk(chunk_clone(chunk));
@@ -1456,6 +1434,9 @@ static void add(private_builder_t *this, builder_part_t part, ...)
                        this->cert->serialNumber = chunk_clone(serial);
                        break;
                }
+               case BUILD_DIGEST_ALG:
+                       this->digest_alg = va_arg(args, int);
+                       break;
                default:
                        /* abort if unsupported option */
                        if (this->cert)
@@ -1486,6 +1467,7 @@ builder_t *x509_cert_builder(certificate_type_t type)
        this->flags = 0;
        this->sign_cert = NULL;
        this->sign_key = NULL;
+       this->digest_alg = HASH_SHA1;
        this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add;
        this->public.build = (void*(*)(builder_t *this))build;