Add EC key support to helpers and KeyInfo resolution.
authorScott Cantor <cantor.2@osu.edu>
Wed, 30 Jun 2010 02:01:52 +0000 (02:01 +0000)
committerScott Cantor <cantor.2@osu.edu>
Wed, 30 Jun 2010 02:01:52 +0000 (02:01 +0000)
config_win32.h
configure.ac
xmltooling/security/impl/InlineKeyResolver.cpp
xmltooling/security/impl/SecurityHelper.cpp

index ed324c2..fad778f 100644 (file)
 # if (_XSEC_VERSION_FULL >= 10600)
 #  define XMLTOOLING_XMLSEC_MULTIPLECRL 1
 #  define XMLTOOLING_XMLSEC_SIGALGORITHM 1
+#  define XMLTOOLING_XMLSEC_ECC 1
 # endif
 #endif
 
index 6e78970..4c7fd07 100644 (file)
@@ -328,6 +328,13 @@ int i = 0;
           [AC_DEFINE([XMLTOOLING_XMLSEC_SIGALGORITHM], [1], [Define to 1 if XML-Security-C exposes the signature algorithm URI.])],
           [AC_MSG_RESULT([no])])
 
+    AC_MSG_CHECKING([whether XML-Security-C includes ECC support])
+    AC_TRY_COMPILE([#include <xsec/dsig/DSIGKeyInfoValue.hpp>],
+          [DSIGKeyInfoValue* info; info->getECNamedCurve();],
+          [AC_MSG_RESULT([yes])]
+          [AC_DEFINE([XMLTOOLING_XMLSEC_ECC], [1], [Define to 1 if XML-Security-C includes ECC support.])],
+          [AC_MSG_RESULT([no])])
+
        # restore master libs
        LIBS="$save_LIBS"
 
index 9c3471c..9ed4dee 100644 (file)
@@ -40,6 +40,7 @@
 #include <xsec/enc/XSECCryptoX509.hpp>
 #include <xsec/enc/XSECCryptoKeyRSA.hpp>
 #include <xsec/enc/XSECCryptoKeyDSA.hpp>
+#include <xsec/enc/XSECCryptoKeyEC.hpp>
 #include <xsec/enc/XSECCryptoException.hpp>
 #include <xsec/framework/XSECException.hpp>
 
@@ -282,10 +283,20 @@ bool InlineCredential::resolveKey(const KeyInfo* keyInfo, bool followRefs)
                 m_key = dsa.release();
                 return true;
             }
+#ifdef XMLTOOLING_XMLSEC_ECC
             ECKeyValue* eckv = (*i)->getECKeyValue();
-            if (eckv) {
-                log.warn("skipping ds11:ECKeyValue, not yet supported");
+            if (eckv && eckv->getNamedCurve() && eckv->getPublicKey()) {
+                log.warn("resolving ds11:ECKeyValue");
+                auto_ptr<XSECCryptoKeyEC> ec(XSECPlatformUtils::g_cryptoProvider->keyEC());
+                auto_ptr_char uri(eckv->getNamedCurve()->getURI());
+                auto_ptr_char val(eckv->getPublicKey()->getValue());
+                if (uri.get() && val.get()) {
+                    ec->loadPublicKeyBase64(uri.get(), val.get(), XMLString::stringLen(val.get()));
+                    m_key = ec.release();
+                    return true;
+                }
             }
+#endif
         }
         catch (ValidationException& ex) {
             log.warn("skipping invalid ds:KeyValue (%s)", ex.what());
index 4b87ac7..d847a60 100644 (file)
@@ -37,6 +37,7 @@
 #include <xsec/enc/OpenSSL/OpenSSLCryptoX509.hpp>
 #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.hpp>
 #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyDSA.hpp>
+#include <xsec/enc/OpenSSL/OpenSSLCryptoKeyEC.hpp>
 #include <xercesc/util/Base64.hpp>
 
 using namespace xmltooling::logging;
@@ -200,6 +201,11 @@ XSECCryptoKey* SecurityHelper::loadKeyFromFile(const char* pathname, const char*
                 ret=new OpenSSLCryptoKeyDSA(pkey);
                 break;
 
+#ifdef XSEC_OPENSSL_HAVE_EC
+            case EVP_PKEY_EC:
+                ret=new OpenSSLCryptoKeyEC(pkey);
+                break;
+#endif
             default:
                 log.error("unsupported private key type");
         }
@@ -497,6 +503,30 @@ bool SecurityHelper::matches(const XSECCryptoKey& key1, const XSECCryptoKey& key
         return (dsa1 && dsa2 && BN_cmp(dsa1->priv_key,dsa2->priv_key) == 0);
     }
 
+#ifdef XMLTOOLING_XMLSEC_ECC
+    // If one key is public or both, just compare the public key half.
+    if (key1.getKeyType()==XSECCryptoKey::KEY_EC_PUBLIC || key1.getKeyType()==XSECCryptoKey::KEY_EC_PAIR) {
+        if (key2.getKeyType()!=XSECCryptoKey::KEY_EC_PUBLIC && key2.getKeyType()!=XSECCryptoKey::KEY_EC_PAIR)
+            return false;
+        const EC_KEY* ec1 = static_cast<const OpenSSLCryptoKeyEC&>(key1).getOpenSSLEC();
+        const EC_KEY* ec2 = static_cast<const OpenSSLCryptoKeyEC&>(key2).getOpenSSLEC();
+        if (!ec1 || !ec2)
+            return false;
+        if (EC_GROUP_cmp(EC_KEY_get0_group(ec1), EC_KEY_get0_group(ec2), nullptr) != 0)
+            return false;
+        return (EC_POINT_cmp(EC_KEY_get0_group(ec1), EC_KEY_get0_public_key(ec1), EC_KEY_get0_public_key(ec2), nullptr) == 0);
+    }
+
+    // For a private key, compare the private half.
+    if (key1.getKeyType()==XSECCryptoKey::KEY_EC_PRIVATE) {
+        if (key2.getKeyType()!=XSECCryptoKey::KEY_EC_PRIVATE && key2.getKeyType()!=XSECCryptoKey::KEY_EC_PAIR)
+            return false;
+        const EC_KEY* ec1 = static_cast<const OpenSSLCryptoKeyEC&>(key1).getOpenSSLEC();
+        const EC_KEY* ec2 = static_cast<const OpenSSLCryptoKeyEC&>(key2).getOpenSSLEC();
+        return (ec1 && ec2 && BN_cmp(EC_KEY_get0_private_key(ec1), EC_KEY_get0_private_key(ec2)) == 0);
+    }
+#endif
+
     Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("unsupported key type for comparison");
     return false;
 }
