TS::TS(const string &url, const Digest &digest, const string &useragent) { SCOPE(TS_REQ, req, TS_REQ_new()); TS_REQ_set_version(req.get(), 1); TS_REQ_set_cert_req(req.get(), 1); SCOPE(X509_ALGOR, algo, X509_ALGOR_new()); algo->algorithm = OBJ_nid2obj(Digest::toMethod(digest.uri())); algo->parameter = ASN1_TYPE_new(); algo->parameter->type = V_ASN1_NULL; SCOPE(TS_MSG_IMPRINT, msg_imprint, TS_MSG_IMPRINT_new()); TS_MSG_IMPRINT_set_algo(msg_imprint.get(), algo.get()); vector<unsigned char> digestdata = digest.result(); TS_MSG_IMPRINT_set_msg(msg_imprint.get(), digestdata.data(), int(digestdata.size())); TS_REQ_set_msg_imprint(req.get(), msg_imprint.get()); #if 0 if(!policy.empty()) { SCOPE(ASN1_OBJECT, obj, OBJ_txt2obj(policy.c_str(), 0)); TS_REQ_set_policy_id(req.get(), obj.get()); } #endif SCOPE(ASN1_INTEGER, nonce, ASN1_INTEGER_new()); nonce->length = 20; nonce->data = (unsigned char*)OPENSSL_malloc(nonce->length); nonce->data[0] = 0; while(nonce->data[0] == 0) // Make sure that first byte is not 0x00 RAND_bytes(nonce->data, nonce->length); TS_REQ_set_nonce(req.get(), nonce.get()); int len = i2d_TS_REQ(req.get(), 0); vector<unsigned char> data(len, 0); unsigned char *p = data.data(); i2d_TS_REQ(req.get(), &p); string result = Connect(url, "POST", 0, useragent).exec({ {"Content-Type", "application/timestamp-query"}, {"Accept", "application/timestamp-reply"}, {"Connection", "Close"}, {"Cache-Control", "no-cache"} }, data).content; const unsigned char *p2 = (const unsigned char*)result.c_str(); SCOPE(TS_RESP, resp, d2i_TS_RESP(0, &p2, long(result.size()))); if(!resp) THROW_OPENSSLEXCEPTION("Failed to parse TS response."); SCOPE(TS_VERIFY_CTX, ctx, TS_VERIFY_CTX_new()); ctx->flags = TS_VFY_NONCE|TS_VFY_VERSION; ctx->nonce = nonce.release(); if(TS_RESP_verify_response(ctx.get(), resp.get()) != 1) THROW_OPENSSLEXCEPTION("Failed to verify TS response."); d.reset(resp->token, function<void(PKCS7*)>(PKCS7_free)); resp->token = nullptr; }
void TS::verify(const Digest &digest) { if(!d) THROW_OPENSSLEXCEPTION("Failed to verify TS response."); vector<unsigned char> data = digest.result(); SCOPE(TS_VERIFY_CTX, ctx, TS_VERIFY_CTX_new()); ctx->flags = TS_VFY_IMPRINT|TS_VFY_VERSION|TS_VFY_SIGNATURE; ctx->imprint = data.data(); ctx->imprint_len = (unsigned int)data.size(); ctx->store = X509_STORE_new(); X509CertStore::instance()->activate(cert().issuerName("C")); for(const X509Cert &i: X509CertStore::instance()->certs()) X509_STORE_add_cert(ctx->store, i.handle()); OpenSSLException(); // Clear errors SCOPE(X509_STORE_CTX, csc, X509_STORE_CTX_new()); if (!csc) THROW_OPENSSLEXCEPTION("Failed to create X509_STORE_CTX"); if(!X509_STORE_CTX_init(csc.get(), ctx->store, 0, 0)) THROW_OPENSSLEXCEPTION("Failed to init X509_STORE_CTX"); X509_STORE_set_verify_cb_func(ctx->store, [](int ok, X509_STORE_CTX *ctx) -> int { switch(X509_STORE_CTX_get_error(ctx)) { case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: case X509_V_ERR_CERT_UNTRUSTED: { const vector<X509Cert> &list = X509CertStore::instance()->certs(); if(find(list.begin(), list.end(), X509Cert(ctx->current_cert)) != list.end()) return 1; return ok; } default: return ok; } }); int err = TS_RESP_verify_token(ctx.get(), d.get()); //Avoid CRYPTO_free ctx->imprint = nullptr; ctx->imprint_len = 0; if(err != 1) { long err = ERR_get_error(); if(ERR_GET_LIB(err) == 47 && ERR_GET_REASON(err) == TS_R_CERTIFICATE_VERIFY_ERROR) { Exception e(EXCEPTION_PARAMS("Certificate status: unknown")); e.setCode( Exception::CertificateUnknown ); throw e; } THROW_OPENSSLEXCEPTION("Failed to verify TS response."); } }
/** * 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); }