how to verify client certificates using boost::asio SSL?

Chirag Desai picture Chirag Desai · Jun 3, 2013 · Viewed 8.4k times · Source

Below is the code snippet for SSL context initialization and verify callback registered. If I connect SSL client with proper certificates it verifies the certificate and works as expected.

But if I connect client without any certificate then it allows connection(actually it should not allow connection without certificates). If SSL client do not send certificate then it do not call verify callback.

    boost::asio::ssl::context_base::method SSL_version =
            static_cast<boost::asio::ssl::context_base::method>(param_values[ID_PROTOCOL_VERSION].int32_value);

    // load certificate files
    boost::shared_ptr<boost::asio::ssl::context> context_ = boost::shared_ptr<boost::asio::ssl::context>(
            new boost::asio::ssl::context(SSL_version)); // parasoft-suppress BD-RES-LEAKS "The memory is allocated via boost::shared_ptr, hence it'll be deallocated automatically"

    p_ctx = boost::static_pointer_cast<void>(context_);

    context_->set_options(boost::asio::ssl::context::default_workarounds);

    context_->use_certificate_chain_file(cert_chain_file);
    context_->use_certificate_file(cert_file, boost::asio::ssl::context::pem);
    context_->use_private_key_file(cert_file, boost::asio::ssl::context::pem);

    context_->set_verify_mode(boost::asio::ssl::verify_peer);
    context_->set_verify_callback(boost::bind(&verify_certificate_cb, _1, _2));

verify_certificate_cb callback function

bool verify_certificate_cb(bool preverified, boost::asio::ssl::verify_context& ctx)
{
    std::cout << "Function : " << __func__ << " ----------------- Line : " << __LINE__ << std::endl;
    int8_t subject_name[256];
    X509_STORE_CTX *cts = ctx.native_handle();
    int32_t length = 0;
    X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
    std::cout << "CTX ERROR : " << cts->error << std::endl;

    int32_t depth = X509_STORE_CTX_get_error_depth(cts);
    std::cout << "CTX DEPTH : " << depth << std::endl;

    switch (cts->error)
    {
    case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
        Debug(PRIORITY_ERROR, "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT");
        break;
    case X509_V_ERR_CERT_NOT_YET_VALID:
    case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
        Debug(PRIORITY_ERROR, "Certificate not yet valid!!");
        break;
    case X509_V_ERR_CERT_HAS_EXPIRED:
    case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
        Debug(PRIORITY_ERROR, "Certificate expired..");
        break;
    case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
        Debug(PRIORITY_WARN, "Self signed certificate in chain!!!\n");
        preverified = true;
        break;
    default:
        break;
    }
    const int32_t name_length = 256;
    X509_NAME_oneline(X509_get_subject_name(cert), reinterpret_cast<char*>(subject_name), name_length);
    Debug(PRIORITY_INFO, "Verifying %s", subject_name);
    Debug(PRIORITY_INFO, "Verification status : %d", preverified);

    std::cout << "Function : " << __func__ << " ----------------- Line : " << __LINE__ << std::endl;
    return preverified;
}

How can I modify the code that do not allow connection without proper certificate files? Thanks in advance.!

Answer

Chirag Desai picture Chirag Desai · Jun 3, 2013

Finally got the solution. One of my teammate has suggested to use flag boost::asio::ssl::verify_fail_if_no_peer_cert in association with boost::asio::ssl::verify_peer and it worked.

updated line of code :

context_->set_verify_mode(boost::asio::ssl::verify_peer | boost::asio::ssl::verify_fail_if_no_peer_cert);