From: Scott Cantor Date: Tue, 15 Jul 2008 20:09:17 +0000 (+0000) Subject: https://issues.shibboleth.net/jira/browse/CPPXT-14 X-Git-Tag: 1.1.0~5 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=shibboleth%2Fcpp-xmltooling.git;a=commitdiff_plain;h=b781ca58b067c66b7b1d04bf627c3ac409f44c0f https://issues.shibboleth.net/jira/browse/CPPXT-14 --- diff --git a/xmltooling/security/BasicX509Credential.h b/xmltooling/security/BasicX509Credential.h index e33e785..9241fd0 100644 --- a/xmltooling/security/BasicX509Credential.h +++ b/xmltooling/security/BasicX509Credential.h @@ -87,8 +87,10 @@ namespace xmltooling { /** * Initializes (or reinitializes) a ds:KeyInfo to represent the Credential. + * + * @param types the kinds of KeyInfo content to include */ - void initKeyInfo(); + void initKeyInfo(unsigned int types=0); public: virtual ~BasicX509Credential(); diff --git a/xmltooling/security/Credential.h b/xmltooling/security/Credential.h index 02d4999..ecd575a 100644 --- a/xmltooling/security/Credential.h +++ b/xmltooling/security/Credential.h @@ -1,6 +1,6 @@ /* * Copyright 2001-2007 Internet2 - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -16,8 +16,8 @@ /** * @file xmltooling/security/Credential.h - * - * Wraps keys and related functionality. + * + * Wraps keys and related functionality. */ #if !defined(__xmltooling_cred_h__) && !defined(XMLTOOLING_NO_XMLSEC) @@ -49,12 +49,12 @@ namespace xmltooling { MAKE_NONCOPYABLE(Credential); protected: Credential() {} - + public: virtual ~Credential() {} - + /** - * Bitmask constants for limiting resolution process inside a CredentialResolver. + * Bitmask constants for limiting resolution process inside a CredentialResolver. */ enum ResolveTypes { RESOLVE_KEYS = 1, @@ -62,7 +62,7 @@ namespace xmltooling { }; /** - * Bitmask of use cases for credentials. + * Bitmask of use cases for credentials. */ enum UsageTypes { UNSPECIFIED_CREDENTIAL = 0, @@ -70,10 +70,18 @@ namespace xmltooling { TLS_CREDENTIAL = 2, ENCRYPTION_CREDENTIAL = 4 }; - + + /** + * Bitmask of supported KeyInfo content to generate. + */ + enum KeyInfoTypes { + KEYINFO_KEY_VALUE = 1, + KEYINFO_KEY_NAME = 2 + }; + /** * Get credential usage types. - * + * * @return the usage bitmask */ virtual unsigned int getUsage() const=0; @@ -94,32 +102,32 @@ namespace xmltooling { /** * Returns a secret or private key to use for signing or decryption operations. - * + * * @return a secret or private key */ virtual XSECCryptoKey* getPrivateKey() const=0; /** * Returns a secret or public key to use for verification or encryption operations. - * + * * @return a secret or public key */ virtual XSECCryptoKey* getPublicKey() const=0; - + /** * Returns names representing the Credential. * *

