Add hashing options to key extraction support.
authorScott Cantor <cantor.2@osu.edu>
Thu, 4 Jun 2009 03:28:55 +0000 (03:28 +0000)
committerScott Cantor <cantor.2@osu.edu>
Thu, 4 Jun 2009 03:28:55 +0000 (03:28 +0000)
xmltooling/XMLToolingConfig.cpp
xmltooling/security/SecurityHelper.h
xmltooling/security/impl/SecurityHelper.cpp
xmltoolingtest/SecurityHelperTest.h

index 506e5be..9773dcd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright 2001-2007 Internet2
+ *  Copyright 2001-2009 Internet2
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -534,7 +534,7 @@ void XMLToolingInternalConfig::registerXMLAlgorithms()
 
 extern "C" __declspec(dllexport) BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID)
 {
-    if (fdwReason == DLL_THREAD_DETACH)
+    if (fdwReason == DLL_THREAD_DETACH || fdwReason == DLL_PROCESS_DETACH)
         ThreadKey::onDetach();
     return TRUE;
 }
index e09e139..0f0207d 100644 (file)
@@ -130,29 +130,32 @@ namespace xmltooling {
         /**
          * Returns the base64-encoded DER encoding of a public key in SubjectPublicKeyInfo format.
          *
-         * @param key       the credential containing the key to encode
+         * @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
          * @return  the base64 encoded key value
          */
-        static std::string getDEREncoding(const Credential& cred, bool nowrap=true);
+        static std::string getDEREncoding(const Credential& cred, bool hash=false, bool nowrap=true);
 
         /**
          * Returns the base64-encoded DER encoding of a public key in SubjectPublicKeyInfo format.
          *
-         * @param key   the key to encode
+         * @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
          * @return  the base64 encoded key value
          */
-        static std::string getDEREncoding(const XSECCryptoKey& key, bool nowrap=true);
+        static std::string getDEREncoding(const XSECCryptoKey& key, bool hash=false, bool nowrap=true);
 
         /**
          * Returns the base64-encoded DER encoding of a certifiate's public key in SubjectPublicKeyInfo format.
          *
-         * @param cert   the certificate's key to encode
+         * @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
          * @return  the base64 encoded key value
          */
-        static std::string getDEREncoding(const XSECCryptoX509& cert, bool nowrap=true);
+        static std::string getDEREncoding(const XSECCryptoX509& cert, bool hash=false, bool nowrap=true);
     };
 };
 
index 6370079..ebcc37c 100644 (file)
@@ -484,7 +484,7 @@ bool SecurityHelper::matches(const XSECCryptoKey& key1, const XSECCryptoKey& key
     return false;
 }
 
-string SecurityHelper::getDEREncoding(const XSECCryptoKey& key, bool nowrap)
+string SecurityHelper::getDEREncoding(const XSECCryptoKey& key, bool hash, bool nowrap)
 {
     string ret;
 
@@ -499,18 +499,37 @@ string SecurityHelper::getDEREncoding(const XSECCryptoKey& key, bool nowrap)
             Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("key was not populated");
             return ret;
         }
-        BIO* base64 = BIO_new(BIO_f_base64());
+        BIO* chain = BIO_new(BIO_s_mem());
+        BIO* b = BIO_new(BIO_f_base64());
         if (nowrap)
-            BIO_set_flags(base64, BIO_FLAGS_BASE64_NO_NL);
-        BIO* mem = BIO_new(BIO_s_mem());
-        BIO_push(base64, mem);
-        i2d_RSA_PUBKEY_bio(base64, const_cast<RSA*>(rsa));
-        BIO_flush(base64);
+            BIO_set_flags(b, BIO_FLAGS_BASE64_NO_NL);
+        chain = BIO_push(b, chain);
+        if (hash) {
+            b = BIO_new(BIO_f_md());
+            BIO_set_md(b, EVP_sha1());
+            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)) {
+                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=NULL;
-        BIO_get_mem_ptr(base64, &bptr);
+        BIO_get_mem_ptr(chain, &bptr);
         if (bptr && bptr->length > 0)
             ret.append(bptr->data, bptr->length);
-        BIO_free_all(base64);
+        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();
@@ -518,18 +537,37 @@ string SecurityHelper::getDEREncoding(const XSECCryptoKey& key, bool nowrap)
             Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("key was not populated");
             return ret;
         }
-        BIO* base64 = BIO_new(BIO_f_base64());
+        BIO* chain = BIO_new(BIO_s_mem());
+        BIO* b = BIO_new(BIO_f_base64());
         if (nowrap)
