带有 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_REQUEST
和 d2i_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);
等等
我正在编写一个需要验证证书有效性的应用程序。为此,我想使用 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_REQUEST
和 d2i_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);
等等