Names should be unique in the context of the comparisons against CredentialCriteria * that deployments expect to see. - * + * * @return a sorted set of names */ virtual const std::set& getKeyNames() const=0; - + /** * Returns a ds:KeyInfo object representing the Credential for use in * communicating with other entities. - * + * * @param compact true iff the communication medium is such that only compact forms should be included * @return a KeyInfo object, which must be freed by the caller */ @@ -128,7 +136,7 @@ namespace xmltooling { /** * Get the credential context information, which provides additional information * specific to the context in which the credential was resolved. - * + * * @return resolution context of the credential */ virtual const CredentialContext* getCredentalContext() const { diff --git a/xmltooling/security/X509Credential.h b/xmltooling/security/X509Credential.h index a4d6e69..59dcd07 100644 --- a/xmltooling/security/X509Credential.h +++ b/xmltooling/security/X509Credential.h @@ -50,6 +50,15 @@ namespace xmltooling { }; /** + * Bitmask of supported KeyInfo content to generate. + */ + enum KeyInfoTypes { + KEYINFO_X509_CERTIFICATE = 4, + KEYINFO_X509_SUBJECTNAME = 8, + KEYINFO_X509_ISSUERSERIAL = 16 + }; + + /** * Gets an immutable collection of certificates in the entity's trust chain. The entity certificate is contained * within this list. No specific ordering of the certificates is guaranteed. * diff --git a/xmltooling/security/impl/BasicX509Credential.cpp b/xmltooling/security/impl/BasicX509Credential.cpp index b9678ff..50da3ed 100644 --- a/xmltooling/security/impl/BasicX509Credential.cpp +++ b/xmltooling/security/impl/BasicX509Credential.cpp @@ -1,6 +1,6 @@ /* * Copyright 2001-2007 Internet2 - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -16,8 +16,8 @@ /** * BasicX509Credential.cpp - * - * Wraps an X.509-based Credential by storing key/cert objects inside. + * + * Wraps an X.509-based Credential by storing key/cert objects inside. */ #include "internal.h" @@ -42,56 +42,61 @@ BasicX509Credential::~BasicX509Credential() delete m_compactKeyInfo; } -void BasicX509Credential::initKeyInfo() +void BasicX509Credential::initKeyInfo(unsigned int types) { delete m_keyInfo; m_keyInfo = NULL; delete m_compactKeyInfo; m_compactKeyInfo = NULL; - const set& names = getKeyNames(); - if (!names.empty()) { - m_compactKeyInfo = KeyInfoBuilder::buildKeyInfo(); - VectorOf(KeyName) knames = m_compactKeyInfo->getKeyNames(); - for (set::const_iterator n = names.begin(); n!=names.end(); ++n) { - if (*n == m_subjectName) - continue; - auto_ptr_XMLCh wide(n->c_str()); - KeyName* kname = KeyNameBuilder::buildKeyName(); - kname->setName(wide.get()); - knames.push_back(kname); - } - } + if (types == 0) + types = KEYINFO_KEY_VALUE | KEYINFO_KEY_NAME | KEYINFO_X509_CERTIFICATE | KEYINFO_X509_SUBJECTNAME | KEYINFO_X509_ISSUERSERIAL; -// if (!m_subjectName.empty() || (!m_issuerName.empty() && !m_serial.empty())) { - if (!m_subjectName.empty()) { - if (!m_compactKeyInfo) + if (types & KEYINFO_KEY_NAME) { + const set& names = getKeyNames(); + if (!names.empty()) { m_compactKeyInfo = KeyInfoBuilder::buildKeyInfo(); - X509Data* x509Data=X509DataBuilder::buildX509Data(); - m_compactKeyInfo->getX509Datas().push_back(x509Data); - if (!m_subjectName.empty()) { - X509SubjectName* sn = X509SubjectNameBuilder::buildX509SubjectName(); - auto_ptr_XMLCh wide(m_subjectName.c_str()); - sn->setName(wide.get()); - x509Data->getX509SubjectNames().push_back(sn); + VectorOf(KeyName) knames = m_compactKeyInfo->getKeyNames(); + for (set::const_iterator n = names.begin(); n!=names.end(); ++n) { + if (*n == m_subjectName) + continue; + auto_ptr_XMLCh wide(n->c_str()); + KeyName* kname = KeyNameBuilder::buildKeyName(); + kname->setName(wide.get()); + knames.push_back(kname); + } } -/* - if (!m_issuerName.empty() && !m_serial.empty()) { - X509IssuerSerial* is = X509IssuerSerialBuilder::buildX509IssuerSerial(); - X509IssuerName* in = X509IssuerNameBuilder::buildX509IssuerName(); - auto_ptr_XMLCh wide(m_issuerName.c_str()); - in->setName(wide.get()); - is->setX509IssuerName(in); - X509SerialNumber* ser = X509SerialNumberBuilder::buildX509SerialNumber(); - auto_ptr_XMLCh wide2(m_serial.c_str()); - ser->setSerialNumber(wide2.get()); - is->setX509SerialNumber(ser); - x509Data->getX509IssuerSerials().push_back(is); + } + + if (types & KEYINFO_X509_SUBJECTNAME || types & KEYINFO_X509_ISSUERSERIAL) { + if (!m_subjectName.empty() || (!m_issuerName.empty() && !m_serial.empty())) { + if (!m_compactKeyInfo) + m_compactKeyInfo = KeyInfoBuilder::buildKeyInfo(); + X509Data* x509Data=X509DataBuilder::buildX509Data(); + m_compactKeyInfo->getX509Datas().push_back(x509Data); + if (types & KEYINFO_X509_SUBJECTNAME && !m_subjectName.empty()) { + X509SubjectName* sn = X509SubjectNameBuilder::buildX509SubjectName(); + auto_ptr_XMLCh wide(m_subjectName.c_str()); + sn->setName(wide.get()); + x509Data->getX509SubjectNames().push_back(sn); + } + + if (types & KEYINFO_X509_ISSUERSERIAL && !m_issuerName.empty() && !m_serial.empty()) { + X509IssuerSerial* is = X509IssuerSerialBuilder::buildX509IssuerSerial(); + X509IssuerName* in = X509IssuerNameBuilder::buildX509IssuerName(); + auto_ptr_XMLCh wide(m_issuerName.c_str()); + in->setName(wide.get()); + is->setX509IssuerName(in); + X509SerialNumber* ser = X509SerialNumberBuilder::buildX509SerialNumber(); + auto_ptr_XMLCh wide2(m_serial.c_str()); + ser->setSerialNumber(wide2.get()); + is->setX509SerialNumber(ser); + x509Data->getX509IssuerSerials().push_back(is); + } } -*/ } - - if (!m_xseccerts.empty()) { + + if (types & KEYINFO_X509_CERTIFICATE && !m_xseccerts.empty()) { m_keyInfo = m_compactKeyInfo ? m_compactKeyInfo->cloneKeyInfo() : KeyInfoBuilder::buildKeyInfo(); if (m_keyInfo->getX509Datas().empty()) m_keyInfo->getX509Datas().push_back(X509DataBuilder::buildX509Data()); @@ -142,7 +147,7 @@ void BasicX509Credential::extract() } BN_free(serialBN); } - + X509_NAME* subject=X509_get_subject_name(cert); if (subject) { memset(buf,0,sizeof(buf)); @@ -196,7 +201,7 @@ const char* BasicX509Credential::getAlgorithm() const case XSECCryptoKey::KEY_DSA_PUBLIC: case XSECCryptoKey::KEY_DSA_PAIR: return "DSA"; - + case XSECCryptoKey::KEY_HMAC: return "HMAC"; diff --git a/xmltooling/security/impl/FilesystemCredentialResolver.cpp b/xmltooling/security/impl/FilesystemCredentialResolver.cpp index 7089d2f..b36eef0 100644 --- a/xmltooling/security/impl/FilesystemCredentialResolver.cpp +++ b/xmltooling/security/impl/FilesystemCredentialResolver.cpp @@ -1,6 +1,6 @@ /* * Copyright 2001-2007 Internet2 - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -16,7 +16,7 @@ /** * FilesystemCredentialResolver.cpp - * + * * Supplies credentials from local files */ @@ -55,7 +55,7 @@ static int passwd_callback(char* buf, int len, int verify, void* passwd) strcpy(buf,reinterpret_cast(passwd)); return strlen(buf); } - } + } return 0; } @@ -95,13 +95,13 @@ namespace xmltooling { } void addKeyNames(const DOMElement* e); - - void initKeyInfo() { - BasicX509Credential::initKeyInfo(); + + void initKeyInfo(unsigned int types=0) { + BasicX509Credential::initKeyInfo(types); } void attach(SSL_CTX* ctx) const; - + private: FilesystemCredentialResolver* m_resolver; unsigned int m_usage; @@ -122,7 +122,7 @@ namespace xmltooling { Lockable* lock() { return this; } void unlock() {} - + const Credential* resolve(const CredentialCriteria* criteria=NULL) const { return (criteria ? (criteria->matches(*m_credential) ? m_credential : NULL) : m_credential); } @@ -142,13 +142,13 @@ namespace xmltooling { private: XSECCryptoKey* loadKey(); XSECCryptoX509CRL* loadCRL(); - + enum format_t { PEM=SSL_FILETYPE_PEM, DER=SSL_FILETYPE_ASN1, _PKCS12, UNKNOWN }; - + format_t getEncodingFormat(BIO* in) const; string formatToString(format_t format) const; format_t xmlFormatToFormat(const XMLCh* format_xml) const; - + format_t m_keyformat,m_crlformat; string m_keypath,m_keypass,m_crlpath; vector m_certs; @@ -168,6 +168,7 @@ namespace xmltooling { static const XMLCh format[] = UNICODE_LITERAL_6(f,o,r,m,a,t); static const XMLCh Key[] = UNICODE_LITERAL_3(K,e,y); static const XMLCh _key[] = UNICODE_LITERAL_3(k,e,y); + static const XMLCh keyInfoMask[] = UNICODE_LITERAL_11(k,e,y,I,n,f,o,M,a,s,k); static const XMLCh keyName[] = UNICODE_LITERAL_7(k,e,y,N,a,m,e); static const XMLCh Name[] = UNICODE_LITERAL_4(N,a,m,e); static const XMLCh password[] = UNICODE_LITERAL_8(p,a,s,s,w,o,r,d); @@ -182,6 +183,15 @@ FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e) #endif Category& log=Category::getInstance(XMLTOOLING_LOGCAT".CredentialResolver."FILESYSTEM_CREDENTIAL_RESOLVER); + // Default to disable X509IssuerSerial due to schema validation issues. + unsigned int mask = + Credential::KEYINFO_KEY_NAME | + Credential::KEYINFO_KEY_VALUE | + X509Credential::KEYINFO_X509_CERTIFICATE | + X509Credential::KEYINFO_X509_SUBJECTNAME; + if (e && e->hasAttributeNS(NULL,keyInfoMask)) + mask = XMLString::parseInt(e->getAttributeNS(NULL,keyInfoMask)); + if (e && (e->hasAttributeNS(NULL,_certificate) || e->hasAttributeNS(NULL,_key))) { // Dummy up a simple file resolver config using these attributes. DOMElement* dummy = e->getOwnerDocument()->createElementNS(NULL,_CredentialResolver); @@ -210,7 +220,7 @@ FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e) } e = dummy; // reset "root" to the dummy config element } - + const DOMElement* root=e; const XMLCh* usage = root->getAttributeNS(NULL,_use); @@ -221,20 +231,20 @@ FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e) format_t fformat; const XMLCh* format_xml=NULL; BIO* in = NULL; - + // Move to Key const DOMElement* keynode=XMLHelper::getFirstChildElement(root,Key); if (keynode) { - // Get raw format attrib value, but defer processing til later since may need to + // Get raw format attrib value, but defer processing til later since may need to // determine format dynamically, and we need the Path for that. format_xml=keynode->getAttributeNS(NULL,format); - + const XMLCh* password_xml=keynode->getAttributeNS(NULL,password); if (password_xml) { auto_ptr_char kp(password_xml); m_keypass=kp.get(); } - + e=XMLHelper::getFirstChildElement(keynode,Path); if (e && e->hasChildNodes()) { const XMLCh* s=e->getFirstChild()->getNodeValue(); @@ -282,20 +292,20 @@ FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e) } if (in) BIO_free(in); - in = NULL; + in = NULL; } - + // Load the key. key = loadKey(); } - + // Check for CRL. const DOMElement* crlnode=XMLHelper::getFirstChildElement(root,CRL); if (crlnode) { - // Get raw format attrib value, but defer processing til later since may need to + // Get raw format attrib value, but defer processing til later since may need to // determine format dynamically, and we need the Path for that. format_xml=crlnode->getAttributeNS(NULL,format); - + e=XMLHelper::getFirstChildElement(crlnode,Path); if (e && e->hasChildNodes()) { const XMLCh* s=e->getFirstChild()->getNodeValue(); @@ -345,7 +355,7 @@ FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e) BIO_free(in); in = NULL; } - + // Load the key. crl = loadCRL(); } @@ -356,11 +366,11 @@ FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e) m_credential = new FilesystemCredential(this,key,xseccerts,crl); m_credential->addKeyNames(keynode); m_credential->setUsage(usage); - m_credential->initKeyInfo(); + m_credential->initKeyInfo(mask); return; } auto_ptr_char certpass(e->getAttributeNS(NULL,password)); - + const DOMElement* ep=XMLHelper::getFirstChildElement(e,Path); if (!ep || !ep->hasChildNodes()) { log.error("Path element missing inside Certificate element or is empty"); @@ -368,7 +378,7 @@ FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e) delete crl; throw XMLSecurityException("FilesystemCredentialResolver can't access certificate file, missing or empty Path element."); } - + auto_ptr_char certpath2(ep->getFirstChild()->getNodeValue()); string certpath(certpath2.get()); XMLToolingConfig::getConfig().getPathResolver()->resolve(certpath, PathResolver::XMLTOOLING_CFG_FILE); @@ -384,7 +394,7 @@ FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e) throw XMLSecurityException("FilesystemCredentialResolver configuration contains unknown certificate encoding format ($1)",params(1,unknown.get())); } } - + try { X509* x=NULL; PKCS12* p12=NULL; @@ -405,7 +415,7 @@ FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e) while (x=PEM_read_bio_X509(in,NULL,passwd_callback,const_cast(certpass.get()))) m_certs.push_back(x); break; - + case DER: x=d2i_X509_bio(in,NULL); if (x) @@ -519,7 +529,7 @@ FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e) log.error("CA certificate file (%s) can't be opened", capath.c_str()); throw XMLSecurityException("FilesystemCredentialResolver can't open CA certificate file ($1)",params(1,capath.c_str())); } - + extra = XMLHelper::getNextSiblingElement(extra,CAPath); } } @@ -538,7 +548,7 @@ FilesystemCredentialResolver::FilesystemCredentialResolver(const DOMElement* e) m_credential = new FilesystemCredential(this, key, xseccerts, crl); m_credential->addKeyNames(keynode); m_credential->setUsage(usage); - m_credential->initKeyInfo(); + m_credential->initKeyInfo(mask); } XSECCryptoKey* FilesystemCredentialResolver::loadKey() @@ -558,11 +568,11 @@ XSECCryptoKey* FilesystemCredentialResolver::loadKey() case PEM: pkey=PEM_read_bio_PrivateKey(in, NULL, passwd_callback, const_cast(m_keypass.c_str())); break; - + case DER: pkey=d2i_PrivateKey_bio(in, NULL); break; - + default: { PKCS12* p12 = d2i_PKCS12_bio(in, NULL); if (p12) { @@ -574,7 +584,7 @@ XSECCryptoKey* FilesystemCredentialResolver::loadKey() } if (in) BIO_free(in); - + // Now map it to an XSEC wrapper. if (pkey) { XSECCryptoKey* ret=NULL; @@ -582,11 +592,11 @@ XSECCryptoKey* FilesystemCredentialResolver::loadKey() case EVP_PKEY_RSA: ret=new OpenSSLCryptoKeyRSA(pkey); break; - + case EVP_PKEY_DSA: ret=new OpenSSLCryptoKeyDSA(pkey); break; - + default: Category::getInstance(XMLTOOLING_LOGCAT".CredentialResolver."FILESYSTEM_CREDENTIAL_RESOLVER).error("unsupported private key type"); } @@ -596,7 +606,7 @@ XSECCryptoKey* FilesystemCredentialResolver::loadKey() } log_openssl(); - throw XMLSecurityException("FilesystemCredentialResolver unable to load private key from file."); + throw XMLSecurityException("FilesystemCredentialResolver unable to load private key from file."); } XSECCryptoX509CRL* FilesystemCredentialResolver::loadCRL() @@ -615,7 +625,7 @@ XSECCryptoX509CRL* FilesystemCredentialResolver::loadCRL() case PEM: crl=PEM_read_bio_X509_CRL(in, NULL, NULL, NULL); break; - + case DER: crl=d2i_X509_CRL_bio(in, NULL); break; @@ -623,7 +633,7 @@ XSECCryptoX509CRL* FilesystemCredentialResolver::loadCRL() } if (in) BIO_free(in); - + // Now map it to an XSEC wrapper. if (crl) { XSECCryptoX509CRL* ret=new OpenSSLCryptoX509CRL(crl); @@ -632,7 +642,7 @@ XSECCryptoX509CRL* FilesystemCredentialResolver::loadCRL() } log_openssl(); - throw XMLSecurityException("FilesystemCredentialResolver unable to load CRL from file."); + throw XMLSecurityException("FilesystemCredentialResolver unable to load CRL from file."); } // Used to determine the encoding format of credentials files @@ -648,11 +658,11 @@ FilesystemCredentialResolver::format_t FilesystemCredentialResolver::getEncoding int mark; try { - if ( (mark = BIO_tell(in)) < 0 ) + if ( (mark = BIO_tell(in)) < 0 ) throw XMLSecurityException("getEncodingFormat: BIO_tell() can't get the file position"); - if ( BIO_read(in, buf, READSIZE) <= 0 ) + if ( BIO_read(in, buf, READSIZE) <= 0 ) throw XMLSecurityException("getEncodingFormat: BIO_read() can't read from the stream"); - if ( BIO_seek(in, mark) < 0 ) + if ( BIO_seek(in, mark) < 0 ) throw XMLSecurityException("getEncodingFormat: BIO_seek() can't reset the file position"); } catch (...) { @@ -679,7 +689,7 @@ FilesystemCredentialResolver::format_t FilesystemCredentialResolver::getEncoding format = _PKCS12; } if (p12) - PKCS12_free(p12); + PKCS12_free(p12); if ( BIO_seek(in, mark) < 0 ) { log_openssl(); throw XMLSecurityException("getEncodingFormat: BIO_seek() can't reset the file position"); @@ -742,11 +752,11 @@ void FilesystemCredentialResolver::attach(SSL_CTX* ctx) const case PEM: ret=SSL_CTX_use_PrivateKey_file(ctx, m_keypath.c_str(), m_keyformat); break; - + case DER: ret=SSL_CTX_use_RSAPrivateKey_file(ctx, m_keypath.c_str(), m_keyformat); break; - + default: { BIO* in=BIO_new(BIO_s_file_internal()); if (in && BIO_read_filename(in,m_keypath.c_str())>0) { @@ -765,7 +775,7 @@ void FilesystemCredentialResolver::attach(SSL_CTX* ctx) const BIO_free(in); } } - + if (ret!=1) { log_openssl(); throw XMLSecurityException("Unable to attach private key to SSL context.");