From c4b9345c1dac797b6492ed5c1eb695236852fe24 Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Mon, 2 Nov 2009 15:52:34 +0000 Subject: [PATCH] Support alternate hash algorithms in helper routines. --- .cproject | 1 + xmltooling/security/SecurityHelper.h | 9 ++-- xmltooling/security/impl/SecurityHelper.cpp | 71 +++++++++++++++++++---------- xmltoolingtest/SecurityHelperTest.h | 5 ++ 4 files changed, 60 insertions(+), 26 deletions(-) diff --git a/.cproject b/.cproject index 703a661..34bcb9d 100644 --- a/.cproject +++ b/.cproject @@ -58,6 +58,7 @@ diff --git a/xmltooling/security/SecurityHelper.h b/xmltooling/security/SecurityHelper.h index 7ad65d9..e6cbee3 100644 --- a/xmltooling/security/SecurityHelper.h +++ b/xmltooling/security/SecurityHelper.h @@ -138,9 +138,10 @@ namespace xmltooling { * @param cred the credential containing the key to encode * @param hash if true, the DER encoded data is hashed with SHA-1 before base64 encoding * @param nowrap if true, any linefeeds will be stripped from the result + * @param hashAlg name of hash algorithm, syntax specific to crypto provider * @return the base64 encoded key value */ - static std::string getDEREncoding(const Credential& cred, bool hash=false, bool nowrap=true); + static std::string getDEREncoding(const Credential& cred, bool hash=false, bool nowrap=true, const char* hashAlg="SHA1"); /** * Returns the base64-encoded DER encoding of a public key in SubjectPublicKeyInfo format. @@ -148,9 +149,10 @@ namespace xmltooling { * @param key the key to encode * @param hash if true, the DER encoded data is hashed with SHA-1 before base64 encoding * @param nowrap if true, any linefeeds will be stripped from the result + * @param hashAlg name of hash algorithm, syntax specific to crypto provider * @return the base64 encoded key value */ - static std::string getDEREncoding(const XSECCryptoKey& key, bool hash=false, bool nowrap=true); + static std::string getDEREncoding(const XSECCryptoKey& key, bool hash=false, bool nowrap=true, const char* hashAlg="SHA1"); /** * Returns the base64-encoded DER encoding of a certifiate's public key in SubjectPublicKeyInfo format. @@ -158,9 +160,10 @@ namespace xmltooling { * @param cert the certificate's key to encode * @param hash if true, the DER encoded data is hashed with SHA-1 before base64 encoding * @param nowrap if true, any linefeeds will be stripped from the result + * @param hashAlg name of hash algorithm, syntax specific to crypto provider * @return the base64 encoded key value */ - static std::string getDEREncoding(const XSECCryptoX509& cert, bool hash=false, bool nowrap=true); + static std::string getDEREncoding(const XSECCryptoX509& cert, bool hash=false, bool nowrap=true, const char* hashAlg="SHA1"); }; }; diff --git a/xmltooling/security/impl/SecurityHelper.cpp b/xmltooling/security/impl/SecurityHelper.cpp index ebcc37c..ea69204 100644 --- a/xmltooling/security/impl/SecurityHelper.cpp +++ b/xmltooling/security/impl/SecurityHelper.cpp @@ -484,7 +484,7 @@ bool SecurityHelper::matches(const XSECCryptoKey& key1, const XSECCryptoKey& key return false; } -string SecurityHelper::getDEREncoding(const XSECCryptoKey& key, bool hash, bool nowrap) +string SecurityHelper::getDEREncoding(const XSECCryptoKey& key, bool hash, bool nowrap, const char* hashAlg) { string ret; @@ -499,22 +499,30 @@ string SecurityHelper::getDEREncoding(const XSECCryptoKey& key, bool hash, bool Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("key was not populated"); return ret; } + const EVP_MD* md=NULL; + if (hash && hashAlg) { + md = EVP_get_digestbyname(hashAlg); + if (!md) { + Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").error("hash algorithm (%s) not available", hashAlg); + 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 (hash) { + if (md) { b = BIO_new(BIO_f_md()); - BIO_set_md(b, EVP_sha1()); + BIO_set_md(b, md); chain = BIO_push(b, chain); } i2d_RSA_PUBKEY_bio(chain, const_cast(rsa)); BIO_flush(chain); - if (hash) { - char digest[20]; - int len = BIO_gets(chain, digest, sizeof(digest)); - if (len != sizeof(digest)) { + 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; } @@ -537,22 +545,30 @@ string SecurityHelper::getDEREncoding(const XSECCryptoKey& key, bool hash, bool Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("key was not populated"); return ret; } + const EVP_MD* md=NULL; + if (hash && hashAlg) { + md = EVP_get_digestbyname(hashAlg); + if (!md) { + Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").error("hash algorithm (%s) not available", hashAlg); + 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 (hash) { + if (md) { b = BIO_new(BIO_f_md()); - BIO_set_md(b, EVP_sha1()); + BIO_set_md(b, md); chain = BIO_push(b, chain); } i2d_DSA_PUBKEY_bio(chain, const_cast(dsa)); BIO_flush(chain); - if (hash) { - char digest[20]; - int len = BIO_gets(chain, digest, sizeof(digest)); - if (len != sizeof(digest)) { + 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; } @@ -575,7 +591,7 @@ string SecurityHelper::getDEREncoding(const XSECCryptoKey& key, bool hash, bool return ret; } -string SecurityHelper::getDEREncoding(const XSECCryptoX509& cert, bool hash, bool nowrap) +string SecurityHelper::getDEREncoding(const XSECCryptoX509& cert, bool hash, bool nowrap, const char* hashAlg) { string ret; @@ -584,6 +600,15 @@ string SecurityHelper::getDEREncoding(const XSECCryptoX509& cert, bool hash, boo return ret; } + const EVP_MD* md=NULL; + if (hash && hashAlg) { + md = EVP_get_digestbyname(hashAlg); + if (!md) { + Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").error("hash algorithm (%s) not available", hashAlg); + return ret; + } + } + const X509* x = static_cast(cert).getOpenSSLX509(); EVP_PKEY* key = X509_get_pubkey(const_cast(x)); @@ -592,18 +617,18 @@ string SecurityHelper::getDEREncoding(const XSECCryptoX509& cert, bool hash, boo if (nowrap) BIO_set_flags(b, BIO_FLAGS_BASE64_NO_NL); chain = BIO_push(b, chain); - if (hash) { + if (md) { b = BIO_new(BIO_f_md()); - BIO_set_md(b, EVP_sha1()); + BIO_set_md(b, md); chain = BIO_push(b, chain); } i2d_PUBKEY_bio(chain, key); EVP_PKEY_free(key); BIO_flush(chain); - if (hash) { - char digest[20]; - int len = BIO_gets(chain, digest, sizeof(digest)); - if (len != sizeof(digest)) { + 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; } @@ -622,12 +647,12 @@ string SecurityHelper::getDEREncoding(const XSECCryptoX509& cert, bool hash, boo return ret; } -string SecurityHelper::getDEREncoding(const Credential& cred, bool hash, bool nowrap) +string SecurityHelper::getDEREncoding(const Credential& cred, bool hash, bool nowrap, const char* hashAlg) { const X509Credential* x509 = dynamic_cast(&cred); if (x509 && !x509->getEntityCertificateChain().empty()) - return getDEREncoding(*(x509->getEntityCertificateChain().front()), hash, nowrap); + return getDEREncoding(*(x509->getEntityCertificateChain().front()), hash, nowrap, hashAlg); else if (cred.getPublicKey()) - return getDEREncoding(*(cred.getPublicKey()), hash, nowrap); + return getDEREncoding(*(cred.getPublicKey()), hash, nowrap, hashAlg); return ""; } diff --git a/xmltoolingtest/SecurityHelperTest.h b/xmltoolingtest/SecurityHelperTest.h index e5812a6..3b7640c 100644 --- a/xmltoolingtest/SecurityHelperTest.h +++ b/xmltoolingtest/SecurityHelperTest.h @@ -96,6 +96,11 @@ public: SecurityHelper::getDEREncoding(*certs[2], true), SecurityHelper::getDEREncoding(*key1.get(), true) ); + TSM_ASSERT_EQUALS( + "Certificate and its key produced different hashed encodings", + SecurityHelper::getDEREncoding(*certs[2], true, true, "SHA256"), SecurityHelper::getDEREncoding(*key1.get(), true, true, "SHA256") + ); + for_each(certs.begin(), certs.end(), xmltooling::cleanup()); certs.clear(); } -- 2.1.4