https://bugs.internet2.edu/jira/browse/CPPXT-64
[shibboleth/xmltooling.git] / xmltooling / security / impl / AbstractPKIXTrustEngine.cpp
1 /*
2  *  Copyright 2001-2010 Internet2
3  * 
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /**
18  * AbstractPKIXTrustEngine.cpp
19  * 
20  * A trust engine that uses X.509 trust anchors and CRLs associated with a KeyInfoSource
21  * to perform PKIX validation of signatures and certificates.
22  */
23
24 #include "internal.h"
25 #include "logging.h"
26 #include "security/AbstractPKIXTrustEngine.h"
27 #include "signature/KeyInfo.h"
28 #include "signature/Signature.h"
29 #include "security/CredentialCriteria.h"
30 #include "security/CredentialResolver.h"
31 #include "security/KeyInfoResolver.h"
32 #include "security/OpenSSLCryptoX509CRL.h"
33 #include "security/SecurityHelper.h"
34 #include "security/X509Credential.h"
35 #include "signature/SignatureValidator.h"
36 #include "util/NDC.h"
37 #include "util/PathResolver.h"
38
39 #include <fstream>
40 #include <openssl/x509_vfy.h>
41 #include <openssl/x509v3.h>
42 #include <xercesc/util/XMLUniDefs.hpp>
43 #include <xsec/enc/OpenSSL/OpenSSLCryptoX509.hpp>
44
45 using namespace xmlsignature;
46 using namespace xmltooling::logging;
47 using namespace xmltooling;
48 using namespace std;
49
50
51 namespace {
52     static int XMLTOOL_DLLLOCAL error_callback(int ok, X509_STORE_CTX* ctx)
53     {
54         if (!ok)
55             Category::getInstance("OpenSSL").error("path validation failure: %s", X509_verify_cert_error_string(ctx->error));
56         return ok;
57     }
58
59     static string XMLTOOL_DLLLOCAL X509_NAME_to_string(X509_NAME* n)
60     {
61         string s;
62         BIO* b = BIO_new(BIO_s_mem());
63         X509_NAME_print_ex(b,n,0,XN_FLAG_RFC2253);
64         BIO_flush(b);
65         BUF_MEM* bptr=nullptr;
66         BIO_get_mem_ptr(b, &bptr);
67         if (bptr && bptr->length > 0) {
68             s.append(bptr->data, bptr->length);
69         }
70         BIO_free(b);
71         return s;
72     }
73
74     static void XMLTOOL_DLLLOCAL getRemoteCRLs(vector<XSECCryptoX509CRL*>& crls, const char* cdpuri, Category& log) {
75         // This is a temporary CRL cache implementation to avoid breaking binary compatibility
76         // for the library. Caching can't rely on any member objects within the TrustEngine,
77         // including locks, so we're using the global library lock for the time being.
78         // All other state is kept in the file system.
79
80         // The filenames for the CRL cache are based on a hash of the CRL location.
81         string cdpfile = SecurityHelper::doHash("SHA1", cdpuri, strlen(cdpuri)) + ".crl";
82         XMLToolingConfig::getConfig().getPathResolver()->resolve(cdpfile, PathResolver::XMLTOOLING_RUN_FILE);
83         string cdpstaging = cdpfile + ".bak";
84         string counterfile = cdpfile + ".cnt";
85
86         // Need to move this to a configurable parameter once we can break binary compatibility.
87         // Ideally this would be based on a percentage of the original CRL window, but OpenSSL
88         // doesn't provide much in the way of ASN1_TIME parsing functions. It does support adding
89         // a fixed time value and comparing against known times.
90         #define MIN_SECS_REMAINING 86400;
91         long counter = 0;
92         try {
93             // While holding the lock, check for a cached copy of the CRL, and check its validity.
94             Locker glock(&XMLToolingConfig::getConfig());
95 #ifdef WIN32
96             struct _stat stat_buf;
97             if (_stat(cdpfile.c_str(), &stat_buf) == 0) {
98 #else
99             struct stat stat_buf;
100             if (stat(cdpfile.c_str(), &stat_buf) == 0) {
101 #endif
102                 SecurityHelper::loadCRLsFromFile(crls, cdpfile.c_str());
103                 if (crls.empty() || crls.front()->getProviderName() != DSIGConstants::s_unicodeStrPROVOpenSSL ||
104                     X509_cmp_time(X509_CRL_get_nextUpdate(static_cast<OpenSSLCryptoX509CRL*>(crls.front())->getOpenSSLX509CRL()), nullptr) < 0) {
105                     for_each(crls.begin(), crls.end(), xmltooling::cleanup<XSECCryptoX509CRL>());
106                     crls.clear();
107                     remove(cdpfile.c_str());    // may as well delete the local copy
108                     remove(counterfile.c_str());
109                     log.info("cached CRL(s) from (%s) have expired", cdpuri);
110                 }
111                 else {
112                     // Look for a file containing the allowable time remaining on the CRL.
113                     // We store this counter in the file system because of the binary compatibility issue.
114                     try {
115                         ifstream countersrc(counterfile.c_str());
116                         if (countersrc)
117                             countersrc >> counter;
118                     }
119                     catch (exception&) {
120                         counter = 0;
121                     }
122                     if (counter == 0)
123                         counter = MIN_SECS_REMAINING;
124
125                     // See if the time left is under the counter threshold.
126                     time_t exp = time(nullptr) + counter;
127                     if (X509_cmp_time(X509_CRL_get_nextUpdate(static_cast<OpenSSLCryptoX509CRL*>(crls.front())->getOpenSSLX509CRL()), &exp) < 0) {
128                         for_each(crls.begin(), crls.end(), xmltooling::cleanup<XSECCryptoX509CRL>());
129                         crls.clear();
130                         log.info("cached CRL(s) from (%s) will expire within %ld seconds, attempting to update them", cdpuri, counter);
131                     }
132                 }
133             }
134         }
135         catch (exception& ex) {
136             log.error("exception loading cached copy of CRL at (%s): %s", cdpuri, ex.what());
137         }
138
139         if (crls.empty()) {
140             try {
141                 // If we get here, the cached copy didn't exist yet, or it's time to refresh.
142                 SOAPTransport::Address addr("AbstractPKIXTrustEngine", cdpuri, cdpuri);
143                 string scheme(addr.m_endpoint, strchr(addr.m_endpoint,':') - addr.m_endpoint);
144                 auto_ptr<SOAPTransport> soap(XMLToolingConfig::getConfig().SOAPTransportManager.newPlugin(scheme.c_str(), addr));
145                 soap->send();
146                 istream& msg = soap->receive();
147                 Locker glock(&XMLToolingConfig::getConfig());
148                 ofstream out(cdpstaging.c_str(), fstream::trunc|fstream::binary);
149                 out << msg.rdbuf();
150                 out.close();
151                 SecurityHelper::loadCRLsFromFile(crls, cdpstaging.c_str());
152                 if (crls.empty() || crls.front()->getProviderName() != DSIGConstants::s_unicodeStrPROVOpenSSL ||
153                     X509_cmp_time(X509_CRL_get_nextUpdate(static_cast<OpenSSLCryptoX509CRL*>(crls.front())->getOpenSSLX509CRL()), nullptr) < 0) {
154                     // The "new" CRLs weren't usable, so get rid of them.
155                     for_each(crls.begin(), crls.end(), xmltooling::cleanup<XSECCryptoX509CRL>());
156                     crls.clear();
157                     remove(cdpstaging.c_str());
158                     log.error("updated CRL(s) from (%s) have already expired", cdpuri);
159
160                     // If counter isn't 0, then we were attempting an update of still-valid CRLs, so reload the old ones
161                     // and cut the counter in half for next time.
162                     if (counter > 0) {
163                         SecurityHelper::loadCRLsFromFile(crls, cdpfile.c_str());
164                         ofstream countersink(counterfile.c_str(), fstream::trunc);
165                         counter /= 2;
166                         countersink << counter;
167                         log.info("failed CRL update attempt, reducing threshold to %ld seconds", counter);
168                     }
169                 }
170                 else {
171                     // If counter isn't zero, we reloaded; see if the new CRLs are "more" valid than before.
172                     if (counter > 0) {
173                         time_t exp = time(nullptr) + counter;
174                         if (X509_cmp_time(X509_CRL_get_nextUpdate(static_cast<OpenSSLCryptoX509CRL*>(crls.front())->getOpenSSLX509CRL()), &exp) < 0) {
175                             // Still invalid past the acceptable interval, so they're the same as what we had.
176                             // Remove the extra copy, and cut the counter in half for next time.
177                             remove(cdpstaging.c_str());
178                             ofstream countersink(counterfile.c_str(), fstream::trunc);
179                             counter /= 2;
180                             countersink << counter;
181                             log.info("remote CRL(s) unchanged, reducing threshold to %ld seconds", counter);
182                         }
183                         else {
184                             counter = 0;
185                             log.info("remote CRL(s) updated");
186                         }
187                     }
188
189                     if (counter == 0) {
190                         // "Commit" the new CRLs.
191                         remove(cdpfile.c_str());
192                         remove(counterfile.c_str());
193                         if (rename(cdpstaging.c_str(), cdpfile.c_str()) != 0)
194                             log.error("unable to rename CRL staging file");
195                     }
196                 }
197             }
198             catch (exception& ex) {
199                 log.error("exception downloading/caching CRL at (%s): %s", cdpuri, ex.what());
200             }
201         }
202     }
203
204     static bool XMLTOOL_DLLLOCAL validate(
205         X509* EE,
206         STACK_OF(X509)* untrusted,
207         AbstractPKIXTrustEngine::PKIXValidationInfoIterator* pkixInfo,
208                 bool useCRL,
209         bool fullCRLChain,
210         const vector<XSECCryptoX509CRL*>* inlineCRLs=nullptr
211         )
212     {
213         Category& log=Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine");
214     
215         // First we build a stack of CA certs. These objects are all referenced in place.
216         log.debug("supplying PKIX Validation information");
217     
218         // We need this for CRL support.
219         X509_STORE* store=X509_STORE_new();
220         if (!store) {
221             log_openssl();
222             return false;
223         }
224     
225         // This contains the state of the validate operation.
226         int count=0;
227         X509_STORE_CTX ctx;
228
229         // AFAICT, EE and untrusted are passed in but not owned by the ctx.
230 #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
231         if (X509_STORE_CTX_init(&ctx,store,EE,untrusted)!=1) {
232             log_openssl();
233             log.error("unable to initialize X509_STORE_CTX");
234             X509_STORE_free(store);
235             return false;
236         }
237 #else
238         X509_STORE_CTX_init(&ctx,store,EE,untrusted);
239 #endif
240
241         STACK_OF(X509)* CAstack = sk_X509_new_null();
242         const vector<XSECCryptoX509*>& CAcerts = pkixInfo->getTrustAnchors();
243         for (vector<XSECCryptoX509*>::const_iterator i=CAcerts.begin(); i!=CAcerts.end(); ++i) {
244             if ((*i)->getProviderName()==DSIGConstants::s_unicodeStrPROVOpenSSL) {
245                 sk_X509_push(CAstack,static_cast<OpenSSLCryptoX509*>(*i)->getOpenSSLX509());
246                 ++count;
247             }
248         }
249         log.debug("supplied (%d) CA certificate(s)", count);
250
251         // Seems to be most efficient to just pass in the CA stack.
252         X509_STORE_CTX_trusted_stack(&ctx,CAstack);
253         X509_STORE_CTX_set_depth(&ctx,100);    // we check the depth down below
254         X509_STORE_CTX_set_verify_cb(&ctx,error_callback);
255
256         // Do a first pass verify. If CRLs aren't used, this is the only pass.
257         int ret=X509_verify_cert(&ctx);
258         if (ret==1) {
259             // Now see if the depth was acceptable by counting the number of intermediates.
260             int depth=sk_X509_num(ctx.chain)-2;
261             if (pkixInfo->getVerificationDepth() < depth) {
262                 log.error(
263                     "certificate chain was too long (%d intermediates, only %d allowed)",
264                     (depth==-1) ? 0 : depth,
265                     pkixInfo->getVerificationDepth()
266                     );
267                 ret=0;
268             }
269         }
270
271         if (useCRL) {
272 #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
273             // When we add CRLs, we have to be sure the nextUpdate hasn't passed, because OpenSSL won't accept
274             // the CRL in that case. If we end up not adding a CRL for a particular link in the chain, the
275             // validation will fail (if the fullChain option was set).
276             set<string> crlissuers;
277             if (inlineCRLs) {
278                 for (vector<XSECCryptoX509CRL*>::const_iterator j=inlineCRLs->begin(); j!=inlineCRLs->end(); ++j) {
279                     if ((*j)->getProviderName()==DSIGConstants::s_unicodeStrPROVOpenSSL &&
280                         (X509_cmp_time(X509_CRL_get_nextUpdate(static_cast<OpenSSLCryptoX509CRL*>(*j)->getOpenSSLX509CRL()), nullptr)==1)) {
281                         // owned by store
282                         X509_STORE_add_crl(store, X509_CRL_dup(static_cast<OpenSSLCryptoX509CRL*>(*j)->getOpenSSLX509CRL()));
283                         string crlissuer(X509_NAME_to_string(X509_CRL_get_issuer(static_cast<OpenSSLCryptoX509CRL*>(*j)->getOpenSSLX509CRL())));
284                         if (!crlissuer.empty()) {
285                             log.debug("added CRL issued by (%s)", crlissuer.c_str());
286                             crlissuers.insert(crlissuer);
287                         }
288                     }
289                 }
290             }
291             const vector<XSECCryptoX509CRL*>& crls = pkixInfo->getCRLs();
292             for (vector<XSECCryptoX509CRL*>::const_iterator j=crls.begin(); j!=crls.end(); ++j) {
293                 if ((*j)->getProviderName()==DSIGConstants::s_unicodeStrPROVOpenSSL &&
294                     (X509_cmp_time(X509_CRL_get_nextUpdate(static_cast<OpenSSLCryptoX509CRL*>(*j)->getOpenSSLX509CRL()), nullptr)==1)) {
295                     // owned by store
296                     X509_STORE_add_crl(store, X509_CRL_dup(static_cast<OpenSSLCryptoX509CRL*>(*j)->getOpenSSLX509CRL()));
297                     string crlissuer(X509_NAME_to_string(X509_CRL_get_issuer(static_cast<OpenSSLCryptoX509CRL*>(*j)->getOpenSSLX509CRL())));
298                     if (!crlissuer.empty()) {
299                         log.debug("added CRL issued by (%s)", crlissuer.c_str());
300                         crlissuers.insert(crlissuer);
301                     }
302                 }
303             }
304
305             for (int i = 0; i < sk_X509_num(untrusted); ++i) {
306                 X509 *cert = sk_X509_value(untrusted, i);
307                 string crlissuer(X509_NAME_to_string(X509_get_issuer_name(cert)));
308                 if (crlissuers.count(crlissuer)) {
309                    // We already have a CRL for this cert, so skip it.
310                    continue;
311                 }
312
313                 bool foundUsableCDP = false;
314                 STACK_OF(DIST_POINT)* dps = (STACK_OF(DIST_POINT)*)X509_get_ext_d2i(cert, NID_crl_distribution_points, nullptr, nullptr);
315                 for (int ii = 0; !foundUsableCDP && ii < sk_DIST_POINT_num(dps); ++ii) {
316                     DIST_POINT* dp = sk_DIST_POINT_value(dps, ii);
317                     if (!dp->distpoint || dp->distpoint->type != 0)
318                         continue;
319                     for (int iii = 0; !foundUsableCDP && iii < sk_GENERAL_NAME_num(dp->distpoint->name.fullname); ++iii) {
320                         GENERAL_NAME* gen = sk_GENERAL_NAME_value(dp->distpoint->name.fullname, iii);
321                         // Only consider HTTP URIs, and stop after the first one we find.
322 #ifdef HAVE_STRCASECMP
323                         if (gen->type == GEN_URI && (!strncasecmp((const char*)gen->d.ia5->data, "http:", 5) ||
324                                 !strncasecmp((const char*)gen->d.ia5->data, "https:", 6))) {
325 #else
326                         if (gen->type == GEN_URI && (!strnicmp((const char*)gen->d.ia5->data, "http:", 5) ||
327                                 !strnicmp((const char*)gen->d.ia5->data, "https:", 6))) {
328 #endif
329                             const char* cdpuri = (const char*)gen->d.ia5->data;
330                             vector<XSECCryptoX509CRL*> crls;
331                             getRemoteCRLs(crls, cdpuri, log);
332                             for (vector<XSECCryptoX509CRL*>::const_iterator j = crls.begin(); j != crls.end(); ++j) {
333                                 if ((*j)->getProviderName()==DSIGConstants::s_unicodeStrPROVOpenSSL &&
334                                     X509_cmp_time(X509_CRL_get_nextUpdate(static_cast<OpenSSLCryptoX509CRL*>(*j)->getOpenSSLX509CRL()), nullptr) > 0) {
335                                     // owned by store
336                                     X509_STORE_add_crl(store, X509_CRL_dup(static_cast<OpenSSLCryptoX509CRL*>(*j)->getOpenSSLX509CRL()));
337                                     log.debug("added CRL issued by (%s)", crlissuer.c_str());
338                                     crlissuers.insert(crlissuer);
339                                     foundUsableCDP = true;
340                                 }
341                             }
342                             for_each(crls.begin(), crls.end(), xmltooling::cleanup<XSECCryptoX509CRL>());
343                         }
344                     }
345                 }
346                 sk_DIST_POINT_free(dps);
347             }
348
349             if (count > 0) {
350                 X509_STORE_set_flags(store, fullCRLChain ? (X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL) : (X509_V_FLAG_CRL_CHECK));
351                     }
352                     else {
353                             log.warn("CRL checking is enabled, but none were supplied");
354                 X509_STORE_CTX_cleanup(&ctx);
355                 X509_STORE_free(store);
356                 sk_X509_free(CAstack);
357                 return false;
358                     }
359 #else
360                         log.warn("CRL checking is enabled, but OpenSSL version is too old");
361             X509_STORE_CTX_cleanup(&ctx);
362             X509_STORE_free(store);
363             sk_X509_free(CAstack);
364             return false;
365 #endif
366             // Do a second pass verify with CRLs in place.
367             ret=X509_verify_cert(&ctx);
368         }
369
370         // Clean up...
371         X509_STORE_CTX_cleanup(&ctx);
372         X509_STORE_free(store);
373         sk_X509_free(CAstack);
374     
375         if (ret==1) {
376             log.debug("successfully validated certificate chain");
377             return true;
378         }
379         
380         return false;
381     }
382
383     static XMLCh fullCRLChain[] =               UNICODE_LITERAL_12(f,u,l,l,C,R,L,C,h,a,i,n);
384         static XMLCh checkRevocation[] =        UNICODE_LITERAL_15(c,h,e,c,k,R,e,v,o,c,a,t,i,o,n);
385 };
386
387 AbstractPKIXTrustEngine::PKIXValidationInfoIterator::PKIXValidationInfoIterator()
388 {
389 }
390
391 AbstractPKIXTrustEngine::PKIXValidationInfoIterator::~PKIXValidationInfoIterator()
392 {
393 }
394
395 AbstractPKIXTrustEngine::AbstractPKIXTrustEngine(const xercesc::DOMElement* e)
396         : TrustEngine(e),
397                 m_fullCRLChain(XMLHelper::getAttrBool(e, false, fullCRLChain)),
398                 m_checkRevocation(XMLHelper::getAttrString(e, nullptr, checkRevocation))
399 {
400     if (m_fullCRLChain) {
401         Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine.PKIX").warn(
402             "fullCRLChain option is deprecated, setting checkRevocation to \"fullChain\""
403             );
404         m_checkRevocation = "fullChain";
405     }
406     else if (m_checkRevocation == "fullChain") {
407         m_fullCRLChain = true; // in case anything's using this
408     }
409 }
410
411 AbstractPKIXTrustEngine::~AbstractPKIXTrustEngine()
412 {
413 }
414
415 bool AbstractPKIXTrustEngine::checkEntityNames(
416     X509* certEE, const CredentialResolver& credResolver, const CredentialCriteria& criteria
417     ) const
418 {
419     Category& log=Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine.PKIX");
420
421     // We resolve to a set of trusted credentials.
422     vector<const Credential*> creds;
423     credResolver.resolve(creds,&criteria);
424
425     // Build a list of acceptable names.
426     set<string> trustednames;
427     trustednames.insert(criteria.getPeerName());
428     for (vector<const Credential*>::const_iterator cred = creds.begin(); cred!=creds.end(); ++cred)
429         trustednames.insert((*cred)->getKeyNames().begin(), (*cred)->getKeyNames().end());
430
431     X509_NAME* subject=X509_get_subject_name(certEE);
432     if (subject) {
433         // One way is a direct match to the subject DN.
434         // Seems that the way to do the compare is to write the X509_NAME into a BIO.
435         BIO* b = BIO_new(BIO_s_mem());
436         BIO* b2 = BIO_new(BIO_s_mem());
437         // The flags give us LDAP order instead of X.500, with a comma separator.
438         X509_NAME_print_ex(b,subject,0,XN_FLAG_RFC2253);
439         BIO_flush(b);
440         // The flags give us LDAP order instead of X.500, with a comma plus space separator.
441         X509_NAME_print_ex(b2,subject,0,XN_FLAG_RFC2253 + XN_FLAG_SEP_CPLUS_SPC - XN_FLAG_SEP_COMMA_PLUS);
442         BIO_flush(b2);
443
444         BUF_MEM* bptr=nullptr;
445         BUF_MEM* bptr2=nullptr;
446         BIO_get_mem_ptr(b, &bptr);
447         BIO_get_mem_ptr(b2, &bptr2);
448
449         if (bptr && bptr->length > 0 && log.isDebugEnabled()) {
450             string subjectstr(bptr->data, bptr->length);
451             log.debug("certificate subject: %s", subjectstr.c_str());
452         }
453         
454         // Check each keyname.
455         for (set<string>::const_iterator n=trustednames.begin(); bptr && bptr2 && n!=trustednames.end(); n++) {
456 #ifdef HAVE_STRCASECMP
457             if ((n->length() == bptr->length && !strncasecmp(n->c_str(), bptr->data, bptr->length)) ||
458                 (n->length() == bptr2->length && !strncasecmp(n->c_str(), bptr2->data, bptr2->length))) {
459 #else
460             if ((n->length() == bptr->length && !strnicmp(n->c_str(), bptr->data, bptr->length)) ||
461                 (n->length() == bptr2->length && !strnicmp(n->c_str(), bptr2->data, bptr2->length))) {
462 #endif
463                 log.debug("matched full subject DN to a key name (%s)", n->c_str());
464                 BIO_free(b);
465                 BIO_free(b2);
466                 return true;
467             }
468         }
469         BIO_free(b);
470         BIO_free(b2);
471
472         log.debug("unable to match DN, trying TLS subjectAltName match");
473         STACK_OF(GENERAL_NAME)* altnames=(STACK_OF(GENERAL_NAME)*)X509_get_ext_d2i(certEE, NID_subject_alt_name, nullptr, nullptr);
474         if (altnames) {
475             int numalts = sk_GENERAL_NAME_num(altnames);
476             for (int an=0; an<numalts; an++) {
477                 const GENERAL_NAME* check = sk_GENERAL_NAME_value(altnames, an);
478                 if (check->type==GEN_DNS || check->type==GEN_URI) {
479                     const char* altptr = (char*)ASN1_STRING_data(check->d.ia5);
480                     const int altlen = ASN1_STRING_length(check->d.ia5);
481                     for (set<string>::const_iterator n=trustednames.begin(); n!=trustednames.end(); n++) {
482 #ifdef HAVE_STRCASECMP
483                         if ((check->type==GEN_DNS && n->length()==altlen && !strncasecmp(altptr,n->c_str(),altlen))
484 #else
485                         if ((check->type==GEN_DNS && n->length()==altlen && !strnicmp(altptr,n->c_str(),altlen))
486 #endif
487                                 || (check->type==GEN_URI && n->length()==altlen && !strncmp(altptr,n->c_str(),altlen))) {
488                             log.debug("matched DNS/URI subjectAltName to a key name (%s)", n->c_str());
489                             GENERAL_NAMES_free(altnames);
490                             return true;
491                         }
492                     }
493                 }
494             }
495         }
496         GENERAL_NAMES_free(altnames);
497             
498         log.debug("unable to match subjectAltName, trying TLS CN match");
499
500         // Fetch the last CN RDN.
501         char* peer_CN = nullptr;
502         int j,i = -1;
503         while ((j=X509_NAME_get_index_by_NID(subject, NID_commonName, i)) >= 0)
504             i = j;
505         if (i >= 0) {
506             ASN1_STRING* tmp = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subject, i));
507             // Copied in from libcurl.
508             /* In OpenSSL 0.9.7d and earlier, ASN1_STRING_to_UTF8 fails if the input
509                is already UTF-8 encoded. We check for this case and copy the raw
510                string manually to avoid the problem. */
511             if(tmp && ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
512                 j = ASN1_STRING_length(tmp);
513                 if(j >= 0) {
514                     peer_CN = (char*)OPENSSL_malloc(j + 1);
515                     memcpy(peer_CN, ASN1_STRING_data(tmp), j);
516                     peer_CN[j] = '\0';
517                 }
518             }
519             else /* not a UTF8 name */ {
520                 j = ASN1_STRING_to_UTF8(reinterpret_cast<unsigned char**>(&peer_CN), tmp);
521             }
522
523             for (set<string>::const_iterator n=trustednames.begin(); n!=trustednames.end(); n++) {
524 #ifdef HAVE_STRCASECMP
525                 if (n->length() == j && !strncasecmp(peer_CN, n->c_str(), j)) {
526 #else
527                 if (n->length() == j && !strnicmp(peer_CN, n->c_str(), j)) {
528 #endif
529                     log.debug("matched subject CN to a key name (%s)", n->c_str());
530                     if(peer_CN)
531                         OPENSSL_free(peer_CN);
532                     return true;
533                 }
534             }
535             if(peer_CN)
536                 OPENSSL_free(peer_CN);
537         }
538         else {
539             log.warn("no common name in certificate subject");
540         }
541     }
542     else {
543         log.error("certificate has no subject?!");
544     }
545     
546     return false;
547 }
548
549 bool AbstractPKIXTrustEngine::validateWithCRLs(
550     X509* certEE,
551     STACK_OF(X509)* certChain,
552     const CredentialResolver& credResolver,
553     CredentialCriteria* criteria,
554     const std::vector<XSECCryptoX509CRL*>* inlineCRLs
555     ) const
556 {
557 #ifdef _DEBUG
558     NDC ndc("validateWithCRLs");
559 #endif
560     Category& log=Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine.PKIX");
561
562     if (!certEE) {
563         log.error("X.509 credential was NULL, unable to perform validation");
564         return false;
565     }
566
567     if (criteria && criteria->getPeerName() && *(criteria->getPeerName())) {
568         log.debug("checking that the certificate name is acceptable");
569         if (criteria->getUsage()==Credential::UNSPECIFIED_CREDENTIAL)
570             criteria->setUsage(Credential::SIGNING_CREDENTIAL);
571         if (!checkEntityNames(certEE,credResolver,*criteria)) {
572             log.error("certificate name was not acceptable");
573             return false;
574         }
575     }
576     
577     log.debug("performing certificate path validation...");
578
579     auto_ptr<PKIXValidationInfoIterator> pkix(getPKIXValidationInfoIterator(credResolver, criteria));
580     while (pkix->next()) {
581         if (::validate(
582                                 certEE,
583                                 certChain,
584                                 pkix.get(),
585                                 (m_checkRevocation=="entityOnly" || m_checkRevocation=="fullChain"),
586                                 (m_checkRevocation=="fullChain"),
587                                 (m_checkRevocation=="entityOnly" || m_checkRevocation=="fullChain") ? inlineCRLs : nullptr
588                                 )) {
589             return true;
590         }
591     }
592
593     log.debug("failed to validate certificate chain using supplied PKIX information");
594     return false;
595 }
596
597 bool AbstractPKIXTrustEngine::validate(
598     X509* certEE,
599     STACK_OF(X509)* certChain,
600     const CredentialResolver& credResolver,
601     CredentialCriteria* criteria
602     ) const
603 {
604     return validateWithCRLs(certEE,certChain,credResolver,criteria);
605 }
606
607 bool AbstractPKIXTrustEngine::validate(
608     XSECCryptoX509* certEE,
609     const vector<XSECCryptoX509*>& certChain,
610     const CredentialResolver& credResolver,
611     CredentialCriteria* criteria
612     ) const
613 {
614 #ifdef _DEBUG
615         NDC ndc("validate");
616 #endif
617     if (!certEE) {
618         Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine.PKIX").error("X.509 credential was NULL, unable to perform validation");
619         return false;
620     }
621     else if (certEE->getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL) {
622         Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine.PKIX").error("only the OpenSSL XSEC provider is supported");
623         return false;
624     }
625
626     STACK_OF(X509)* untrusted=sk_X509_new_null();
627     for (vector<XSECCryptoX509*>::const_iterator i=certChain.begin(); i!=certChain.end(); ++i)
628         sk_X509_push(untrusted,static_cast<OpenSSLCryptoX509*>(*i)->getOpenSSLX509());
629
630     bool ret = validate(static_cast<OpenSSLCryptoX509*>(certEE)->getOpenSSLX509(), untrusted, credResolver, criteria);
631     sk_X509_free(untrusted);
632     return ret;
633 }
634
635 bool AbstractPKIXTrustEngine::validate(
636     Signature& sig,
637     const CredentialResolver& credResolver,
638     CredentialCriteria* criteria
639     ) const
640 {
641 #ifdef _DEBUG
642     NDC ndc("validate");
643 #endif
644     Category& log=Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine.PKIX");
645
646     const KeyInfoResolver* inlineResolver = m_keyInfoResolver;
647     if (!inlineResolver)
648         inlineResolver = XMLToolingConfig::getConfig().getKeyInfoResolver();
649     if (!inlineResolver) {
650         log.error("unable to perform PKIX validation, no KeyInfoResolver available");
651         return false;
652     }
653
654     // Pull the certificate chain out of the signature.
655     X509Credential* x509cred;
656     auto_ptr<Credential> cred(inlineResolver->resolve(&sig,X509Credential::RESOLVE_CERTS|X509Credential::RESOLVE_CRLS));
657     if (!cred.get() || !(x509cred=dynamic_cast<X509Credential*>(cred.get()))) {
658         log.error("unable to perform PKIX validation, signature does not contain any certificates");
659         return false;
660     }
661     const vector<XSECCryptoX509*>& certs = x509cred->getEntityCertificateChain();
662     if (certs.empty()) {
663         log.error("unable to perform PKIX validation, signature does not contain any certificates");
664         return false;
665     }
666
667     log.debug("validating signature using certificate from within the signature");
668
669     // Find and save off a pointer to the certificate that unlocks the object.
670     // Most of the time, this will be the first one anyway.
671     XSECCryptoX509* certEE=nullptr;
672     SignatureValidator keyValidator;
673     for (vector<XSECCryptoX509*>::const_iterator i=certs.begin(); !certEE && i!=certs.end(); ++i) {
674         try {
675             auto_ptr<XSECCryptoKey> key((*i)->clonePublicKey());
676             keyValidator.setKey(key.get());
677             keyValidator.validate(&sig);
678             log.debug("signature verified with key inside signature, attempting certificate validation...");
679             certEE=(*i);
680         }
681         catch (ValidationException& ex) {
682             log.debug(ex.what());
683         }
684     }
685     
686     if (!certEE) {
687         log.debug("failed to verify signature with embedded certificates");
688         return false;
689     }
690     else if (certEE->getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL) {
691         log.error("only the OpenSSL XSEC provider is supported");
692         return false;
693     }
694
695     STACK_OF(X509)* untrusted=sk_X509_new_null();
696     for (vector<XSECCryptoX509*>::const_iterator i=certs.begin(); i!=certs.end(); ++i)
697         sk_X509_push(untrusted,static_cast<OpenSSLCryptoX509*>(*i)->getOpenSSLX509());
698     const vector<XSECCryptoX509CRL*>& crls = x509cred->getCRLs();
699     bool ret = validateWithCRLs(static_cast<OpenSSLCryptoX509*>(certEE)->getOpenSSLX509(), untrusted, credResolver, criteria, &crls);
700     sk_X509_free(untrusted);
701     return ret;
702 }
703
704 bool AbstractPKIXTrustEngine::validate(
705     const XMLCh* sigAlgorithm,
706     const char* sig,
707     KeyInfo* keyInfo,
708     const char* in,
709     unsigned int in_len,
710     const CredentialResolver& credResolver,
711     CredentialCriteria* criteria
712     ) const
713 {
714 #ifdef _DEBUG
715     NDC ndc("validate");
716 #endif
717     Category& log=Category::getInstance(XMLTOOLING_LOGCAT".TrustEngine.PKIX");
718
719     if (!keyInfo) {
720         log.error("unable to perform PKIX validation, KeyInfo not present");
721         return false;
722     }
723
724     const KeyInfoResolver* inlineResolver = m_keyInfoResolver;
725     if (!inlineResolver)
726         inlineResolver = XMLToolingConfig::getConfig().getKeyInfoResolver();
727     if (!inlineResolver) {
728         log.error("unable to perform PKIX validation, no KeyInfoResolver available");
729         return false;
730     }
731
732     // Pull the certificate chain out of the signature.
733     X509Credential* x509cred;
734     auto_ptr<Credential> cred(inlineResolver->resolve(keyInfo,X509Credential::RESOLVE_CERTS));
735     if (!cred.get() || !(x509cred=dynamic_cast<X509Credential*>(cred.get()))) {
736         log.error("unable to perform PKIX validation, KeyInfo does not contain any certificates");
737         return false;
738     }
739     const vector<XSECCryptoX509*>& certs = x509cred->getEntityCertificateChain();
740     if (certs.empty()) {
741         log.error("unable to perform PKIX validation, KeyInfo does not contain any certificates");
742         return false;
743     }
744
745     log.debug("validating signature using certificate from within KeyInfo");
746
747     // Find and save off a pointer to the certificate that unlocks the object.
748     // Most of the time, this will be the first one anyway.
749     XSECCryptoX509* certEE=nullptr;
750     for (vector<XSECCryptoX509*>::const_iterator i=certs.begin(); !certEE && i!=certs.end(); ++i) {
751         try {
752             auto_ptr<XSECCryptoKey> key((*i)->clonePublicKey());
753             if (Signature::verifyRawSignature(key.get(), sigAlgorithm, sig, in, in_len)) {
754                 log.debug("signature verified with key inside signature, attempting certificate validation...");
755                 certEE=(*i);
756             }
757         }
758         catch (SignatureException& ex) {
759             log.debug(ex.what());
760         }
761     }
762
763     if (!certEE) {
764         log.debug("failed to verify signature with embedded certificates");
765         return false;
766     }
767     else if (certEE->getProviderName()!=DSIGConstants::s_unicodeStrPROVOpenSSL) {
768         log.error("only the OpenSSL XSEC provider is supported");
769         return false;
770     }
771
772     STACK_OF(X509)* untrusted=sk_X509_new_null();
773     for (vector<XSECCryptoX509*>::const_iterator i=certs.begin(); i!=certs.end(); ++i)
774         sk_X509_push(untrusted,static_cast<OpenSSLCryptoX509*>(*i)->getOpenSSLX509());
775     const vector<XSECCryptoX509CRL*>& crls = x509cred->getCRLs();
776     bool ret = validateWithCRLs(static_cast<OpenSSLCryptoX509*>(certEE)->getOpenSSLX509(), untrusted, credResolver, criteria, &crls);
777     sk_X509_free(untrusted);
778     return ret;
779 }