inline int opensslVerifyClientCertCallback()

in host/cxpslib/cxpssslcontext.h [386:562]


inline int opensslVerifyClientCertCallback(int preverifyOk, X509_STORE_CTX* ctx)
{
#ifdef CXPS_x64
    USES_CONVERSION;
    HCERTSTORE                      hStore = NULL;
    PCCERT_CONTEXT                  pCertContext = NULL;

    X509* cert  = X509_STORE_CTX_get_current_cert(ctx);
    if (0 == cert) {
        CXPS_LOG_ERROR(AT_LOC<<"cert verfication failed as current cert not present");
        return preverifyOk;
    }

    SSL* ssl = static_cast<SSL*>(X509_STORE_CTX_get_ex_data(ctx, 
        SSL_get_ex_data_X509_STORE_CTX_idx()));

    if (0 == ssl)
    {
        CXPS_LOG_ERROR(AT_LOC<<"ssl details fetch failed");
        return preverifyOk;
    }

    SSL_CTX* sslCtx = ::SSL_get_SSL_CTX(ssl);
    if (0 == sslCtx)
    {
        CXPS_LOG_ERROR(AT_LOC<<"ssl context from ssl failed");
        return preverifyOk;
    }

    if (!SSL_CTX_get_ex_data(sslCtx, 1))
    {
        CXPS_LOG_ERROR(AT_LOC<<"ssl ex_data fetch failed");
        return preverifyOk;
    }
    std::string fingerprint = g_fingerprintMgr.getFingerprint(cert);
    char subject_name[256];
    X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256);

    CXPS_LOG_MONITOR(MONITOR_LOG_LEVEL_2, AT_LOC<<
        "client cert name=" << subject_name << ", fingerprint=" << fingerprint);

    if (X509_cmp_time(X509_get_notAfter(cert), 0) <= 0) 
    {
        CXPS_LOG_ERROR(AT_LOC<<"Cert is expired, Not After Date="
            << X509_get_notAfter(cert)
            <<", Not Before Date="<< X509_get_notBefore(cert));
        return preverifyOk;
    }
     
    std::string certSubjectName = std::string(subject_name);
    if (!(certSubjectName.find("CN=") == std::string::npos || certSubjectName.find("cn=") == std::string::npos))
    {
        CXPS_LOG_ERROR(AT_LOC<<"subject name does not contain CN=, cert subject name="<<certSubjectName);
        return preverifyOk;
    }

    std::string certificateBiosId;
    size_t biosIdIndex = certSubjectName.find_first_of("=");
    if (std::string::npos != biosIdIndex) {
        certificateBiosId = certSubjectName.substr(biosIdIndex + 1);
    }

    boost::regex guidRegex(GUID_REGEX);
    if (!boost::regex_match(certificateBiosId, guidRegex))
    {
        CXPS_LOG_ERROR(AT_LOC<<"guid not found in subject name="<<certSubjectName);
        return preverifyOk;
    }

    CxpsSslContext* cxpsctx = static_cast<CxpsSslContext*>(SSL_CTX_get_ex_data(sslCtx, 1));

    CXPS_LOG_MONITOR(MONITOR_LOG_LEVEL_3, AT_LOC<<"opening the LocalMachine\\My cert store");
    if (!(hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM,
        0,
        NULL,
        CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG,
        USER_CERT_STORE)))
    {
        CXPS_LOG_ERROR(AT_LOC<<" LocalMachine\\My cert store opening failed");
        return preverifyOk;
    }

    CXPS_LOG_MONITOR(MONITOR_LOG_LEVEL_3, AT_LOC<<"searching the thumbprint in the store.");

#ifdef _DEBUG
    ON_BLOCK_EXIT(boost::bind(&cxpsCertCloseStore, hStore));
#else
    ON_BLOCK_EXIT(boost::bind<void>(&CertCloseStore, hStore, 0));
#endif

    std::string cacertThumbprint;
    size_t cnt = cxpsctx->getCaCertThumbprint().length() / 2;
    for (size_t i = 0; cnt > i; ++i)
    {
        uint32_t s = 0;
        std::stringstream ss;
        ss << std::hex << cxpsctx->getCaCertThumbprint().substr(i * 2, 2);
        ss >> s;

        cacertThumbprint.push_back(static_cast<unsigned char>(s));
    }

    CRYPT_HASH_BLOB hashBlob;
    hashBlob.cbData = cacertThumbprint.length();
    hashBlob.pbData = (BYTE *)cacertThumbprint.c_str();

    // check the thumbprint in the certificate.
    if (!(pCertContext = CertFindCertificateInStore(hStore,
        (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING),
        0,
        CERT_FIND_SHA1_HASH,
        &hashBlob,
        NULL)))
    {
        CXPS_LOG_ERROR(AT_LOC<<"No certificate with ca thumbprint in local store :"
            << cxpsctx->getCaCertThumbprint()<<"\t");
        return preverifyOk;
    }

    ON_BLOCK_EXIT(boost::bind<void>(&CertFreeCertificateContext, pCertContext));

    CXPS_LOG_MONITOR(MONITOR_LOG_LEVEL_3, AT_LOC<<"Making the certificate chain");
    
    X509_STORE *store = X509_STORE_new();
    if (store == NULL)
    {
        CXPS_LOG_ERROR(AT_LOC<<"creation of cert store to check certificate validation failed");
        return preverifyOk;
    }

    ON_BLOCK_EXIT(boost::bind(&X509_STORE_free, store));

    X509 *matchingCert = d2i_X509(NULL,
        (const unsigned char **)&pCertContext->pbCertEncoded,
        pCertContext->cbCertEncoded);

    if (matchingCert == NULL) {
        CXPS_LOG_ERROR(AT_LOC<<"Cert in local store with same thumbprint's conversion to X509 Failed");
        return preverifyOk;
    }
    ON_BLOCK_EXIT(boost::bind(&X509_free, matchingCert));

    if (!X509_STORE_add_cert(store, matchingCert)) {
        CXPS_LOG_ERROR(AT_LOC<<"Local Cert addition in Store Failed");
        return preverifyOk;
    }
    
    X509_STORE_CTX * storectx= X509_STORE_CTX_new();
    if (storectx == NULL)
    {
        CXPS_LOG_ERROR(AT_LOC<<"creation of cert store context to check certificate validation failed");
        return preverifyOk;
    }
    ON_BLOCK_EXIT(boost::bind(&X509_STORE_CTX_free, storectx));

    X509_STORE_set_verify_cb(store, verify_cb);
    if (X509_STORE_CTX_init(storectx, store, cert, NULL) == 0)
    {
        CXPS_LOG_ERROR(AT_LOC << "Context Setup for Verification Failed");
        return preverifyOk;
    }

    if (X509_verify_cert(storectx) <= 0)
    {
        CXPS_LOG_ERROR(AT_LOC<<"Verification of Cert Chain Failed");
        return preverifyOk;
    }
    
    preverifyOk = 1;
    X509_STORE_CTX_set_error(ctx, X509_V_OK);

    cxpsctx->setCertBiosId(certificateBiosId);
    CXPS_LOG_MONITOR(MONITOR_LOG_LEVEL_1, AT_LOC<<"client cert verification successful");

#endif
    return preverifyOk;
}