/** * Searches certificate by subject and returns a copy of it if found. * If not found returns <code>NULL</code>. * NB! The returned certificate must be freed with OpenSSL function X509_free(X509* cert). * * @param subject certificate subject. * @return returns copy of found certificate or <code>NULL</code> if certificate was not found. * @throws IOException exception is thrown if copying certificate failed. */ X509Cert X509CertStore::findIssuer(const X509Cert &cert, const set<string> &type) const { activate(cert.issuerName("C")); SCOPE(AUTHORITY_KEYID, akid, X509_get_ext_d2i(cert.handle(), NID_authority_key_identifier, nullptr, nullptr)); for(const TSL::Service &s: *d) { if(type.find(s.type) == type.cend()) continue; for(const X509Cert &i: s.certs) { if(!akid || !akid->keyid) { if(X509_NAME_cmp(X509_get_subject_name(i.handle()), X509_get_issuer_name(cert.handle()))) return i; } else { SCOPE(ASN1_OCTET_STRING, skid, X509_get_ext_d2i(i.handle(), NID_subject_key_identifier, nullptr, nullptr)); if(skid.get() && ASN1_OCTET_STRING_cmp(akid->keyid, skid.get()) == 0) return i; } } } return X509Cert(); }
/** * Adds signing certificate to the signature XML. The DER encoded X.509 certificate is added to * Signature->KeyInfo->X509Data->X509Certificate. Certificate info is also added to * Signature->Object->QualifyingProperties->SignedProperties->SignedSignatureProperties->SigningCertificate. * * @param cert certificate that is used for signing the signature XML. */ void SignatureBES::setSigningCertificate(const X509Cert& x509) { DEBUG("SignatureBES::setSigningCertificate()"); // Estoniand ID-Card specific hack for older cards, they support only max SHA224 string method = Conf::instance()->digestUri(); X509Crypto key(x509); if(!key.rsaModulus().empty()) { if(method != URI_SHA1 && method != URI_SHA224) { vector<string> pol = x509.certificatePolicies(); for(vector<string>::const_iterator i = pol.begin(); i != pol.end(); ++i) { if((i->compare(0, 22, "1.3.6.1.4.1.10015.1.1.") == 0 || i->compare(0, 22, "1.3.6.1.4.1.10015.3.1.") == 0) && key.rsaModulus().size() <= 128) { method = URI_SHA224; break; } } } signature->signedInfo().signatureMethod(Uri(Digest::toRsaUri(method))); } else signature->signedInfo().signatureMethod(Uri(Digest::toEcUri(method))); // Signature->KeyInfo->X509Data->X509Certificate // BASE64 encoding of a DER-encoded X.509 certificate = PEM encoded. X509DataType x509Data; x509Data.x509Certificate().push_back(toBase64(x509)); KeyInfoType keyInfo; keyInfo.x509Data().push_back(x509Data); signature->keyInfo(keyInfo); // Signature->Object->QualifyingProperties->SignedProperties->SignedSignatureProperties->SigningCertificate // Calculate digest of the X.509 certificate. auto_ptr<Digest> digest(new Digest()); digest->update(x509); CertIDListType signingCertificate; signingCertificate.cert().push_back(CertIDType( DigestAlgAndValueType(DigestMethodType(digest->uri()), toBase64(digest->digest())), X509IssuerSerialType(x509.issuerName(), x509.serial()))); getSignedSignatureProperties().signingCertificate(signingCertificate); }
/** * Adds signing certificate to the signature XML. The DER encoded X.509 certificate is added to * Signature->KeyInfo->X509Data->X509Certificate. Certificate info is also added to * Signature->Object->QualifyingProperties->SignedProperties->SignedSignatureProperties->SigningCertificate. * * @param cert certificate that is used for signing the signature XML. */ void SignatureBES::setSigningCertificate(const X509Cert& x509) { DEBUG("SignatureBES::setSigningCertificate()"); // Signature->KeyInfo->X509Data->X509Certificate // BASE64 encoding of a DER-encoded X.509 certificate = PEM encoded. X509DataType x509Data; x509Data.x509Certificate().push_back(toBase64(x509)); KeyInfoType keyInfo; keyInfo.x509Data().push_back(x509Data); signature->keyInfo(keyInfo); // Signature->Object->QualifyingProperties->SignedProperties->SignedSignatureProperties->SigningCertificate // Calculate digest of the X.509 certificate. Digest digest; digest.update(x509); CertIDListType signingCertificate; signingCertificate.cert().push_back(CertIDType( DigestAlgAndValueType(DigestMethodType(digest.uri()), toBase64(digest.result())), X509IssuerSerialType(x509.issuerName(), x509.serial()))); getSignedSignatureProperties().signingCertificate(signingCertificate); }
/** * 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; } }