From e4ed5f5716f6a8973b098c6bb033838d258d47b0 Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Wed, 30 Jun 2010 02:01:52 +0000 Subject: [PATCH] Add EC key support to helpers and KeyInfo resolution. --- config_win32.h | 1 + configure.ac | 7 + xmltooling/security/impl/InlineKeyResolver.cpp | 15 +- xmltooling/security/impl/SecurityHelper.cpp | 182 ++++++++++++++----------- 4 files changed, 124 insertions(+), 81 deletions(-) diff --git a/config_win32.h b/config_win32.h index ed324c2..fad778f 100644 --- a/config_win32.h +++ b/config_win32.h @@ -129,6 +129,7 @@ # if (_XSEC_VERSION_FULL >= 10600) # define XMLTOOLING_XMLSEC_MULTIPLECRL 1 # define XMLTOOLING_XMLSEC_SIGALGORITHM 1 +# define XMLTOOLING_XMLSEC_ECC 1 # endif #endif diff --git a/configure.ac b/configure.ac index 6e78970..4c7fd07 100644 --- a/configure.ac +++ b/configure.ac @@ -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 ], + [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" diff --git a/xmltooling/security/impl/InlineKeyResolver.cpp b/xmltooling/security/impl/InlineKeyResolver.cpp index 9c3471c..9ed4dee 100644 --- a/xmltooling/security/impl/InlineKeyResolver.cpp +++ b/xmltooling/security/impl/InlineKeyResolver.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -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 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()); diff --git a/xmltooling/security/impl/SecurityHelper.cpp b/xmltooling/security/impl/SecurityHelper.cpp index 4b87ac7..d847a60 100644 --- a/xmltooling/security/impl/SecurityHelper.cpp +++ b/xmltooling/security/impl/SecurityHelper.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include 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(key1).getOpenSSLEC(); + const EC_KEY* ec2 = static_cast(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(key1).getOpenSSLEC(); + const EC_KEY* ec2 = static_cast(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(key).getOpenSSLRSA(); + rsa = static_cast(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)); - 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(key).getOpenSSLDSA(); + dsa = static_cast(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(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)); + else if (dsa) i2d_DSA_PUBKEY_bio(chain, const_cast(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)); +#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"); } -- 2.1.4