diff options
Diffstat (limited to 'src/manager/service/ocsp.cpp')
-rw-r--r-- | src/manager/service/ocsp.cpp | 667 |
1 files changed, 344 insertions, 323 deletions
diff --git a/src/manager/service/ocsp.cpp b/src/manager/service/ocsp.cpp index aa5fa968..25219fc4 100644 --- a/src/manager/service/ocsp.cpp +++ b/src/manager/service/ocsp.cpp @@ -39,350 +39,371 @@ namespace CKM { namespace { -typedef std::unique_ptr<BIO, std::function<void(BIO*)>> BioUniquePtr; +typedef std::unique_ptr<BIO, std::function<void(BIO *)>> BioUniquePtr; -void BIO_write_and_free(BIO* bio) +void BIO_write_and_free(BIO *bio) { - if (!bio) - return; + if (!bio) + return; - std::vector<char> message(1024); - int size = BIO_read(bio, message.data(), message.size()); - if (size > 0) { - message.resize(size); - LogError("OCSP error description:" << std::string(message.begin(), message.end())); - } + std::vector<char> message(1024); + int size = BIO_read(bio, message.data(), message.size()); - BIO_free_all(bio); + if (size > 0) { + message.resize(size); + LogError("OCSP error description:" << std::string(message.begin(), + message.end())); + } + + BIO_free_all(bio); } } // namespace anonymous OCSPModule::OCSPModule() { - // Do nothing. + // Do nothing. } OCSPModule::~OCSPModule() { - // Do nothing. + // Do nothing. } int OCSPModule::verify(const CertificateImplVector &certificateChain) { - bool unsupported = false; // ocsp is unsupported in certificate in chain (except root CA) - - // create trusted store - X509_STACK_PTR trustedCerts = create_x509_stack(); - - // skip first 2 certificates - for (auto it = certificateChain.cbegin() + 2; it < certificateChain.cend(); it++) { - if (it->empty()) { - LogError("Error. Broken certificate chain."); - return CKM_API_OCSP_STATUS_INTERNAL_ERROR; - } - sk_X509_push(trustedCerts.get(), it->getX509()); - } - - for (int i = 0; i < static_cast<int>(certificateChain.size()) - 1; i++) {// except root certificate - if (certificateChain[i].empty() || certificateChain[i+1].empty()) { - LogError("Error. Broken certificate chain."); - return CKM_API_OCSP_STATUS_INTERNAL_ERROR; - } - - X509 *cert = certificateChain[i].getX509(); - X509 *issuer = certificateChain[i+1].getX509(); - - std::string url = certificateChain[i].getOCSPURL(); - - if (url.empty()) { - LogError("Certificate in certchain[" << i << "] does not provide OCSP extension."); - unsupported = true; - continue; - } - - int result = ocsp_verify(cert, issuer, trustedCerts.get(), url); - // remove first element from trustedCerts store - sk_X509_delete(trustedCerts.get(), 0); - - if (result != CKM_API_OCSP_STATUS_GOOD) { - LogError("Fail to OCSP certification check. Errorcode=[" << result << - "], on certChain[" << i << "]"); - return result; - } - } - - if (unsupported) - return CKM_API_OCSP_STATUS_UNSUPPORTED; - - return CKM_API_OCSP_STATUS_GOOD; + bool unsupported = + false; // ocsp is unsupported in certificate in chain (except root CA) + + // create trusted store + X509_STACK_PTR trustedCerts = create_x509_stack(); + + // skip first 2 certificates + for (auto it = certificateChain.cbegin() + 2; it < certificateChain.cend(); + it++) { + if (it->empty()) { + LogError("Error. Broken certificate chain."); + return CKM_API_OCSP_STATUS_INTERNAL_ERROR; + } + + sk_X509_push(trustedCerts.get(), it->getX509()); + } + + for (int i = 0; i < static_cast<int>(certificateChain.size()) - 1; + i++) {// except root certificate + if (certificateChain[i].empty() || certificateChain[i + 1].empty()) { + LogError("Error. Broken certificate chain."); + return CKM_API_OCSP_STATUS_INTERNAL_ERROR; + } + + X509 *cert = certificateChain[i].getX509(); + X509 *issuer = certificateChain[i + 1].getX509(); + + std::string url = certificateChain[i].getOCSPURL(); + + if (url.empty()) { + LogError("Certificate in certchain[" << i << + "] does not provide OCSP extension."); + unsupported = true; + continue; + } + + int result = ocsp_verify(cert, issuer, trustedCerts.get(), url); + // remove first element from trustedCerts store + sk_X509_delete(trustedCerts.get(), 0); + + if (result != CKM_API_OCSP_STATUS_GOOD) { + LogError("Fail to OCSP certification check. Errorcode=[" << result << + "], on certChain[" << i << "]"); + return result; + } + } + + if (unsupported) + return CKM_API_OCSP_STATUS_UNSUPPORTED; + + return CKM_API_OCSP_STATUS_GOOD; } -int OCSPModule::ocsp_verify(X509 *cert, X509 *issuer, STACK_OF(X509) *trustedCerts, const std::string &constUrl) +int OCSPModule::ocsp_verify(X509 *cert, X509 *issuer, + STACK_OF(X509) *trustedCerts, const std::string &constUrl) { - OCSP_REQUEST *req = NULL; - OCSP_RESPONSE *resp = NULL; - OCSP_BASICRESP *bs = NULL; - OCSP_CERTID *certid = NULL; - BIO *cbio = NULL; - SSL_CTX *use_ssl_ctx = NULL; - char *host = NULL, *port = NULL, *path = NULL; - ASN1_GENERALIZEDTIME *rev = NULL; - ASN1_GENERALIZEDTIME *thisupd = NULL; - ASN1_GENERALIZEDTIME *nextupd = NULL; - int use_ssl = 0; - int ocspStatus = -1; - int i = 0; - long nsec = MAX_VALIDITY_PERIOD, maxage = -1; - char subj_buf[256]; - int reason = 0; - // const char *reason_str = NULL;0 - X509_STORE *trustedStore = NULL; - BioUniquePtr bioLogger(BIO_new(BIO_s_mem()), BIO_write_and_free); - - std::vector<char> url(constUrl.begin(), constUrl.end()); - url.push_back(0); - - if (!OCSP_parse_url(url.data(), &host, &port, &path, &use_ssl)) - /* report error */ - return CKM_API_OCSP_STATUS_INVALID_URL; - - LogDebug("Host: " << host); - LogDebug("Port: " << port); - LogDebug("Path: " << path); - LogDebug("Use_ssl: " << use_ssl); - - cbio = BIO_new_connect(host); - if (cbio == NULL) { - /*BIO_printf(bio_err, "Error creating connect BIO\n");*/ - /* report error */ - return CKM_API_OCSP_STATUS_INTERNAL_ERROR; - } - - if (port != NULL) - BIO_set_conn_port(cbio, port); - - if (use_ssl == 1) { - BIO *sbio = NULL; - use_ssl_ctx = SSL_CTX_new(SSLv23_client_method()); - if (use_ssl_ctx == NULL) { - /* report error */ - return CKM_API_OCSP_STATUS_INTERNAL_ERROR; - } - - SSL_CTX_set_mode(use_ssl_ctx, SSL_MODE_AUTO_RETRY); - sbio = BIO_new_ssl(use_ssl_ctx, 1); - if (sbio == NULL) { - /* report error */ - return CKM_API_OCSP_STATUS_INTERNAL_ERROR; - } - - cbio = BIO_push(sbio, cbio); - if (cbio == NULL) { - /* report error */ - return CKM_API_OCSP_STATUS_INTERNAL_ERROR; - } - } - - if (BIO_do_connect(cbio) <= 0) { - LogDebug("Error in BIO_do_connect."); - ERR_print_errors(bioLogger.get()); - /* report error */ - - /* free stuff */ - if (host != NULL) - OPENSSL_free(host); - - if (port != NULL) - OPENSSL_free(port); - - if (path != NULL) - OPENSSL_free(path); - - host = port = path = NULL; - - if (use_ssl && use_ssl_ctx) - SSL_CTX_free(use_ssl_ctx); - - use_ssl_ctx = NULL; - - if (cbio != NULL) - BIO_free_all(cbio); - - cbio = NULL; - - return CKM_API_OCSP_STATUS_NET_ERROR; - } - - req = OCSP_REQUEST_new(); - if (req == NULL) { - LogDebug("Error in OCPS_REQUEST_new"); - return CKM_API_OCSP_STATUS_INTERNAL_ERROR; - } - - certid = OCSP_cert_to_id(NULL, cert, issuer); - if (certid == NULL) { - LogDebug("Error in OCSP_cert_to_id"); - return CKM_API_OCSP_STATUS_INTERNAL_ERROR; - } - - if (OCSP_request_add0_id(req, certid) == NULL) { - LogDebug("Error in OCSP_request_add0_id"); - return CKM_API_OCSP_STATUS_INTERNAL_ERROR; - } - - resp = OCSP_sendreq_bio(cbio, path, req); - /* free some stuff we no longer need */ - if (host != NULL) - OPENSSL_free(host); - - if (port != NULL) - OPENSSL_free(port); - - if (path != NULL) - OPENSSL_free(path); - - host = port = path = NULL; - - if (use_ssl && use_ssl_ctx) - SSL_CTX_free(use_ssl_ctx); - - use_ssl_ctx = NULL; - - if (cbio != NULL) - BIO_free_all(cbio); - - cbio = NULL; - - if (!resp) { - /*BIO_printf(bio_err, "Error querying OCSP responsder\n");*/ - /* report error */ - /* free stuff */ - OCSP_REQUEST_free(req); - return CKM_API_OCSP_STATUS_NET_ERROR; - } - - i = OCSP_response_status(resp); - - if (i != OCSP_RESPONSE_STATUS_SUCCESSFUL) { - /* report error */ - ERR_print_errors(bioLogger.get()); - /* free stuff */ - OCSP_REQUEST_free(req); - OCSP_RESPONSE_free(resp); - return CKM_API_OCSP_STATUS_REMOTE_ERROR; - } - - bs = OCSP_response_get1_basic(resp); - if (!bs) { - /* report error */ - ERR_print_errors(bioLogger.get()); - /* free stuff */ - OCSP_REQUEST_free(req); - OCSP_RESPONSE_free(resp); - - LogDebug("Error in OCSP_response_get1_basic"); - return CKM_API_OCSP_STATUS_INVALID_RESPONSE; - } - - if (trustedCerts != NULL) { - trustedStore = X509_STORE_new(); - - for (int tmpIdx = 0; tmpIdx < sk_X509_num(trustedCerts); tmpIdx++) - X509_STORE_add_cert(trustedStore, sk_X509_value(trustedCerts, tmpIdx)); - - X509_STORE_add_cert(trustedStore, issuer); - } - - int response = OCSP_basic_verify(bs, NULL, trustedStore, 0); - if (response <= 0) { - OCSP_REQUEST_free(req); - OCSP_RESPONSE_free(resp); - OCSP_BASICRESP_free(bs); - X509_STORE_free(trustedStore); - ERR_print_errors(bioLogger.get()); - return CKM_API_OCSP_STATUS_INVALID_RESPONSE; - } - - if ((i = OCSP_check_nonce(req, bs)) <= 0) { - if (i == -1) { - ERR_print_errors(bioLogger.get()); - } else { - /* report error */ - ERR_print_errors(bioLogger.get()); - /* free stuff */ - OCSP_REQUEST_free(req); - OCSP_RESPONSE_free(resp); - OCSP_BASICRESP_free(bs); - X509_STORE_free(trustedStore); - LogDebug("Error in OCSP_check_nonce"); - return CKM_API_OCSP_STATUS_INVALID_RESPONSE; - } - } - - (void)X509_NAME_oneline(X509_get_subject_name(cert), subj_buf, 255); - if (!OCSP_resp_find_status(bs, certid, &ocspStatus, &reason, - &rev, &thisupd, &nextupd)) { - /* report error */ - ERR_print_errors(bioLogger.get()); - /* free stuff */ - OCSP_RESPONSE_free(resp); - OCSP_REQUEST_free(req); - OCSP_BASICRESP_free(bs); - X509_STORE_free(trustedStore); - - LogDebug("Error in OCSP_resp_find_status"); - return CKM_API_OCSP_STATUS_INVALID_RESPONSE; - } - - - /* Check validity: if invalid write to output BIO so we - * know which response this refers to. - */ - if (!OCSP_check_validity(thisupd, nextupd, nsec, maxage)) { - /* report error */ - ERR_print_errors(bioLogger.get()); - /* free stuff */ - OCSP_REQUEST_free(req); - OCSP_RESPONSE_free(resp); - OCSP_BASICRESP_free(bs); - X509_STORE_free(trustedStore); - - LogDebug("Error in OCSP_check_validity"); - return CKM_API_OCSP_STATUS_INVALID_RESPONSE; - } - - if (req != NULL) { - OCSP_REQUEST_free(req); - req = NULL; - } - - if (resp != NULL) { - OCSP_RESPONSE_free(resp); - resp = NULL; - } - - if (bs != NULL) { - OCSP_BASICRESP_free(bs); - bs = NULL; - } - - if (trustedStore != NULL) { - X509_STORE_free(trustedStore); - trustedStore = NULL; - } - - switch (ocspStatus) { - case V_OCSP_CERTSTATUS_GOOD: - return CKM_API_OCSP_STATUS_GOOD; - case V_OCSP_CERTSTATUS_REVOKED: - return CKM_API_OCSP_STATUS_REVOKED; - case V_OCSP_CERTSTATUS_UNKNOWN: - return CKM_API_OCSP_STATUS_UNKNOWN; - default: - LogError("Internal openssl error: Certificate status have value is out of bound."); - return CKM_API_OCSP_STATUS_INTERNAL_ERROR; - } + OCSP_REQUEST *req = NULL; + OCSP_RESPONSE *resp = NULL; + OCSP_BASICRESP *bs = NULL; + OCSP_CERTID *certid = NULL; + BIO *cbio = NULL; + SSL_CTX *use_ssl_ctx = NULL; + char *host = NULL, *port = NULL, *path = NULL; + ASN1_GENERALIZEDTIME *rev = NULL; + ASN1_GENERALIZEDTIME *thisupd = NULL; + ASN1_GENERALIZEDTIME *nextupd = NULL; + int use_ssl = 0; + int ocspStatus = -1; + int i = 0; + long nsec = MAX_VALIDITY_PERIOD, maxage = -1; + char subj_buf[256]; + int reason = 0; + // const char *reason_str = NULL;0 + X509_STORE *trustedStore = NULL; + BioUniquePtr bioLogger(BIO_new(BIO_s_mem()), BIO_write_and_free); + + std::vector<char> url(constUrl.begin(), constUrl.end()); + url.push_back(0); + + if (!OCSP_parse_url(url.data(), &host, &port, &path, &use_ssl)) + /* report error */ + return CKM_API_OCSP_STATUS_INVALID_URL; + + LogDebug("Host: " << host); + LogDebug("Port: " << port); + LogDebug("Path: " << path); + LogDebug("Use_ssl: " << use_ssl); + + cbio = BIO_new_connect(host); + + if (cbio == NULL) { + /*BIO_printf(bio_err, "Error creating connect BIO\n");*/ + /* report error */ + return CKM_API_OCSP_STATUS_INTERNAL_ERROR; + } + + if (port != NULL) + BIO_set_conn_port(cbio, port); + + if (use_ssl == 1) { + BIO *sbio = NULL; + use_ssl_ctx = SSL_CTX_new(SSLv23_client_method()); + + if (use_ssl_ctx == NULL) { + /* report error */ + return CKM_API_OCSP_STATUS_INTERNAL_ERROR; + } + + SSL_CTX_set_mode(use_ssl_ctx, SSL_MODE_AUTO_RETRY); + sbio = BIO_new_ssl(use_ssl_ctx, 1); + + if (sbio == NULL) { + /* report error */ + return CKM_API_OCSP_STATUS_INTERNAL_ERROR; + } + + cbio = BIO_push(sbio, cbio); + + if (cbio == NULL) { + /* report error */ + return CKM_API_OCSP_STATUS_INTERNAL_ERROR; + } + } + + if (BIO_do_connect(cbio) <= 0) { + LogDebug("Error in BIO_do_connect."); + ERR_print_errors(bioLogger.get()); + /* report error */ + + /* free stuff */ + if (host != NULL) + OPENSSL_free(host); + + if (port != NULL) + OPENSSL_free(port); + + if (path != NULL) + OPENSSL_free(path); + + host = port = path = NULL; + + if (use_ssl && use_ssl_ctx) + SSL_CTX_free(use_ssl_ctx); + + use_ssl_ctx = NULL; + + if (cbio != NULL) + BIO_free_all(cbio); + + cbio = NULL; + + return CKM_API_OCSP_STATUS_NET_ERROR; + } + + req = OCSP_REQUEST_new(); + + if (req == NULL) { + LogDebug("Error in OCPS_REQUEST_new"); + return CKM_API_OCSP_STATUS_INTERNAL_ERROR; + } + + certid = OCSP_cert_to_id(NULL, cert, issuer); + + if (certid == NULL) { + LogDebug("Error in OCSP_cert_to_id"); + return CKM_API_OCSP_STATUS_INTERNAL_ERROR; + } + + if (OCSP_request_add0_id(req, certid) == NULL) { + LogDebug("Error in OCSP_request_add0_id"); + return CKM_API_OCSP_STATUS_INTERNAL_ERROR; + } + + resp = OCSP_sendreq_bio(cbio, path, req); + + /* free some stuff we no longer need */ + if (host != NULL) + OPENSSL_free(host); + + if (port != NULL) + OPENSSL_free(port); + + if (path != NULL) + OPENSSL_free(path); + + host = port = path = NULL; + + if (use_ssl && use_ssl_ctx) + SSL_CTX_free(use_ssl_ctx); + + use_ssl_ctx = NULL; + + if (cbio != NULL) + BIO_free_all(cbio); + + cbio = NULL; + + if (!resp) { + /*BIO_printf(bio_err, "Error querying OCSP responsder\n");*/ + /* report error */ + /* free stuff */ + OCSP_REQUEST_free(req); + return CKM_API_OCSP_STATUS_NET_ERROR; + } + + i = OCSP_response_status(resp); + + if (i != OCSP_RESPONSE_STATUS_SUCCESSFUL) { + /* report error */ + ERR_print_errors(bioLogger.get()); + /* free stuff */ + OCSP_REQUEST_free(req); + OCSP_RESPONSE_free(resp); + return CKM_API_OCSP_STATUS_REMOTE_ERROR; + } + + bs = OCSP_response_get1_basic(resp); + + if (!bs) { + /* report error */ + ERR_print_errors(bioLogger.get()); + /* free stuff */ + OCSP_REQUEST_free(req); + OCSP_RESPONSE_free(resp); + + LogDebug("Error in OCSP_response_get1_basic"); + return CKM_API_OCSP_STATUS_INVALID_RESPONSE; + } + + if (trustedCerts != NULL) { + trustedStore = X509_STORE_new(); + + for (int tmpIdx = 0; tmpIdx < sk_X509_num(trustedCerts); tmpIdx++) + X509_STORE_add_cert(trustedStore, sk_X509_value(trustedCerts, tmpIdx)); + + X509_STORE_add_cert(trustedStore, issuer); + } + + int response = OCSP_basic_verify(bs, NULL, trustedStore, 0); + + if (response <= 0) { + OCSP_REQUEST_free(req); + OCSP_RESPONSE_free(resp); + OCSP_BASICRESP_free(bs); + X509_STORE_free(trustedStore); + ERR_print_errors(bioLogger.get()); + return CKM_API_OCSP_STATUS_INVALID_RESPONSE; + } + + if ((i = OCSP_check_nonce(req, bs)) <= 0) { + if (i == -1) { + ERR_print_errors(bioLogger.get()); + } else { + /* report error */ + ERR_print_errors(bioLogger.get()); + /* free stuff */ + OCSP_REQUEST_free(req); + OCSP_RESPONSE_free(resp); + OCSP_BASICRESP_free(bs); + X509_STORE_free(trustedStore); + LogDebug("Error in OCSP_check_nonce"); + return CKM_API_OCSP_STATUS_INVALID_RESPONSE; + } + } + + (void)X509_NAME_oneline(X509_get_subject_name(cert), subj_buf, 255); + + if (!OCSP_resp_find_status(bs, certid, &ocspStatus, &reason, + &rev, &thisupd, &nextupd)) { + /* report error */ + ERR_print_errors(bioLogger.get()); + /* free stuff */ + OCSP_RESPONSE_free(resp); + OCSP_REQUEST_free(req); + OCSP_BASICRESP_free(bs); + X509_STORE_free(trustedStore); + + LogDebug("Error in OCSP_resp_find_status"); + return CKM_API_OCSP_STATUS_INVALID_RESPONSE; + } + + + /* Check validity: if invalid write to output BIO so we + * know which response this refers to. + */ + if (!OCSP_check_validity(thisupd, nextupd, nsec, maxage)) { + /* report error */ + ERR_print_errors(bioLogger.get()); + /* free stuff */ + OCSP_REQUEST_free(req); + OCSP_RESPONSE_free(resp); + OCSP_BASICRESP_free(bs); + X509_STORE_free(trustedStore); + + LogDebug("Error in OCSP_check_validity"); + return CKM_API_OCSP_STATUS_INVALID_RESPONSE; + } + + if (req != NULL) { + OCSP_REQUEST_free(req); + req = NULL; + } + + if (resp != NULL) { + OCSP_RESPONSE_free(resp); + resp = NULL; + } + + if (bs != NULL) { + OCSP_BASICRESP_free(bs); + bs = NULL; + } + + if (trustedStore != NULL) { + X509_STORE_free(trustedStore); + trustedStore = NULL; + } + + switch (ocspStatus) { + case V_OCSP_CERTSTATUS_GOOD: + return CKM_API_OCSP_STATUS_GOOD; + + case V_OCSP_CERTSTATUS_REVOKED: + return CKM_API_OCSP_STATUS_REVOKED; + + case V_OCSP_CERTSTATUS_UNKNOWN: + return CKM_API_OCSP_STATUS_UNKNOWN; + + default: + LogError("Internal openssl error: Certificate status have value is out of bound."); + return CKM_API_OCSP_STATUS_INTERNAL_ERROR; + } } } // namespace CKM |