/// Check if signing certificate was issued by trusted party. /// @throws SignatureException on a problem with signing certificate void SignatureBES::checkSigningCertificate() const { try { X509Cert signingCert = signingCertificate(); vector<X509Cert::KeyUsage> usage = signingCert.keyUsage(); if(find(usage.begin(), usage.end(), X509Cert::NonRepudiation) == usage.end()) THROW("Signing certificate does not contain NonRepudiation key usage flag"); string time = trustedSigningTime(); if(time.empty()) THROW("SigningTime missing"); time_t signingTime_t = util::date::string2time_t(time); if(!X509CertStore::instance()->verify(signingCert, &signingTime_t)) THROW("Unable to verify signing certificate"); } catch(const Exception &e) { THROW_CAUSE( e, "Unable to verify signing certificate" ); } }
/** * Check if X509Cert is signed by trusted issuer * @throw Exception if error */ bool X509CertStore::verify(const X509Cert &cert, bool noqscd) const { activate(cert.issuerName("C")); const ASN1_TIME *asn1time = X509_get0_notBefore(cert.handle()); time_t time = util::date::ASN1TimeToTime_t(string((const char*)asn1time->data, size_t(asn1time->length)), asn1time->type == V_ASN1_GENERALIZEDTIME); SCOPE(X509_STORE, store, createStore(X509CertStore::CA, &time)); SCOPE(X509_STORE_CTX, csc, X509_STORE_CTX_new()); if(!X509_STORE_CTX_init(csc.get(), store.get(), cert.handle(), nullptr)) THROW_OPENSSLEXCEPTION("Failed to init X509_STORE_CTX"); if(X509_verify_cert(csc.get()) > 0) { if(noqscd) return true; const TSL::Validity *v = static_cast<const TSL::Validity*>(X509_STORE_CTX_get_ex_data(csc.get(), 0)); const vector<string> policies = cert.certificatePolicies(); const vector<string> qcstatement = cert.qcStatements(); const vector<X509Cert::KeyUsage> keyUsage = cert.keyUsage(); bool isQCCompliant = find(qcstatement.cbegin(), qcstatement.cend(), X509Cert::QC_COMPLIANT) != qcstatement.cend(); bool isQSCD = find(policies.cbegin(), policies.cend(), X509Cert::QCP_PUBLIC_WITH_SSCD) != policies.cend() || find(policies.cbegin(), policies.cend(), X509Cert::QCP_LEGAL_QSCD) != policies.cend() || find(policies.cbegin(), policies.cend(), X509Cert::QCP_NATURAL_QSCD) != policies.cend() || find(qcstatement.cbegin(), qcstatement.cend(), X509Cert::QC_SSCD) != qcstatement.cend(); bool isESeal = // Special treamtent for E-Seals find(policies.cbegin(), policies.cend(), X509Cert::QCP_LEGAL) != policies.cend() || find(qcstatement.cbegin(), qcstatement.cend(), X509Cert::QCT_ESEAL) != qcstatement.cend(); auto matchPolicySet = [&](const vector<string> &policySet){ return all_of(policySet.cbegin(), policySet.cend(), [&](const string &policy){ return find(policies.cbegin(), policies.cend(), policy) != policies.cend(); }); }; auto matchKeyUsageSet = [&](const map<X509Cert::KeyUsage,bool> &keyUsageSet){ return all_of(keyUsageSet.cbegin(), keyUsageSet.cend(), [&](pair<X509Cert::KeyUsage,bool> keyUsageBit){ return (find(keyUsage.cbegin(), keyUsage.cend(), keyUsageBit.first) != keyUsage.cend()) == keyUsageBit.second; }); }; for(const TSL::Qualifier &q: v->qualifiers) { if(q.assert_ == "all") { if(!(all_of(q.policySet.cbegin(), q.policySet.cend(), matchPolicySet) && all_of(q.keyUsage.cbegin(), q.keyUsage.cend(), matchKeyUsageSet))) continue; } else if(q.assert_ == "atLeastOne") { if(!(any_of(q.policySet.cbegin(), q.policySet.cend(), matchPolicySet) || any_of(q.keyUsage.cbegin(), q.keyUsage.cend(), matchKeyUsageSet) )) continue; } else { WARN("Unable to handle Qualifier assert '%s'", q.assert_.c_str()); continue; } for(const string &qc: q.qualifiers) { if(qc == "http://uri.etsi.org/TrstSvc/TrustedList/SvcInfoExt/QCStatement" || qc == "http://uri.etsi.org/TrstSvc/TrustedList/SvcInfoExt/QCForESig") isQCCompliant = true; else if(qc == "http://uri.etsi.org/TrstSvc/TrustedList/SvcInfoExt/NotQualified") isQCCompliant = false; else if(qc == "http://uri.etsi.org/TrstSvc/TrustedList/SvcInfoExt/QCSSCDStatusAsInCert" || qc == "http://uri.etsi.org/TrstSvc/TrustedList/SvcInfoExt/QCQSCDStatusAsInCert") continue; else if(qc == "http://uri.etsi.org/TrstSvc/TrustedList/SvcInfoExt/QCWithSSCD" || qc == "http://uri.etsi.org/TrstSvc/TrustedList/SvcInfoExt/QCWithQSCD") isQSCD = true; else if(qc == "http://uri.etsi.org/TrstSvc/TrustedList/SvcInfoExt/QCNoSSCD" || qc == "http://uri.etsi.org/TrstSvc/TrustedList/SvcInfoExt/QCNoQSCD") isQSCD = false; else if(qc == "http://uri.etsi.org/TrstSvc/TrustedList/SvcInfoExt/QCForLegalPerson" || qc == "http://uri.etsi.org/TrstSvc/TrustedList/SvcInfoExt/QCForESeal") isESeal = true; } } if(!((isQCCompliant && isQSCD) || isESeal)) { Exception e(EXCEPTION_PARAMS("Signing certificate does not meet Qualification requirements")); e.setCode(Exception::CertificateIssuerMissing); throw e; } return true; } int err = X509_STORE_CTX_get_error(csc.get()); Exception e(EXCEPTION_PARAMS(X509_verify_cert_error_string(err)), OpenSSLException()); switch(err) { case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: e.setCode(Exception::CertificateIssuerMissing); throw e; default: throw e; } }