distinguish between RFC 4754 (concatenated) and RFC 3279 (DER encoded) ECDSA signatures
authorMartin Willi <martin@strongswan.org>
Thu, 27 Aug 2009 15:36:17 +0000 (17:36 +0200)
committerMartin Willi <martin@strongswan.org>
Thu, 27 Aug 2009 15:37:42 +0000 (17:37 +0200)
src/libstrongswan/credentials/keys/public_key.c
src/libstrongswan/credentials/keys/public_key.h
src/libstrongswan/plugins/openssl/openssl_ec_private_key.c
src/libstrongswan/plugins/openssl/openssl_ec_public_key.c
src/libstrongswan/plugins/x509/x509_cert.c
src/libstrongswan/plugins/x509/x509_ocsp_request.c

index 4abaf40..8958a35 100644 (file)
@@ -32,8 +32,11 @@ ENUM(signature_scheme_names, SIGN_UNKNOWN, SIGN_ECDSA_521,
        "RSA_EMSA_PKCS1_SHA256",
        "RSA_EMSA_PKCS1_SHA384",
        "RSA_EMSA_PKCS1_SHA512",
+       "ECDSA_WITH_SHA1_DER",
+       "ECDSA_WITH_SHA256_DER",
+       "ECDSA_WITH_SHA384_DER",
+       "ECDSA_WITH_SHA512_DER",
        "ECDSA_WITH_NULL",
-       "ECDSA_WITH_SHA1",
        "ECDSA-256",
        "ECDSA-384",
        "ECDSA-521",
@@ -90,13 +93,13 @@ signature_scheme_t signature_scheme_from_oid(int oid)
                        return SIGN_RSA_EMSA_PKCS1_SHA512;
                case OID_ECDSA_WITH_SHA1:
                case OID_EC_PUBLICKEY:
-                       return SIGN_ECDSA_WITH_SHA1;
+                       return SIGN_ECDSA_WITH_SHA1_DER;
                case OID_ECDSA_WITH_SHA256:
-                       return SIGN_ECDSA_256;
+                       return SIGN_ECDSA_WITH_SHA256_DER;
                case OID_ECDSA_WITH_SHA384:
-                       return SIGN_ECDSA_384;
+                       return SIGN_ECDSA_WITH_SHA384_DER;
                case OID_ECDSA_WITH_SHA512:
-                       return SIGN_ECDSA_521;
+                       return SIGN_ECDSA_WITH_SHA512_DER;
                default:
                        return SIGN_UNKNOWN;
        }
index 294a956..984c8c0 100644 (file)
@@ -54,8 +54,7 @@ extern enum_name_t *key_type_names;
  *
  * EMSA-PKCS1 signatures are defined in PKCS#1 standard.
  * A prepended ASN.1 encoded digestInfo field contains the 