@@ -551,101 +581,90 @@ string SecurityHelper::getDEREncoding(const XSECCryptoKey& key, const char* hash
         return ret;
     }
 
+    const RSA* rsa = nullptr;
+    const DSA* dsa = nullptr;
+#ifdef XMLTOOLING_XMLSEC_ECC
+    const EC_KEY* ec = nullptr;
+#endif
+
     if (key.getKeyType() == XSECCryptoKey::KEY_RSA_PUBLIC || key.getKeyType() == XSECCryptoKey::KEY_RSA_PAIR) {
-        const RSA* rsa = static_cast<const OpenSSLCryptoKeyRSA&>(key).getOpenSSLRSA();
+        rsa = static_cast<const OpenSSLCryptoKeyRSA&>(key).getOpenSSLRSA();
         if (!rsa) {
             Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("key was not populated");
             return ret;
         }
-        const EVP_MD* md=nullptr;
-        if (hash) {
-            md = EVP_get_digestbyname(hash);
-            if (!md) {
-                Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").error("hash algorithm (%s) not available", hash);
-                return ret;
-            }
-        }
-        BIO* chain = BIO_new(BIO_s_mem());
-        BIO* b = BIO_new(BIO_f_base64());
-        if (nowrap)
-            BIO_set_flags(b, BIO_FLAGS_BASE64_NO_NL);
-        chain = BIO_push(b, chain);
-        if (md) {
-            b = BIO_new(BIO_f_md());
-            BIO_set_md(b, md);
-            chain = BIO_push(b, chain);
-        }
-        i2d_RSA_PUBKEY_bio(chain, const_cast<RSA*>(rsa));
-        BIO_flush(chain);
-        if (md) {
-            char digest[EVP_MAX_MD_SIZE];
-            int len = BIO_gets(chain, digest, EVP_MD_size(md));
-            if (len != EVP_MD_size(md)) {
-                BIO_free_all(chain);
-                return ret;
-            }
-            b = BIO_pop(chain);
-            BIO_free(chain);
-            chain = b;
-            BIO_reset(chain);
-            BIO_write(chain, digest, len);
-            BIO_flush(chain);
-        }
-        BUF_MEM* bptr=nullptr;
-        BIO_get_mem_ptr(chain, &bptr);
-        if (bptr && bptr->length > 0)
-            ret.append(bptr->data, bptr->length);
-        BIO_free_all(chain);
     }
     else if (key.getKeyType() == XSECCryptoKey::KEY_DSA_PUBLIC || key.getKeyType() == XSECCryptoKey::KEY_DSA_PAIR) {
-        const DSA* dsa = static_cast<const OpenSSLCryptoKeyDSA&>(key).getOpenSSLDSA();
+        dsa = static_cast<const OpenSSLCryptoKeyDSA&>(key).getOpenSSLDSA();
         if (!dsa) {
             Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("key was not populated");
             return ret;
         }
-        const EVP_MD* md=nullptr;
-        if (hash) {
-            md = EVP_get_digestbyname(hash);
-            if (!md) {
-                Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").error("hash algorithm (%s) not available", hash);
-                return ret;
-            }
+    }
+#ifdef XMLTOOLING_XMLSEC_ECC
+    else if (key.getKeyType() == XSECCryptoKey::KEY_EC_PUBLIC || key.getKeyType() == XSECCryptoKey::KEY_EC_PAIR) {
+        ec = static_cast<const OpenSSLCryptoKeyEC&>(key).getOpenSSLEC();
+        if (!ec) {
+            Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("key was not populated");
+            return ret;
         }
-        BIO* chain = BIO_new(BIO_s_mem());
-        BIO* b = BIO_new(BIO_f_base64());
-        if (nowrap)
-            BIO_set_flags(b, BIO_FLAGS_BASE64_NO_NL);
-        chain = BIO_push(b, chain);
-        if (md) {
-            b = BIO_new(BIO_f_md());
-            BIO_set_md(b, md);
-            chain = BIO_push(b, chain);
+    }
+#endif
+    else {
+        Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("public key type not supported");
+        return ret;
+    }
+
+    const EVP_MD* md=nullptr;
+    if (hash) {
+        md = EVP_get_digestbyname(hash);
+        if (!md) {
+            Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").error("hash algorithm (%s) not available", hash);
+            return ret;
         }
+    }
+
+    BIO* chain = BIO_new(BIO_s_mem());
+    BIO* b = BIO_new(BIO_f_base64());
+    if (nowrap)
+        BIO_set_flags(b, BIO_FLAGS_BASE64_NO_NL);
+    chain = BIO_push(b, chain);
+    if (md) {
+        b = BIO_new(BIO_f_md());
+        BIO_set_md(b, md);
+        chain = BIO_push(b, chain);
+    }
+
+    if (rsa)
+        i2d_RSA_PUBKEY_bio(chain, const_cast<RSA*>(rsa));
+    else if (dsa)
         i2d_DSA_PUBKEY_bio(chain, const_cast<DSA*>(dsa));
-        BIO_flush(chain);
-        if (md) {
-            char digest[EVP_MAX_MD_SIZE];
-            int len = BIO_gets(chain, digest, EVP_MD_size(md));
-            if (len != EVP_MD_size(md)) {
-                BIO_free_all(chain);
-                return ret;
-            }
-            b = BIO_pop(chain);
-            BIO_free(chain);
-            chain = b;
-            BIO_reset(chain);
-            BIO_write(chain, digest, len);
-            BIO_flush(chain);
+#ifdef XMLTOOLING_XMLSEC_ECC
+    else
+        i2d_EC_PUBKEY_bio(chain, const_cast<EC_KEY*>(ec));
+#endif
+
+    BIO_flush(chain);
+    if (md) {
+        char digest[EVP_MAX_MD_SIZE];
+        int len = BIO_gets(chain, digest, EVP_MD_size(md));
+        if (len != EVP_MD_size(md)) {
+            BIO_free_all(chain);
+            return ret;
         }
-        BUF_MEM* bptr=nullptr;
-        BIO_get_mem_ptr(chain, &bptr);
-        if (bptr && bptr->length > 0)
-            ret.append(bptr->data, bptr->length);
-        BIO_free_all(chain);
-    }
-    else {
-        Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("encoding of non-RSA/DSA public keys not supported");
+        b = BIO_pop(chain);
+        BIO_free(chain);
+        chain = b;
+        BIO_reset(chain);
+        BIO_write(chain, digest, len);
+        BIO_flush(chain);
     }
+    BUF_MEM* bptr=nullptr;
+    BIO_get_mem_ptr(chain, &bptr);
+    if (bptr && bptr->length > 0)
+        ret.append(bptr->data, bptr->length);
+    BIO_free_all(chain);
+
     return ret;
 }
 
@@ -766,6 +785,11 @@ XSECCryptoKey* SecurityHelper::fromDEREncoding(const char* buf, unsigned long bu
                     ret = new OpenSSLCryptoKeyDSA(pkey);
                     break;
 
+#ifdef XMLTOOLING_XMLSEC_ECC
+                case EVP_PKEY_EC:
+                    ret = new OpenSSLCryptoKeyEC(pkey);
+                    break;
+#endif
                 default:
                     Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").error("unsupported public key type");
             }