Support alternate hash algorithms in helper routines.
[shibboleth/cpp-xmltooling.git] / xmltooling / security / impl / SecurityHelper.cpp
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 "";
 }