- * OID of the used hash algorithm. The ASN.1 type of the PKCS#7
- * variants is OCTET_STRING instead of the default BIT_STRING.
+ * OID of the used hash algorithm.
  */
 enum signature_scheme_t {
        /** Unknown signature scheme                                       */
@@ -74,10 +73,16 @@ enum signature_scheme_t {
        SIGN_RSA_EMSA_PKCS1_SHA384,
        /** EMSA-PKCS1_v1.5 signature as in PKCS#1 using RSA and SHA-512   */
        SIGN_RSA_EMSA_PKCS1_SHA512,
-       /** ECDSA over precomputed digest                                  */
+       /** ECDSA with SHA-1 using DER encoding as in RFC 3279             */
+       SIGN_ECDSA_WITH_SHA1_DER,
+       /** ECDSA with SHA-256 using DER encoding as in RFC 3279           */
+       SIGN_ECDSA_WITH_SHA256_DER,
+       /** ECDSA with SHA-384 using DER encoding as in RFC 3279           */
+       SIGN_ECDSA_WITH_SHA384_DER,
+       /** ECDSA with SHA-1 using DER encoding as in RFC 3279             */
+       SIGN_ECDSA_WITH_SHA512_DER,
+       /** ECDSA over precomputed digest, signature as in RFC 4754        */
        SIGN_ECDSA_WITH_NULL,
-       /** ECDSA with SHA-1                                               */
-       SIGN_ECDSA_WITH_SHA1,
        /** ECDSA on the P-256 curve with SHA-256 as in RFC 4754           */
        SIGN_ECDSA_256,
        /** ECDSA on the P-384 curve with SHA-384 as in RFC 4754           */
index f333bd3..576eaf5 100644 (file)
@@ -43,153 +43,129 @@ struct private_openssl_ec_private_key_t {
        /**
         * reference count
         */
-       refcount_t ref; 
+       refcount_t ref;
 };
 
-/**
- * Mapping from the signature scheme defined in (RFC 4754) to the elliptic
- * curve and the hash algorithm
- */
-typedef struct {
-       /**
-        * Scheme specified in RFC 4754
-        */
-       int scheme;
-       
-       /**
-        * NID of the hash
-        */
-       int hash;
-       
-       /**
-        * NID of the curve
-        */
-       int curve;
-} openssl_ecdsa_scheme_t;
-
-#define END_OF_LIST -1
-
-/**
- * Signature schemes
- */
-static openssl_ecdsa_scheme_t ecdsa_schemes[] = {
-       {SIGN_ECDSA_WITH_SHA1,  NID_sha1,       -1},
-       {SIGN_ECDSA_256,                NID_sha256,     NID_X9_62_prime256v1},
-       {SIGN_ECDSA_384,                NID_sha384,     NID_secp384r1},
-       {SIGN_ECDSA_521,                NID_sha512,     NID_secp521r1},
-       {END_OF_LIST,                   0,                      0},
-};
-
-/**
- * Look up the hash and curve of a signature scheme
- */
-static bool lookup_scheme(int scheme, int *hash, int *curve)
-{
-       openssl_ecdsa_scheme_t *ecdsa_scheme = ecdsa_schemes;
-       while (ecdsa_scheme->scheme != END_OF_LIST)
-       {
-               if (scheme == ecdsa_scheme->scheme)
-               {
-                       *hash = ecdsa_scheme->hash;
-                       *curve = ecdsa_scheme->curve;
-                       return TRUE;
-               }
-               ecdsa_scheme++;
-       }
-       return FALSE;
-}
-
 /* from ec public key */
 bool openssl_ec_fingerprint(EC_KEY *ec, key_encoding_type_t type, chunk_t *fp);
 
 /**
- * Convert an ECDSA_SIG to a chunk by concatenating r and s.
- * This function allocates memory for the chunk.
- */
-static bool sig2chunk(const EC_GROUP *group, ECDSA_SIG *sig, chunk_t *chunk)
-{
-       return openssl_bn_cat(EC_FIELD_ELEMENT_LEN(group), sig->r, sig->s, chunk);
-}
-
-/**
- * Build the signature
+ * Build a signature as in RFC 4754
  */
 static bool build_signature(private_openssl_ec_private_key_t *this,
                                                        chunk_t hash, chunk_t *signature)
 {
+       bool built = FALSE;
        ECDSA_SIG *sig;
-       bool success;
        
        sig = ECDSA_do_sign(hash.ptr, hash.len, this->ec);
-       if (!sig)
+       if (sig)
        {
-               return FALSE;
+               /* concatenate BNs r/s to a signature chunk */
+               built = openssl_bn_cat(EC_FIELD_ELEMENT_LEN(EC_KEY_get0_group(this->ec)),
+                                                          sig->r, sig->s, signature);
+               ECDSA_SIG_free(sig);
        }
-       success = sig2chunk(EC_KEY_get0_group(this->ec), sig, signature);
-       ECDSA_SIG_free(sig);
-       return success;
+       return built;
 }
 
 /**
- * Implementation of private_key_t.get_type.
+ * Build a RFC 4754 signature for a specified curve and hash algorithm
  */
-static key_type_t get_type(private_openssl_ec_private_key_t *this)
+static bool build_curve_signature(private_openssl_ec_private_key_t *this,
+                                                               signature_scheme_t scheme, int nid_hash,
+                                                               int nid_curve, chunk_t data, chunk_t *signature)
 {
-       return KEY_ECDSA;
+       const EC_GROUP *my_group;
+       EC_GROUP *req_group;
+       chunk_t hash;
+       bool built;
+       
+       req_group = EC_GROUP_new_by_curve_name(nid_curve);
+       if (!req_group)
+       {
+               DBG1("signature scheme %N not supported in EC (required curve "
+                        "not supported)", signature_scheme_names, scheme);
+               return FALSE;
+       }
+       my_group = EC_KEY_get0_group(this->ec);
+       if (EC_GROUP_cmp(my_group, req_group, NULL) != 0)
+       {
+               DBG1("signature scheme %N not supported by private key",
+                        signature_scheme_names, scheme);
+               return FALSE;
+       }
+       EC_GROUP_free(req_group);
+       if (!openssl_hash_chunk(nid_hash, data, &hash))
+       {
+               return FALSE;
+       }
+       built = build_signature(this, data, signature);
+       chunk_free(&hash);
+       return built;
 }
 
 /**
- * Implementation of private_key_t.sign.
+ * Build a DER encoded signature as in RFC 3279
  */
-static bool sign(private_openssl_ec_private_key_t *this, signature_scheme_t scheme, 
-                                chunk_t data, chunk_t *signature)
+static bool build_der_signature(private_openssl_ec_private_key_t *this,
+                                                               int hash_nid, chunk_t data, chunk_t *signature)
 {
-       bool success;
+       chunk_t hash, sig;
+       int siglen = 0;
+       bool built;
        
-       if (scheme == SIGN_ECDSA_WITH_NULL)
+       if (!openssl_hash_chunk(hash_nid, data, &hash))
        {
-               success = build_signature(this, data, signature);
+               return FALSE;
+       }
+       sig = chunk_alloc(ECDSA_size(this->ec));
+       built = ECDSA_sign(0, hash.ptr, hash.len, sig.ptr, &siglen, this->ec) == 1;
+       sig.len = siglen;
+       if (built)
+       {
+               *signature = sig;
        }
        else
        {
-               EC_GROUP *req_group;
-               const EC_GROUP *my_group;
-               chunk_t hash = chunk_empty;
-               int hash_type, curve;
-               
-               if (!lookup_scheme(scheme, &hash_type, &curve))
-               {
-                       DBG1("signature scheme %N not supported in EC",
-                                        signature_scheme_names, scheme);
-                       return FALSE;
-               }
-               
-               if (curve != -1)
-               {
-                       req_group = EC_GROUP_new_by_curve_name(curve);
-                       if (!req_group)
-                       {
-                               DBG1("signature scheme %N not supported in EC (required curve "
-                                        "not supported)", signature_scheme_names, scheme);
-                               return FALSE;
-                       }
-                       my_group = EC_KEY_get0_group(this->ec);
-                       if (EC_GROUP_cmp(my_group, req_group, NULL) != 0)
-                       {
-                               DBG1("signature scheme %N not supported by private key",
-                                        signature_scheme_names, scheme);
-                               return FALSE;
-                       }
-                       EC_GROUP_free(req_group);
-               }
-               if (!openssl_hash_chunk(hash_type, data, &hash))
-               {
+               free(sig.ptr);
+       }
+       free(hash.ptr);
+       return built;
+}
+
+/**
+ * Implementation of private_key_t.sign.
+ */
+static bool sign(private_openssl_ec_private_key_t *this,
+                                signature_scheme_t scheme, chunk_t data, chunk_t *signature)
+{
+       switch (scheme)
+       {
+               case SIGN_ECDSA_WITH_NULL:
+                       return build_signature(this, data, signature);
+               case SIGN_ECDSA_WITH_SHA1_DER:
+                       return build_der_signature(this, NID_sha1, data, signature);
+               case SIGN_ECDSA_WITH_SHA256_DER:
+                       return build_der_signature(this, NID_sha256, data, signature);
+               case SIGN_ECDSA_WITH_SHA384_DER:
+                       return build_der_signature(this, NID_sha384, data, signature);
+               case SIGN_ECDSA_WITH_SHA512_DER:
+                       return build_der_signature(this, NID_sha512, data, signature);
+               case SIGN_ECDSA_256:
+                       return build_curve_signature(this, scheme, NID_X9_62_prime256v1,
+                                                                                NID_sha256, data, signature);
+               case SIGN_ECDSA_384:
+                       return build_curve_signature(this, scheme, NID_secp384r1,
+                                                                                NID_sha384, data, signature);
+               case SIGN_ECDSA_521:
+                       return build_curve_signature(this, scheme, NID_secp521r1,
+                                                                                NID_sha512, data, signature);
+               default:
+                       DBG1("signature scheme %N not supported",
+                                signature_scheme_names, scheme);
                        return FALSE;
-               }
-               success = build_signature(this, hash, signature);
-               chunk_free(&hash);
-       }       
-       return success;
+       }
 }
 
 /**
@@ -211,6 +187,14 @@ static size_t get_keysize(private_openssl_ec_private_key_t *this)
 }
 
 /**
+ * Implementation of private_key_t.get_type.
+ */
+static key_type_t get_type(private_openssl_ec_private_key_t *this)
+{
+       return KEY_ECDSA;
+}
+
+/**
  * Implementation of private_key_t.get_public_key.
  */
 static public_key_t* get_public_key(private_openssl_ec_private_key_t *this)
index d1b3a4e..b351067 100644 (file)
@@ -46,51 +46,31 @@ struct private_openssl_ec_public_key_t {
 };
 
 /**
- * Convert a chunk to an ECDSA_SIG (which must already exist). r and s
- * of the signature have to be concatenated in the chunk.
- */
-static bool chunk2sig(const EC_GROUP *group, chunk_t chunk, ECDSA_SIG *sig)
-{
-       return openssl_bn_split(chunk, sig->r, sig->s);
-}
-
-/**
  * Verification of a signature as in RFC 4754
  */
 static bool verify_signature(private_openssl_ec_public_key_t *this,
-                                                               int hash_type, chunk_t data, chunk_t signature)
+                                                        int hash_type, chunk_t data, chunk_t signature)
 {
-       chunk_t hash = chunk_empty;
-       ECDSA_SIG *sig;
        bool valid = FALSE;
+       ECDSA_SIG *sig;
+       chunk_t hash;
        
-       if (hash_type == NID_undef)
-       {
-               hash = data;
-       }
-       else
+       hash = data;
+       if (hash_type != NID_undef)
        {
                if (!openssl_hash_chunk(hash_type, data, &hash))
                {
                        return FALSE;
                }
        }
-       
        sig = ECDSA_SIG_new();
-       if (!sig)
-       {
-               goto error;
-       }
-       
-       if (!chunk2sig(EC_KEY_get0_group(this->ec), signature, sig))
-       {
-               goto error;
-       }
-       valid = (ECDSA_do_verify(hash.ptr, hash.len, sig, this->ec) == 1);
-       
-error:
        if (sig)
        {
+               /* split the signature chunk in r and s */
+               if (openssl_bn_split(signature, sig->r, sig->s))
+               {
+                       valid = (ECDSA_do_verify(hash.ptr, hash.len, sig, this->ec) == 1);
+               }
                ECDSA_SIG_free(sig);
        }
        if (hash_type != NID_undef)
@@ -100,45 +80,26 @@ error:
        return valid;
 }
 
