From 2b4a6cd70522f955d101f73a08fe3d685b7877c5 Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Thu, 4 Jun 2009 03:28:55 +0000 Subject: [PATCH] Add hashing options to key extraction support. --- xmltooling/XMLToolingConfig.cpp | 4 +- xmltooling/security/SecurityHelper.h | 15 ++-- xmltooling/security/impl/SecurityHelper.cpp | 115 +++++++++++++++++++++------- xmltoolingtest/SecurityHelperTest.h | 6 ++ 4 files changed, 103 insertions(+), 37 deletions(-) diff --git a/xmltooling/XMLToolingConfig.cpp b/xmltooling/XMLToolingConfig.cpp index 506e5be..9773dcd 100644 --- a/xmltooling/XMLToolingConfig.cpp +++ b/xmltooling/XMLToolingConfig.cpp @@ -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; } diff --git a/xmltooling/security/SecurityHelper.h b/xmltooling/security/SecurityHelper.h index e09e139..0f0207d 100644 --- a/xmltooling/security/SecurityHelper.h +++ b/xmltooling/security/SecurityHelper.h @@ -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); }; }; diff --git a/xmltooling/security/impl/SecurityHelper.cpp b/xmltooling/security/impl/SecurityHelper.cpp index 6370079..ebcc37c 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 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)); - 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)); + 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(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)); - 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)); + 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(cert).getOpenSSLX509(); EVP_PKEY* key = X509_get_pubkey(const_cast(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(&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 ""; } diff --git a/xmltoolingtest/SecurityHelperTest.h b/xmltoolingtest/SecurityHelperTest.h index 70e451b..6d57690 100644 --- a/xmltoolingtest/SecurityHelperTest.h +++ b/xmltoolingtest/SecurityHelperTest.h @@ -32,6 +32,7 @@ public: void tearDown() { for_each(certs.begin(), certs.end(), xmltooling::cleanup()); + 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()); certs.clear(); } -- 2.1.4