#include <xmltooling/security/OpenSSLTrustEngine.h>
#include <xmltooling/security/SignatureTrustEngine.h>
+#include <set>
#include <string>
namespace xmltooling {
*
* <ul>
* <li>checkRevocation attribute (off, entityOnly, fullChain)
+ * <li>policyMappingInhibit attribute (boolean)
+ * <li>anyPolicyInhibit attribute (boolean)
+ * <li><TrustedName> element (zero or more)
+ * <li><PolicyOID> element (zero or more)
* </ul>
*
* @param e DOM to supply configuration for provider
*/
AbstractPKIXTrustEngine(const xercesc::DOMElement* e=nullptr);
- /** Controls revocation checking, currently limited to CRLs and supports "off", "entityOnly", "fullChain". */
- std::string m_checkRevocation;
+ /** Controls revocation checking, currently limited to CRLs and supports "off", "entityOnly", "fullChain". */
+ std::string m_checkRevocation;
/** Deprecated option, equivalent to checkRevocation="fullChain". */
bool m_fullCRLChain;
-
+
+ /** Disable policy mapping when applying PKIX policy checking. */
+ bool m_policyMappingInhibit;
+
+ /** Disallow the anyPolicy OID (2.5.29.32.0) when applying PKIX policy checking. */
+ bool m_anyPolicyInhibit;
+
+ /** A list of acceptable policy OIDs (explicit policy checking). */
+ std::set<std::string> m_policyOIDs;
+
+ /** A list of trusted names (subject DNs / CN attributes / subjectAltName entries). */
+ std::set<std::string> m_trustedNames;
+
/**
* Checks that either the name of the peer with the given credentials or the names
* of the credentials match the subject or subject alternate names of the certificate.
+ * Alternatively explicit trusted names can be supplied statically via configuration.
*
* @param certEE the credential for the entity to validate
- * @param credResolver source of credentials
+ * @param credResolver source of trusted credentials
* @param criteria criteria for selecting credentials, including the peer name
*
* @return true the name check succeeds, false if not
X509* EE,
STACK_OF(X509)* untrusted,
AbstractPKIXTrustEngine::PKIXValidationInfoIterator* pkixInfo,
- bool useCRL,
+ bool useCRL,
bool fullCRLChain,
- const vector<XSECCryptoX509CRL*>* inlineCRLs=nullptr
+ const vector<XSECCryptoX509CRL*>* inlineCRLs=nullptr,
+ bool policyMappingInhibit=false,
+ bool anyPolicyInhibit=false,
+ const set<string>* policyOIDs=nullptr
)
{
Category& log=Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine");
log_openssl();
return false;
}
+
+ // PKIX policy checking (cf. RFCs 3280/5280 section 6)
+ if (policyMappingInhibit || anyPolicyInhibit || (policyOIDs && !policyOIDs->empty())) {
+#if (OPENSSL_VERSION_NUMBER < 0x00908000L)
+ log.error("PKIX policy checking option is configured, but OpenSSL version is less than 0.9.8");
+ X509_STORE_free(store);
+ return false;
+#else
+ unsigned long pflags = 0;
+ X509_VERIFY_PARAM *vpm = X509_VERIFY_PARAM_new();
+ if (!vpm) {
+ log_openssl();
+ X509_STORE_free(store);
+ return false;
+ }
+
+ // populate the "user-initial-policy-set" input variable
+ if (policyOIDs && !policyOIDs->empty()) {
+ for (set<string>::const_iterator o=policyOIDs->begin(); o!=policyOIDs->end(); o++) {
+ ASN1_OBJECT *oid = OBJ_txt2obj(o->c_str(), 1);
+ if (oid && X509_VERIFY_PARAM_add0_policy(vpm, oid)) {
+ log.debug("OID (%s) added to set of acceptable policies", o->c_str());
+ }
+ else {
+ log_openssl();
+ log.error("unable to parse/configure policy OID value (%s)", o->c_str());
+ if (oid)
+ ASN1_OBJECT_free(oid);
+ X509_VERIFY_PARAM_free(vpm);
+ X509_STORE_free(store);
+ return false;
+ }
+ }
+ // when the user has supplied at least one policy OID, he obviously wants to check
+ // for an explicit policy ("initial-explicit-policy")
+ pflags |= X509_V_FLAG_EXPLICIT_POLICY;
+ }
+
+ // "initial-policy-mapping-inhibit" input variable
+ if (policyMappingInhibit)
+ pflags |= X509_V_FLAG_INHIBIT_MAP;
+ // "initial-any-policy-inhibit" input variable
+ if (anyPolicyInhibit)
+ pflags |= X509_V_FLAG_INHIBIT_ANY;
+
+ if (!X509_VERIFY_PARAM_set_flags(vpm, pflags) || !X509_STORE_set1_param(store, vpm)) {
+ log_openssl();
+ log.error("unable to set PKIX policy checking parameters");
+ X509_VERIFY_PARAM_free(vpm);
+ X509_STORE_free(store);
+ return false;
+ }
+
+ X509_VERIFY_PARAM_free(vpm);
+#endif
+ }
// This contains the state of the validate operation.
int count=0;
return false;
}
- static XMLCh fullCRLChain[] = UNICODE_LITERAL_12(f,u,l,l,C,R,L,C,h,a,i,n);
- static XMLCh checkRevocation[] = UNICODE_LITERAL_15(c,h,e,c,k,R,e,v,o,c,a,t,i,o,n);
+ static XMLCh fullCRLChain[] = UNICODE_LITERAL_12(f,u,l,l,C,R,L,C,h,a,i,n);
+ static XMLCh checkRevocation[] = UNICODE_LITERAL_15(c,h,e,c,k,R,e,v,o,c,a,t,i,o,n);
+ static XMLCh policyMappingInhibit[] = UNICODE_LITERAL_20(p,o,l,i,c,y,M,a,p,p,i,n,g,I,n,h,i,b,i,t);
+ static XMLCh anyPolicyInhibit[] = UNICODE_LITERAL_16(a,n,y,P,o,l,i,c,y,I,n,h,i,b,i,t);
+ static XMLCh PolicyOID[] = UNICODE_LITERAL_9(P,o,l,i,c,y,O,I,D);
+ static XMLCh TrustedName[] = UNICODE_LITERAL_11(T,r,u,s,t,e,d,N,a,m,e);
};
AbstractPKIXTrustEngine::PKIXValidationInfoIterator::PKIXValidationInfoIterator()
AbstractPKIXTrustEngine::AbstractPKIXTrustEngine(const xercesc::DOMElement* e)
: TrustEngine(e),
+ m_checkRevocation(XMLHelper::getAttrString(e, nullptr, checkRevocation)),
m_fullCRLChain(XMLHelper::getAttrBool(e, false, fullCRLChain)),
- m_checkRevocation(XMLHelper::getAttrString(e, nullptr, checkRevocation))
+ m_policyMappingInhibit(XMLHelper::getAttrBool(e, false, policyMappingInhibit)),
+ m_anyPolicyInhibit(XMLHelper::getAttrBool(e, false, anyPolicyInhibit))
{
if (m_fullCRLChain) {
Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine.PKIX").warn(
else if (m_checkRevocation == "fullChain") {
m_fullCRLChain = true; // in case anything's using this
}
+
+ xercesc::DOMElement* c = XMLHelper::getFirstChildElement(e);
+ while (c) {
+ if (c->hasChildNodes()) {
+ auto_ptr_char v(c->getTextContent());
+ if (v.get() && *v.get()) {
+ if (XMLString::equals(c->getLocalName(), PolicyOID))
+ m_policyOIDs.insert(v.get());
+ else if (XMLString::equals(c->getLocalName(), TrustedName))
+ m_trustedNames.insert(v.get());
+ }
+ }
+ c = XMLHelper::getNextSiblingElement(c);
+ }
}
AbstractPKIXTrustEngine::~AbstractPKIXTrustEngine()
credResolver.resolve(creds,&criteria);
// Build a list of acceptable names.
- set<string> trustednames;
- trustednames.insert(criteria.getPeerName());
- for (vector<const Credential*>::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred)
+ set<string> trustednames = m_trustedNames;
+ if (log.isDebugEnabled()) {
+ for (set<string>::const_iterator n=m_trustedNames.begin(); n!=m_trustedNames.end(); n++) {
+ log.debug("adding to list of trusted names (%s)", n->c_str());
+ }
+ }
+ if (criteria.getPeerName()) {
+ trustednames.insert(criteria.getPeerName());
+ log.debug("adding to list of trusted names (%s)", criteria.getPeerName());
+ }
+ for (vector<const Credential*>::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred) {
trustednames.insert((*cred)->getKeyNames().begin(), (*cred)->getKeyNames().end());
+ if (log.isDebugEnabled()) {
+ for (set<string>::const_iterator n=(*cred)->getKeyNames().begin(); n!=(*cred)->getKeyNames().end(); n++) {
+ log.debug("adding to list of trusted names (%s)", n->c_str());
+ }
+ }
+ }
X509_NAME* subject=X509_get_subject_name(certEE);
if (subject) {
return false;
}
- if (criteria && criteria->getPeerName() && *(criteria->getPeerName())) {
+ if ((criteria && criteria->getPeerName() && *(criteria->getPeerName())) || !m_trustedNames.empty()) {
log.debug("checking that the certificate name is acceptable");
- if (criteria->getUsage()==Credential::UNSPECIFIED_CREDENTIAL)
+ if (criteria && criteria->getUsage()==Credential::UNSPECIFIED_CREDENTIAL)
criteria->setUsage(Credential::SIGNING_CREDENTIAL);
if (!checkEntityNames(certEE,credResolver,*criteria)) {
log.error("certificate name was not acceptable");
pkix.get(),
(m_checkRevocation=="entityOnly" || m_checkRevocation=="fullChain"),
(m_checkRevocation=="fullChain"),
- (m_checkRevocation=="entityOnly" || m_checkRevocation=="fullChain") ? inlineCRLs : nullptr
+ (m_checkRevocation=="entityOnly" || m_checkRevocation=="fullChain") ? inlineCRLs : nullptr,
+ m_policyMappingInhibit,
+ m_anyPolicyInhibit,
+ &m_policyOIDs
)) {
return true;
}