-
 /**
- * Verification of the default signature using SHA-1
+ * Verification of a DER encoded signature as in RFC 3279
  */
-static bool verify_default_signature(private_openssl_ec_public_key_t *this,
-                                                               chunk_t data, chunk_t signature)
+static bool verify_der_signature(private_openssl_ec_public_key_t *this,
+                                                                int nid, chunk_t data, chunk_t signature)
 {
+       chunk_t hash;
        bool valid = FALSE;
-       chunk_t hash = chunk_empty;
-       u_char *p;
-       ECDSA_SIG *sig;
        
        /* remove any preceding 0-bytes from signature */
-       while (signature.len && *(signature.ptr) == 0x00)
-       {
-               signature.len -= 1;
-               signature.ptr++;
-       }
-       
-       p = signature.ptr;
-       sig = d2i_ECDSA_SIG(NULL, (const u_char**)&p, signature.len);
-       if (!sig)
+       while (signature.len && signature.ptr[0] == 0x00)
        {
-               return FALSE;
-       }
-       
-       if (!openssl_hash_chunk(NID_sha1, data, &hash))
-       {
-               goto error;
+               signature = chunk_skip(signature, 1);
        }
-       
-       valid = (ECDSA_do_verify(hash.ptr, hash.len, sig, this->ec) == 1);
-
-error:
-       if (sig)
+       if (openssl_hash_chunk(nid, data, &hash))
        {
-               ECDSA_SIG_free(sig);
+               valid = ECDSA_verify(0, hash.ptr, hash.len,
+                                                        signature.ptr, signature.len, this->ec);
+               free(hash.ptr);
        }
-       chunk_free(&hash);
        return valid;
 }
 
