带有 libcrypto 和 libcurl 的 OCSP

OCSP with libcrypto and libcurl

我正在编写一个需要验证证书有效性的应用程序。为此,我想使用 OCSP。我没有自己实施 OCSP,而是查看了 OpenSSL 的 libcrypto 来准备必要的数据。

我想到了这个(为清楚起见删除了错误处理):

int main(int argc, char** argv) {
    SSL_library_init();
    FILE *cert_f = fopen(argv[1], "r");
    FILE *cacert_f = fopen(argv[2], "r");
    X509 *cert = d2i_X509_fp(cert_f, NULL);
    X509 *cacert = d2i_X509_fp(cacert_f, NULL);
    fclose(cert_f);
    fclose(cacert_f);

    OCSP_REQUEST *req = OCSP_REQUEST_new();
    OCSP_CERTID *id = OCSP_cert_to_id(EVP_sha1(), cert, cacert);
    OCSP_request_add0_id(req, id);
    BIO *bio = BIO_new_connect("ocspserver:http");
    OCSP_RESPONSE *resp = OCSP_sendreq_bio(bio, "/2", req);
}

发送请求就好了。唯一的问题是 OCSP_sendreq_bio() 似乎不支持通过 HTTP 代理发送 HTTP 请求,这对我来说是一个障碍。 documentation 对此有如下说法:

These functions only perform a minimal HTTP query to a responder. If an application wishes to support more advanced features it should use an alternative more complete HTTP library.

只是没说怎么弄,我也想不通。 OCSP_sendreq_bio() 调用将 OCSP_REQUEST 结构转换为 ASN.1 结构,但似乎没有任何 public 调用允许我这样做(除非我'我遗漏了一些东西)。

我这样做的方式正确吗?如果没有,我应该怎么做?

好吧,我是个白痴:-)

答案是 OpenSSL 有一堆宏可以生成通用函数,用于将某些内容从 struct 转换为 ASN.1 二进制格式。这些都具有 i2d_STRUCT_NAME 的形式(并且 d2i_STRUCT_NAME 用于反向操作)。没有记录确切的 i2d_OCSP_REQUESTd2i_OCSP_RESPONSE 函数,但是其他一些函数(例如,d2i_X509,我在我的问题中正在使用它)是并且具有非常相似的函数签名(因为它们是用相同的宏生成的)。

因此,答案是用这样的东西替换 OCSP_sendreq_bio

unsigned char *data = NULL;
long len = (long)i2d_OCSP_REQUEST(req, &data);
CURL *curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, "http://ocspserver/2");
curl_easy_setopt(curl, CURLOPT_POST, (long)1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_memory_append_function);
curl_easy_perform(curl);

等等