-            BIO_set_flags(base64, BIO_FLAGS_BASE64_NO_NL);
-        BIO* mem = BIO_new(BIO_s_mem());
-        BIO_push(base64, mem);
-        i2d_DSA_PUBKEY_bio(base64, const_cast<DSA*>(dsa));
-        BIO_flush(base64);
+            BIO_set_flags(b, BIO_FLAGS_BASE64_NO_NL);
+        chain = BIO_push(b, chain);
+        if (hash) {
+            b = BIO_new(BIO_f_md());
+            BIO_set_md(b, EVP_sha1());
+            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)) {
+                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=NULL;
-        BIO_get_mem_ptr(base64, &bptr);
+        BIO_get_mem_ptr(chain, &bptr);
         if (bptr && bptr->length > 0)
             ret.append(bptr->data, bptr->length);
-        BIO_free_all(base64);
+        BIO_free_all(chain);
     }
     else {
         Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("encoding of non-RSA/DSA public keys not supported");
@@ -537,7 +575,7 @@ string SecurityHelper::getDEREncoding(const XSECCryptoKey& key, bool nowrap)
     return ret;
 }
 
-string SecurityHelper::getDEREncoding(const XSECCryptoX509& cert, bool nowrap)
+string SecurityHelper::getDEREncoding(const XSECCryptoX509& cert, bool hash, bool nowrap)
 {
     string ret;
 
@@ -549,28 +587,47 @@ string SecurityHelper::getDEREncoding(const XSECCryptoX509& cert, bool nowrap)
     const X509* x = static_cast<const OpenSSLCryptoX509&>(cert).getOpenSSLX509();
     EVP_PKEY* key = X509_get_pubkey(const_cast<X509*>(x));
 
-    BIO* base64 = BIO_new(BIO_f_base64());
+    BIO* chain = BIO_new(BIO_s_mem());
+    BIO* b = BIO_new(BIO_f_base64());
     if (nowrap)
-        BIO_set_flags(base64, BIO_FLAGS_BASE64_NO_NL);
-    BIO* mem = BIO_new(BIO_s_mem());
-    BIO_push(base64, mem);
-    i2d_PUBKEY_bio(base64, key);
+        BIO_set_flags(b, BIO_FLAGS_BASE64_NO_NL);
+    chain = BIO_push(b, chain);
+    if (hash) {
+        b = BIO_new(BIO_f_md());
+        BIO_set_md(b, EVP_sha1());
+        chain = BIO_push(b, chain);
+    }
+    i2d_PUBKEY_bio(chain, key);
     EVP_PKEY_free(key);
-    BIO_flush(base64);
+    BIO_flush(chain);
+    if (hash) {
+        char digest[20];
+        int len = BIO_gets(chain, digest, sizeof(digest));
+        if (len != sizeof(digest)) {
+            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=NULL;
-    BIO_get_mem_ptr(base64, &bptr);
+    BIO_get_mem_ptr(chain, &bptr);
     if (bptr && bptr->length > 0)
         ret.append(bptr->data, bptr->length);
-    BIO_free_all(base64);
+    BIO_free_all(chain);
     return ret;
 }
 
-string SecurityHelper::getDEREncoding(const Credential& cred, bool nowrap)
+string SecurityHelper::getDEREncoding(const Credential& cred, bool hash, bool nowrap)
 {
     const X509Credential* x509 = dynamic_cast<const X509Credential*>(&cred);
     if (x509 && !x509->getEntityCertificateChain().empty())
-        return getDEREncoding(*(x509->getEntityCertificateChain().front()), nowrap);
+        return getDEREncoding(*(x509->getEntityCertificateChain().front()), hash, nowrap);
     else if (cred.getPublicKey())
-        return getDEREncoding(*(cred.getPublicKey()), nowrap);
+        return getDEREncoding(*(cred.getPublicKey()), hash, nowrap);
     return "";
 }
index 70e451b..6d57690 100644 (file)
@@ -32,6 +32,7 @@ public:
 
     void tearDown() {
         for_each(certs.begin(), certs.end(), xmltooling::cleanup<XSECCryptoX509>());
+        certs.clear();
     }
 
     void testKeysFromFiles() {
@@ -87,6 +88,11 @@ public:
             SecurityHelper::getDEREncoding(*certs[2]), SecurityHelper::getDEREncoding(*key1.get())
             );
 
+        TSM_ASSERT_EQUALS(
+            "Certificate and its key produced different hashed encodings",
+            SecurityHelper::getDEREncoding(*certs[2], true), SecurityHelper::getDEREncoding(*key1.get(), true)
+            );
+
         for_each(certs.begin(), certs.end(), xmltooling::cleanup<XSECCryptoX509>());
         certs.clear();
     }