bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) const { merchant.clear(); if (!IsInitialized()) return false; // One day we'll support more PKI types, but just // x509 for now: const EVP_MD* digestAlgorithm = NULL; if (paymentRequest.pki_type() == "x509+sha256") { digestAlgorithm = EVP_sha256(); } else if (paymentRequest.pki_type() == "x509+sha1") { digestAlgorithm = EVP_sha1(); } else if (paymentRequest.pki_type() == "none") { qDebug() << "PaymentRequestPlus::getMerchant : Payment request: pki_type == none"; return false; } else { qDebug() << "PaymentRequestPlus::getMerchant : Payment request: unknown pki_type " << QString::fromStdString(paymentRequest.pki_type()); return false; } payments::X509Certificates certChain; if (!certChain.ParseFromString(paymentRequest.pki_data())) { qDebug() << "PaymentRequestPlus::getMerchant : Payment request: error parsing pki_data"; return false; } std::vector<X509*> certs; const QDateTime currentTime = QDateTime::currentDateTime(); for (int i = 0; i < certChain.certificate_size(); i++) { QByteArray certData(certChain.certificate(i).data(), certChain.certificate(i).size()); QSslCertificate qCert(certData, QSsl::Der); if (currentTime < qCert.effectiveDate() || currentTime > qCert.expiryDate()) { qDebug() << "PaymentRequestPlus::getMerchant : Payment request: certificate expired or not yet active: " << qCert; return false; } #if QT_VERSION >= 0x050000 if (qCert.isBlacklisted()) { qDebug() << "PaymentRequestPlus::getMerchant : Payment request: certificate blacklisted: " << qCert; return false; } #endif const unsigned char *data = (const unsigned char *)certChain.certificate(i).data(); X509 *cert = d2i_X509(NULL, &data, certChain.certificate(i).size()); if (cert) certs.push_back(cert); } if (certs.empty()) { qDebug() << "PaymentRequestPlus::getMerchant : Payment request: empty certificate chain"; return false; } // The first cert is the signing cert, the rest are untrusted certs that chain // to a valid root authority. OpenSSL needs them separately. STACK_OF(X509) *chain = sk_X509_new_null(); for (int i = certs.size()-1; i > 0; i--) { sk_X509_push(chain, certs[i]); } X509 *signing_cert = certs[0]; // Now create a "store context", which is a single use object for checking, // load the signing cert into it and verify. X509_STORE_CTX *store_ctx = X509_STORE_CTX_new(); if (!store_ctx) { qDebug() << "PaymentRequestPlus::getMerchant : Payment request: error creating X509_STORE_CTX"; return false; } char *website = NULL; bool fResult = true; try { if (!X509_STORE_CTX_init(store_ctx, certStore, signing_cert, chain)) { int error = X509_STORE_CTX_get_error(store_ctx); throw SSLVerifyError(X509_verify_cert_error_string(error)); } // Now do the verification! int result = X509_verify_cert(store_ctx); if (result != 1) { int error = X509_STORE_CTX_get_error(store_ctx); throw SSLVerifyError(X509_verify_cert_error_string(error)); } X509_NAME *certname = X509_get_subject_name(signing_cert); // Valid cert; check signature: payments::PaymentRequest rcopy(paymentRequest); // Copy rcopy.set_signature(std::string("")); std::string data_to_verify; // Everything but the signature rcopy.SerializeToString(&data_to_verify); EVP_MD_CTX ctx; EVP_PKEY *pubkey = X509_get_pubkey(signing_cert); EVP_MD_CTX_init(&ctx); if (!EVP_VerifyInit_ex(&ctx, digestAlgorithm, NULL) || !EVP_VerifyUpdate(&ctx, data_to_verify.data(), data_to_verify.size()) || !EVP_VerifyFinal(&ctx, (const unsigned char*)paymentRequest.signature().data(), paymentRequest.signature().size(), pubkey)) { throw SSLVerifyError("Bad signature, invalid PaymentRequest."); } // OpenSSL API for getting human printable strings from certs is baroque. int textlen = X509_NAME_get_text_by_NID(certname, NID_commonName, NULL, 0); website = new char[textlen + 1]; if (X509_NAME_get_text_by_NID(certname, NID_commonName, website, textlen + 1) == textlen && textlen > 0) { merchant = website; } else { throw SSLVerifyError("Bad certificate, missing common name."); } // TODO: detect EV certificates and set merchant = business name instead of unfriendly NID_commonName ? } catch (SSLVerifyError& err) { fResult = false; qDebug() << "PaymentRequestPlus::getMerchant : SSL error: " << err.what(); } if (website) delete[] website; X509_STORE_CTX_free(store_ctx); for (unsigned int i = 0; i < certs.size(); i++) X509_free(certs[i]); return fResult; }
int MS_CALLBACK verify_callback(int ok, X509_STORE_CTX *ctx) { X509 *err_cert; int err,depth; err_cert=X509_STORE_CTX_get_current_cert(ctx); err= X509_STORE_CTX_get_error(ctx); depth= X509_STORE_CTX_get_error_depth(ctx); BIO_printf(bio_err,"depth=%d ",depth); if (err_cert) { X509_NAME_print_ex(bio_err, X509_get_subject_name(err_cert), 0, XN_FLAG_ONELINE); BIO_puts(bio_err, "\n"); } else BIO_puts(bio_err, "<no cert>\n"); if (!ok) { BIO_printf(bio_err,"verify error:num=%d:%s\n",err, X509_verify_cert_error_string(err)); if (verify_depth >= depth) { if (!verify_return_error) ok=1; verify_error=X509_V_OK; } else { ok=0; verify_error=X509_V_ERR_CERT_CHAIN_TOO_LONG; } } switch (err) { case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: BIO_puts(bio_err,"issuer= "); X509_NAME_print_ex(bio_err, X509_get_issuer_name(err_cert), 0, XN_FLAG_ONELINE); BIO_puts(bio_err, "\n"); break; case X509_V_ERR_CERT_NOT_YET_VALID: case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: BIO_printf(bio_err,"notBefore="); ASN1_TIME_print(bio_err,X509_get_notBefore(err_cert)); BIO_printf(bio_err,"\n"); break; case X509_V_ERR_CERT_HAS_EXPIRED: case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: BIO_printf(bio_err,"notAfter="); ASN1_TIME_print(bio_err,X509_get_notAfter(err_cert)); BIO_printf(bio_err,"\n"); break; case X509_V_ERR_NO_EXPLICIT_POLICY: policies_print(bio_err, ctx); break; } if (err == X509_V_OK && ok == 2) policies_print(bio_err, ctx); BIO_printf(bio_err,"verify return:%d\n",ok); return(ok); }
int CZNCSock::VerifyPeerCertificate(int iPreVerify, X509_STORE_CTX * pStoreCTX) { if (iPreVerify == 0) { m_ssCertVerificationErrors.insert(X509_verify_cert_error_string(X509_STORE_CTX_get_error(pStoreCTX))); } return 1; }
/* This callback is called during each verification process, at each step during the chain of certificates (this function is not the certificate_verification one!). */ int verify_callback(int pre_verify_ok, X509_STORE_CTX *ctx) { char buf[256]; X509 *err_cert; int err, depth; depth = X509_STORE_CTX_get_error_depth(ctx); LM_NOTICE("depth = %d\n",depth); if ( depth > VERIFY_DEPTH_S ) { LM_NOTICE("cert chain too long ( depth > VERIFY_DEPTH_S)\n"); pre_verify_ok=0; } if( pre_verify_ok ) { LM_NOTICE("preverify is good: verify return: %d\n", pre_verify_ok); return pre_verify_ok; } err_cert = X509_STORE_CTX_get_current_cert(ctx); err = X509_STORE_CTX_get_error(ctx); X509_NAME_oneline(X509_get_subject_name(err_cert),buf,sizeof buf); LM_NOTICE("subject = %s\n", buf); LM_NOTICE("verify error:num=%d:%s\n", err, X509_verify_cert_error_string(err)); LM_NOTICE("error code is %d\n", ctx->error); switch (ctx->error) { case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf,sizeof buf); LM_NOTICE("issuer= %s\n",buf); break; case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: case X509_V_ERR_CERT_NOT_YET_VALID: LM_NOTICE("notBefore\n"); break; case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: case X509_V_ERR_CERT_HAS_EXPIRED: LM_NOTICE("notAfter\n"); break; case X509_V_ERR_CERT_SIGNATURE_FAILURE: case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: LM_NOTICE("unable to decrypt cert " "signature\n"); break; case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: LM_NOTICE("unable to decode issuer " "public key\n"); break; case X509_V_ERR_OUT_OF_MEM: LM_NOTICE("out of memory \n"); break; case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: LM_NOTICE("Self signed certificate " "issue\n"); break; case X509_V_ERR_CERT_CHAIN_TOO_LONG: LM_NOTICE("certificate chain too long\n"); break; case X509_V_ERR_INVALID_CA: LM_NOTICE("invalid CA\n"); break; case X509_V_ERR_PATH_LENGTH_EXCEEDED: LM_NOTICE("path length exceeded\n"); break; case X509_V_ERR_INVALID_PURPOSE: LM_NOTICE("invalid purpose\n"); break; case X509_V_ERR_CERT_UNTRUSTED: LM_NOTICE("certificate untrusted\n"); break; case X509_V_ERR_CERT_REJECTED: LM_NOTICE("certificate rejected\n"); break; default: LM_NOTICE("something wrong with the cert" " ... error code is %d (check x509_vfy.h)\n", ctx->error); break; } LM_NOTICE("verify return:%d\n", pre_verify_ok); return(pre_verify_ok); }
static int verifyPeerCertificate(int ok, X509_STORE_CTX *xContext) { X509 *cert; SSL *handle; OpenSocket *osp; MprSocket *sp; MprSsl *ssl; char subject[512], issuer[512], peerName[512]; int error, depth; subject[0] = issuer[0] = '\0'; handle = (SSL*) X509_STORE_CTX_get_app_data(xContext); osp = (OpenSocket*) SSL_get_app_data(handle); sp = osp->sock; ssl = sp->ssl; cert = X509_STORE_CTX_get_current_cert(xContext); depth = X509_STORE_CTX_get_error_depth(xContext); error = X509_STORE_CTX_get_error(xContext); ok = 1; if (X509_NAME_oneline(X509_get_subject_name(cert), subject, sizeof(subject) - 1) < 0) { sp->errorMsg = sclone("Cannot get subject name"); ok = 0; } if (X509_NAME_oneline(X509_get_issuer_name(cert), issuer, sizeof(issuer) - 1) < 0) { sp->errorMsg = sclone("Cannot get issuer name"); ok = 0; } if (X509_NAME_get_text_by_NID(X509_get_subject_name(cert), NID_commonName, peerName, sizeof(peerName) - 1) == 0) { sp->errorMsg = sclone("Cannot get peer name"); ok = 0; } if (ok && ssl->verifyDepth < depth) { if (error == 0) { error = X509_V_ERR_CERT_CHAIN_TOO_LONG; } } switch (error) { case X509_V_OK: break; case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: /* Normal self signed certificate */ if (ssl->verifyIssuer) { sp->errorMsg = sclone("Self-signed certificate"); ok = 0; } break; case X509_V_ERR_CERT_UNTRUSTED: case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: if (ssl->verifyIssuer) { /* Issuer cannot be verified */ sp->errorMsg = sclone("Certificate not trusted"); ok = 0; } break; case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: if (ssl->verifyIssuer) { /* Issuer cannot be verified */ sp->errorMsg = sclone("Certificate not trusted"); ok = 0; } break; case X509_V_ERR_CERT_HAS_EXPIRED: sp->errorMsg = sfmt("Certificate has expired"); ok = 0; break; case X509_V_ERR_CERT_CHAIN_TOO_LONG: case X509_V_ERR_CERT_NOT_YET_VALID: case X509_V_ERR_CERT_REJECTED: case X509_V_ERR_CERT_SIGNATURE_FAILURE: case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: case X509_V_ERR_INVALID_CA: default: sp->errorMsg = sfmt("Certificate verification error %d", error); ok = 0; break; } return ok; }
/** * xmlSecOpenSSLX509StoreVerify: * @store: the pointer to X509 key data store klass. * @certs: the untrusted certificates stack. * @crls: the crls stack. * @keyInfoCtx: the pointer to <dsig:KeyInfo/> element processing context. * * Verifies @certs list. * * Returns: pointer to the first verified certificate from @certs. */ X509* xmlSecOpenSSLX509StoreVerify(xmlSecKeyDataStorePtr store, XMLSEC_STACK_OF_X509* certs, XMLSEC_STACK_OF_X509_CRL* crls, xmlSecKeyInfoCtx* keyInfoCtx) { xmlSecOpenSSLX509StoreCtxPtr ctx; STACK_OF(X509)* certs2 = NULL; STACK_OF(X509_CRL)* crls2 = NULL; X509 * res = NULL; X509 * cert; X509 * err_cert = NULL; char buf[256]; int err = 0, depth; int i; int ret; xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecOpenSSLX509StoreId), NULL); xmlSecAssert2(certs != NULL, NULL); xmlSecAssert2(keyInfoCtx != NULL, NULL); ctx = xmlSecOpenSSLX509StoreGetCtx(store); xmlSecAssert2(ctx != NULL, NULL); xmlSecAssert2(ctx->xst != NULL, NULL); /* dup certs */ certs2 = sk_X509_dup(certs); if(certs2 == NULL) { xmlSecError(XMLSEC_ERRORS_HERE, xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), "sk_X509_dup", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } /* add untrusted certs from the store */ if(ctx->untrusted != NULL) { for(i = 0; i < sk_X509_num(ctx->untrusted); ++i) { ret = sk_X509_push(certs2, sk_X509_value(ctx->untrusted, i)); if(ret < 1) { xmlSecError(XMLSEC_ERRORS_HERE, xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), "sk_X509_push", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } } } /* dup crls but remove all non-verified */ if(crls != NULL) { crls2 = sk_X509_CRL_dup(crls); if(crls2 == NULL) { xmlSecError(XMLSEC_ERRORS_HERE, xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), "sk_X509_CRL_dup", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } for(i = 0; i < sk_X509_CRL_num(crls2); ) { ret = xmlSecOpenSSLX509VerifyCRL(ctx->xst, sk_X509_CRL_value(crls2, i)); if(ret == 1) { ++i; } else if(ret == 0) { (void)sk_X509_CRL_delete(crls2, i); } else { xmlSecError(XMLSEC_ERRORS_HERE, xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), "xmlSecOpenSSLX509VerifyCRL", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } } } /* remove all revoked certs */ for(i = 0; i < sk_X509_num(certs2);) { cert = sk_X509_value(certs2, i); if(crls2 != NULL) { ret = xmlSecOpenSSLX509VerifyCertAgainstCrls(crls2, cert); if(ret == 0) { (void)sk_X509_delete(certs2, i); continue; } else if(ret != 1) { xmlSecError(XMLSEC_ERRORS_HERE, xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), "xmlSecOpenSSLX509VerifyCertAgainstCrls", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } } if(ctx->crls != NULL) { ret = xmlSecOpenSSLX509VerifyCertAgainstCrls(ctx->crls, cert); if(ret == 0) { (void)sk_X509_delete(certs2, i); continue; } else if(ret != 1) { xmlSecError(XMLSEC_ERRORS_HERE, xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), "xmlSecOpenSSLX509VerifyCertAgainstCrls", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } } ++i; } /* get one cert after another and try to verify */ for(i = 0; i < sk_X509_num(certs2); ++i) { cert = sk_X509_value(certs2, i); if(xmlSecOpenSSLX509FindNextChainCert(certs2, cert) == NULL) { X509_STORE_CTX xsc; #if !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097) X509_VERIFY_PARAM * vpm = NULL; unsigned long vpm_flags = 0; vpm = X509_VERIFY_PARAM_new(); if(vpm == NULL) { xmlSecError(XMLSEC_ERRORS_HERE, xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), "X509_VERIFY_PARAM_new", XMLSEC_ERRORS_R_CRYPTO_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } vpm_flags = vpm->flags; /* vpm_flags &= (~X509_V_FLAG_X509_STRICT); */ vpm_flags &= (~X509_V_FLAG_CRL_CHECK); X509_VERIFY_PARAM_set_depth(vpm, 9); X509_VERIFY_PARAM_set_flags(vpm, vpm_flags); #endif /* !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097) */ X509_STORE_CTX_init (&xsc, ctx->xst, cert, certs2); if(keyInfoCtx->certsVerificationTime > 0) { #if !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097) vpm_flags |= X509_V_FLAG_USE_CHECK_TIME; X509_VERIFY_PARAM_set_time(vpm, keyInfoCtx->certsVerificationTime); #endif /* !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097) */ X509_STORE_CTX_set_time(&xsc, 0, keyInfoCtx->certsVerificationTime); } #if !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097) X509_STORE_CTX_set0_param(&xsc, vpm); #endif /* !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097) */ ret = X509_verify_cert(&xsc); err_cert = X509_STORE_CTX_get_current_cert(&xsc); err = X509_STORE_CTX_get_error(&xsc); depth = X509_STORE_CTX_get_error_depth(&xsc); X509_STORE_CTX_cleanup (&xsc); if(ret == 1) { res = cert; goto done; } else if(ret < 0) { const char* err_msg; buf[0] = '\0'; X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof buf); err_msg = X509_verify_cert_error_string(err); xmlSecError(XMLSEC_ERRORS_HERE, xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), "X509_verify_cert", XMLSEC_ERRORS_R_CRYPTO_FAILED, "subj=%s;err=%d;msg=%s", xmlSecErrorsSafeString(buf), err, xmlSecErrorsSafeString(err_msg)); goto done; } else if(ret == 0) { const char* err_msg; buf[0] = '\0'; X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof buf); err_msg = X509_verify_cert_error_string(err); xmlSecError(XMLSEC_ERRORS_HERE, xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), "X509_verify_cert", XMLSEC_ERRORS_R_CRYPTO_FAILED, "subj=%s;err=%d;msg=%s", xmlSecErrorsSafeString(buf), err, xmlSecErrorsSafeString(err_msg)); } } } /* if we came here then we found nothing. do we have any error? */ if((err != 0) && (err_cert != NULL)) { const char* err_msg; err_msg = X509_verify_cert_error_string(err); switch (err) { case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: X509_NAME_oneline(X509_get_issuer_name(err_cert), buf, sizeof buf); xmlSecError(XMLSEC_ERRORS_HERE, xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), NULL, XMLSEC_ERRORS_R_CERT_ISSUER_FAILED, "err=%d;msg=%s;issuer=%s", err, xmlSecErrorsSafeString(err_msg), xmlSecErrorsSafeString(buf)); break; case X509_V_ERR_CERT_NOT_YET_VALID: case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: xmlSecError(XMLSEC_ERRORS_HERE, xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), NULL, XMLSEC_ERRORS_R_CERT_NOT_YET_VALID, "err=%d;msg=%s", err, xmlSecErrorsSafeString(err_msg)); break; case X509_V_ERR_CERT_HAS_EXPIRED: case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: xmlSecError(XMLSEC_ERRORS_HERE, xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), NULL, XMLSEC_ERRORS_R_CERT_HAS_EXPIRED, "err=%d;msg=%s", err, xmlSecErrorsSafeString(err_msg)); break; default: xmlSecError(XMLSEC_ERRORS_HERE, xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), NULL, XMLSEC_ERRORS_R_CERT_VERIFY_FAILED, "err=%d;msg=%s", err, xmlSecErrorsSafeString(err_msg)); } } done: if(certs2 != NULL) { sk_X509_free(certs2); } if(crls2 != NULL) { sk_X509_CRL_free(crls2); } return(res); }