X-Git-Url: http://www.project-moonshot.org/gitweb/?p=shibboleth%2Fcpp-xmltooling.git;a=blobdiff_plain;f=xmltooling%2Fsecurity%2Fimpl%2FSecurityHelper.cpp;h=ebcc37c4496b2da84ded958481aa4fff19a03cec;hp=0ee81ab1226a5995361eac064153eca4e70c5768;hb=2b4a6cd70522f955d101f73a08fe3d685b7877c5;hpb=18296076c28faadea55aec9384967574bb485b99 diff --git a/xmltooling/security/impl/SecurityHelper.cpp b/xmltooling/security/impl/SecurityHelper.cpp index 0ee81ab..ebcc37c 100644 --- a/xmltooling/security/impl/SecurityHelper.cpp +++ b/xmltooling/security/impl/SecurityHelper.cpp @@ -24,6 +24,7 @@ #include "logging.h" #include "security/OpenSSLCryptoX509CRL.h" #include "security/SecurityHelper.h" +#include "security/X509Credential.h" #include "util/NDC.h" #include @@ -435,90 +436,138 @@ vector::size_type SecurityHelper::loadCRLsFromURL( return loadCRLsFromFile(crls, backing, format); } -bool SecurityHelper::matches(const XSECCryptoKey* key1, const XSECCryptoKey* key2) +bool SecurityHelper::matches(const XSECCryptoKey& key1, const XSECCryptoKey& key2) { - if (key1->getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL || - key2->getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL) { + if (key1.getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL || + key2.getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL) { Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("comparison of non-OpenSSL keys not supported"); return false; } // If one key is public or both, just compare the public key half. - if (key1->getKeyType()==XSECCryptoKey::KEY_RSA_PUBLIC || key1->getKeyType()==XSECCryptoKey::KEY_RSA_PAIR) { - if (key2->getKeyType()!=XSECCryptoKey::KEY_RSA_PUBLIC && key2->getKeyType()!=XSECCryptoKey::KEY_RSA_PAIR) + if (key1.getKeyType()==XSECCryptoKey::KEY_RSA_PUBLIC || key1.getKeyType()==XSECCryptoKey::KEY_RSA_PAIR) { + if (key2.getKeyType()!=XSECCryptoKey::KEY_RSA_PUBLIC && key2.getKeyType()!=XSECCryptoKey::KEY_RSA_PAIR) return false; - const RSA* rsa1 = static_cast(key1)->getOpenSSLRSA(); - const RSA* rsa2 = static_cast(key2)->getOpenSSLRSA(); - return (BN_cmp(rsa1->n,rsa2->n) == 0 && BN_cmp(rsa1->e,rsa2->e) == 0); + const RSA* rsa1 = static_cast(key1).getOpenSSLRSA(); + const RSA* rsa2 = static_cast(key2).getOpenSSLRSA(); + return (rsa1 && rsa2 && BN_cmp(rsa1->n,rsa2->n) == 0 && BN_cmp(rsa1->e,rsa2->e) == 0); } // For a private key, compare the private half. - if (key1->getKeyType()==XSECCryptoKey::KEY_RSA_PRIVATE) { - if (key2->getKeyType()!=XSECCryptoKey::KEY_RSA_PRIVATE && key2->getKeyType()!=XSECCryptoKey::KEY_RSA_PAIR) + if (key1.getKeyType()==XSECCryptoKey::KEY_RSA_PRIVATE) { + if (key2.getKeyType()!=XSECCryptoKey::KEY_RSA_PRIVATE && key2.getKeyType()!=XSECCryptoKey::KEY_RSA_PAIR) return false; - const RSA* rsa1 = static_cast(key1)->getOpenSSLRSA(); - const RSA* rsa2 = static_cast(key2)->getOpenSSLRSA(); - return (BN_cmp(rsa1->n,rsa2->n) == 0 && BN_cmp(rsa1->d,rsa2->d) == 0); + const RSA* rsa1 = static_cast(key1).getOpenSSLRSA(); + const RSA* rsa2 = static_cast(key2).getOpenSSLRSA(); + return (rsa1 && rsa2 && BN_cmp(rsa1->n,rsa2->n) == 0 && BN_cmp(rsa1->d,rsa2->d) == 0); } // If one key is public or both, just compare the public key half. - if (key1->getKeyType()==XSECCryptoKey::KEY_DSA_PUBLIC || key1->getKeyType()==XSECCryptoKey::KEY_DSA_PAIR) { - if (key2->getKeyType()!=XSECCryptoKey::KEY_DSA_PUBLIC && key2->getKeyType()!=XSECCryptoKey::KEY_DSA_PAIR) + if (key1.getKeyType()==XSECCryptoKey::KEY_DSA_PUBLIC || key1.getKeyType()==XSECCryptoKey::KEY_DSA_PAIR) { + if (key2.getKeyType()!=XSECCryptoKey::KEY_DSA_PUBLIC && key2.getKeyType()!=XSECCryptoKey::KEY_DSA_PAIR) return false; - const DSA* dsa1 = static_cast(key1)->getOpenSSLDSA(); - const DSA* dsa2 = static_cast(key2)->getOpenSSLDSA(); - return (BN_cmp(dsa1->pub_key,dsa2->pub_key) == 0); + const DSA* dsa1 = static_cast(key1).getOpenSSLDSA(); + const DSA* dsa2 = static_cast(key2).getOpenSSLDSA(); + return (dsa1 && dsa2 && BN_cmp(dsa1->pub_key,dsa2->pub_key) == 0); } // For a private key, compare the private half. - if (key1->getKeyType()==XSECCryptoKey::KEY_DSA_PRIVATE) { - if (key2->getKeyType()!=XSECCryptoKey::KEY_DSA_PRIVATE && key2->getKeyType()!=XSECCryptoKey::KEY_DSA_PAIR) + if (key1.getKeyType()==XSECCryptoKey::KEY_DSA_PRIVATE) { + if (key2.getKeyType()!=XSECCryptoKey::KEY_DSA_PRIVATE && key2.getKeyType()!=XSECCryptoKey::KEY_DSA_PAIR) return false; - const DSA* dsa1 = static_cast(key1)->getOpenSSLDSA(); - const DSA* dsa2 = static_cast(key2)->getOpenSSLDSA(); - return (BN_cmp(dsa1->priv_key,dsa2->priv_key) == 0); + const DSA* dsa1 = static_cast(key1).getOpenSSLDSA(); + const DSA* dsa2 = static_cast(key2).getOpenSSLDSA(); + return (dsa1 && dsa2 && BN_cmp(dsa1->priv_key,dsa2->priv_key) == 0); } Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("unsupported key type for comparison"); return false; } -string SecurityHelper::getDEREncoding(const XSECCryptoKey* key) +string SecurityHelper::getDEREncoding(const XSECCryptoKey& key, bool hash, bool nowrap) { string ret; - if (key->getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL) { + if (key.getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL) { Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("encoding of non-OpenSSL keys not supported"); return ret; } - if (key->getKeyType() == XSECCryptoKey::KEY_RSA_PUBLIC || key->getKeyType() == XSECCryptoKey::KEY_RSA_PAIR) { - const RSA* rsa = static_cast(key)->getOpenSSLRSA(); - BIO* base64 = BIO_new(BIO_f_base64()); - 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); + if (key.getKeyType() == XSECCryptoKey::KEY_RSA_PUBLIC || key.getKeyType() == XSECCryptoKey::KEY_RSA_PAIR) { + const RSA* rsa = static_cast(key).getOpenSSLRSA(); + if (!rsa) { + Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("key was not populated"); + 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) { + 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(); - BIO* base64 = BIO_new(BIO_f_base64()); - 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); + else if (key.getKeyType() == XSECCryptoKey::KEY_DSA_PUBLIC || key.getKeyType() == XSECCryptoKey::KEY_DSA_PAIR) { + const DSA* dsa = static_cast(key).getOpenSSLDSA(); + if (!dsa) { + Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("key was not populated"); + 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) { + 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"); @@ -526,29 +575,59 @@ string SecurityHelper::getDEREncoding(const XSECCryptoKey* key) return ret; } -string SecurityHelper::getDEREncoding(const XSECCryptoX509* cert) +string SecurityHelper::getDEREncoding(const XSECCryptoX509& cert, bool hash, bool nowrap) { string ret; - if (cert->getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL) { + if (cert.getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL) { Category::getInstance(XMLTOOLING_LOGCAT".SecurityHelper").warn("encoding of non-OpenSSL keys not supported"); return ret; } - const X509* x = static_cast(cert)->getOpenSSLX509(); + const X509* x = static_cast(cert).getOpenSSLX509(); EVP_PKEY* key = X509_get_pubkey(const_cast(x)); - BIO* base64 = BIO_new(BIO_f_base64()); - 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* 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) { + 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 hash, bool nowrap) +{ + const X509Credential* x509 = dynamic_cast(&cred); + if (x509 && !x509->getEntityCertificateChain().empty()) + return getDEREncoding(*(x509->getEntityCertificateChain().front()), hash, nowrap); + else if (cred.getPublicKey()) + return getDEREncoding(*(cred.getPublicKey()), hash, nowrap); + return ""; +}