@@ -158,10 +119,16 @@ static bool verify(private_openssl_ec_public_key_t *this, signature_scheme_t sch
 {
        switch (scheme)
        {
+               case SIGN_ECDSA_WITH_SHA1_DER:
+                       return verify_der_signature(this, NID_sha1, data, signature);
+               case SIGN_ECDSA_WITH_SHA256_DER:
+                       return verify_der_signature(this, NID_sha256, data, signature);
+               case SIGN_ECDSA_WITH_SHA384_DER:
+                       return verify_der_signature(this, NID_sha384, data, signature);
+               case SIGN_ECDSA_WITH_SHA512_DER:
+                       return verify_der_signature(this, NID_sha512, data, signature);
                case SIGN_ECDSA_WITH_NULL:
                        return verify_signature(this, NID_undef, data, signature);
-               case SIGN_ECDSA_WITH_SHA1:
-                       return verify_default_signature(this, data, signature);
                case SIGN_ECDSA_256:
                        return verify_signature(this, NID_sha256, data, signature);
                case SIGN_ECDSA_384:
index 8a68e9d..c8d0dab 100644 (file)
@@ -1249,7 +1249,7 @@ static bool generate(private_builder_t *this)
                        scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
                        break;
                case KEY_ECDSA:
-                       scheme = SIGN_ECDSA_WITH_SHA1;
+                       scheme = SIGN_ECDSA_WITH_SHA1_DER;
                        this->cert->algorithm = OID_ECDSA_WITH_SHA1;
                        break;
                default:
index f65fa6d..e772b97 100644 (file)
@@ -266,7 +266,7 @@ static chunk_t build_optionalSignature(private_x509_ocsp_request_t *this,
                        break;
                case KEY_ECDSA:
                        oid = OID_ECDSA_WITH_SHA1;
-                       scheme = SIGN_ECDSA_WITH_SHA1;
+                       scheme = SIGN_ECDSA_WITH_SHA1_DER;
                        break;
                default:
                        DBG1("unable to sign OCSP request, %N signature not supported",