Support alternate hash algorithms in helper routines.
authorScott Cantor <cantor.2@osu.edu>
Mon, 2 Nov 2009 15:52:34 +0000 (15:52 +0000)
committerScott Cantor <cantor.2@osu.edu>
Mon, 2 Nov 2009 15:52:34 +0000 (15:52 +0000)
.cproject
xmltooling/security/SecurityHelper.h
xmltooling/security/impl/SecurityHelper.cpp
xmltoolingtest/SecurityHelperTest.h

index 703a661..34bcb9d 100644 (file)
--- a/.cproject
+++ b/.cproject
@@ -58,6 +58,7 @@
 <option id="org.eclipse.linuxtools.cdt.autotools.option.configure.symbols.461255076" name="symbols" superClass="org.eclipse.linuxtools.cdt.autotools.option.configure.symbols" valueType="definedSymbols">\r
 <listOptionValue builtIn="false" value="XMLTOOL_API"/>\r
 <listOptionValue builtIn="false" value="XMLTOOL_DLLLOCAL"/>\r
+<listOptionValue builtIn="false" value="XMLTOOLING_LOGCAT=&quot;XMLTooling&quot;"/>\r
 </option>\r
 <inputType id="org.eclipse.linuxtools.cdt.autotools.inputType.configure.387715961" superClass="org.eclipse.linuxtools.cdt.autotools.inputType.configure"/>\r
 <inputType id="org.eclipse.linuxtools.cdt.autotools.inputType.configure1.2086982536" superClass="org.eclipse.linuxtools.cdt.autotools.inputType.configure1"/>\r
index 7ad65d9..e6cbee3 100644 (file)
@@ -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");
     };
 };
 
index ebcc37c..ea69204 100644 (file)
@@ -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*>(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*>(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<const OpenSSLCryptoX509&>(cert).getOpenSSLX509();
     EVP_PKEY* key = X509_get_pubkey(const_cast<X509*>(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<const X509Credential*>(&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 "";
 }
index e5812a6..3b7640c 100644 (file)
@@ -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<XSECCryptoX509>());
         certs.clear();
     }