将Windows证书存储CRL导入OpenSSL

时间:2016-11-30 18:03:45

标签: windows ssl openssl

我在Windows中使用OpenSSL。我希望OpenSSL的证书检查能够根据其CRL验证证书。在OpenSSL文档中,它说:

  

如果启用CRL检查,则CRL应在相应的X509_STORE结构中可用。不会尝试从CRL分发点扩展名下载CRL。

我使用Windows证书存储区的证书填充OpenSSL证书存储区。我想对Windows证书库中存在的CRL执行相同的操作。

有办法吗?是否有可能OpenSSL已将CRL下载添加到其检查中,但尚未记录?

2 个答案:

答案 0 :(得分:1)

我编写了以下代码来启用按需从缓存中获取CRL:

#define length_of(x) (sizeof(x) / sizeof(x[0]))
#define length_of_null_terminated_string(x) (length_of(x) - 1)

static X509_CRL * GetCRLByUrl(
    const char * url)
{
    PCCRL_CONTEXT pCrlContext = nullptr;
    BOOL res = ::CryptRetrieveObjectByUrlA(url, CONTEXT_OID_CRL, 0, 0, (LPVOID*)&pCrlContext, nullptr, nullptr, nullptr, nullptr);
    if (!res) {
        DWORD dwErr = ::GetLastError();
        return nullptr;
    }

    const unsigned char * pbCrlEncoded = pCrlContext->pbCrlEncoded;
    X509_CRL * x509_crl = d2i_X509_CRL(NULL, &pbCrlEncoded, pCrlContext->cbCrlEncoded);
    ::CertFreeCRLContext(pCrlContext);
    if (!x509_crl) {
        return nullptr;
    }

    return x509_crl;

    LOG_SCOPE_LEAVE;
}

static STACK_OF(X509_CRL) * LookupCRLsInWindowsStore(
    X509_STORE_CTX * ctx,
    X509_NAME * nm)
{
    STACK_OF(X509_CRL) * crls = sk_X509_CRL_new_null();
    if (!crls) {
        return nullptr;
    }

    X509 * x509 = X509_STORE_CTX_get_current_cert(ctx);

    static int nids[] = { NID_crl_distribution_points, NID_freshest_crl };
    for (int * it = std::begin(nids), * itEnd = std::end(nids); it != itEnd; ++it) {
        int nid = *it;
        STACK_OF(DIST_POINT) * crldp = (STACK_OF(DIST_POINT) *)X509_get_ext_d2i(x509, nid, NULL, NULL);
        for (int i = 0, iEnd = sk_DIST_POINT_num(crldp); i < iEnd; ++i) {
            DIST_POINT * dp = sk_DIST_POINT_value(crldp, i);
            if (!dp->distpoint) {
                continue;
            }
            if (dp->distpoint->type != 0) {
                continue;
            }

            GENERAL_NAMES * gens = dp->distpoint->name.fullname;
            for (int j = 0, jEnd = sk_GENERAL_NAME_num(gens); j < jEnd; ++j) {
                GENERAL_NAME * gen = sk_GENERAL_NAME_value(gens, i);
                int gtype;
                ASN1_STRING * uri = (ASN1_STRING *)GENERAL_NAME_get0_value(gen, &gtype);
                if (gtype != GEN_URI) {
                    continue;
                }
                const char * url = (const char *)ASN1_STRING_data(uri);
                if (ASN1_STRING_length(uri) < length_of_null_terminated_string("http://") || strncmp(url, "http://", length_of_null_terminated_string("http://")) != 0) {
                    continue;
                }
                X509_CRL * x509_crl = GetCRLByUrl(url);
                if (x509_crl) {
                    sk_X509_CRL_push(crls, x509_crl);
                    break;
                }
            }
        }
        sk_DIST_POINT_pop_free(crldp, DIST_POINT_free);
    }

    return crls;
}

X509_STORE * x509_store = ...;
X509_STORE_set_lookup_crls_cb(x509_store, LookupCRLsInWindowsStore);

答案 1 :(得分:0)

事实证明它比我想象的要容易得多 - 您使用CertEnumCRLsInStore获取相关商店的CRL,然后使用d2i_X509_CRL对OpenSSL的证书进行编码。整件事情与此非常相似:https://stackoverflow.com/a/40046425/1132699