【问题标题】:How to create ocsp request using openssl in c++?如何在 C++ 中使用 openssl 创建 ocsp 请求?
【发布时间】:2019-10-08 17:38:19
【问题描述】:

我正在尝试使用C++ocsp 服务器发送ocsp 请求,但我找不到任何准备请求的内容。在文档中我发现了以下功能

long SSL_get_tlsext_status_ocsp_resp(ssl, unsigned char **resp);
long SSL_set_tlsext_status_ocsp_resp(ssl, unsigned char *resp, int len);

如何添加证书并为请求设置随机数?

【问题讨论】:

    标签: c++ openssl ocsp


    【解决方案1】:

    您想要做的是为 openssl OCSP 命令生成 C++ 代码:

    openssl ocsp -issuer issuer.pem -cert alice.pem -cert bob.pem -reqout ocspreq.der

    您需要的主要 OPENSSL API 是:

    使用的 API 可能因您希望读取和写入的证书格式而异。

    上述openssl命令转成简单C++代码的一个例子是:

    template<typename T, typename D>
    std::unique_ptr<T, D> make_handle(T* handle, D deleter)
    {
        return std::unique_ptr<T, D>{handle, deleter};
    }
    
    bool generate_ocsp_request()
    {
        // load issuer certificate
        auto file = make_handle(BIO_new_file("issuer.pem", "r"), BIO_free);
        if(!file) return false;
        auto const issuer = make_handle(PEM_read_bio_X509(file.get(), nullptr, nullptr, nullptr), X509_free);
        if(!issuer) return false;
    
        // setup OCSP request
        auto const request = make_handle(OCSP_REQUEST_new(), OCSP_REQUEST_free);
        if(!request) return false;
    
        auto const cert_id_md = EVP_sha1();
    
        // add alice certificate to OCSP request
        file = make_handle(BIO_new_file("alice.pem", "r"), BIO_free);
        if(!file) return false;
        auto cert = PEM_read_bio_X509(file.get(), nullptr, nullptr, nullptr);
    
        auto id = OCSP_cert_to_id(cert_id_md, cert, issuer.get());
        if (id == nullptr) return false;
        if (!OCSP_request_add0_id(request.get(), id)) return false;
    
        // add bob certificate to OCSP request
        file = make_handle(BIO_new_file("bob.pem", "r"), BIO_free);
        if(!file) return false;
        cert = PEM_read_bio_X509(file.get(), nullptr, nullptr, nullptr);
    
        id = OCSP_cert_to_id(cert_id_md, cert, issuer.get());
        if (id == nullptr) return false;
        if (!OCSP_request_add0_id(request.get(), id)) return false;
    
        // write the request out in DER format
        file = make_handle(BIO_new_file("ocspreq.der", "wb"), BIO_free);
        if(!file) return false;
    
        // the below doesn't compile in C++ :(
        // return i2d_OCSP_REQUEST_bio(file.get(), request.get()) != 0;
    
        // go around the macro's that cause the problem in C++ because it will not automatically convert void* to unsigned char* like in C
        return ASN1_i2d_bio(reinterpret_cast<i2d_of_void *>(i2d_OCSP_REQUEST), file.get(), reinterpret_cast<unsigned char*>(request.get())) != 0;
    }
    

    更新:

    阅读响应有点复杂。

    用于处理响应的主要 api 是:

    没有可以提取的“文本”,您需要从响应中具体提取您想要的内容。

    下面的代码基本上是这个命令的一个例子

    openssl ocsp -respin ocspresp.der -reqin ocspreq.der -issuer issuer.pem -cert alice.pem -cert bob.pem

    bool read_ocsp_response()
    {
        // load ocsp request (der format)
        auto file = make_handle(BIO_new_file("ocspreq.der", "rb"), BIO_free);
        if(!file) return false;
        auto const request = make_handle(d2i_OCSP_REQUEST_bio(file.get(), nullptr), OCSP_REQUEST_free);
        if(!request) return false;
    
        // load ocsp response (der format)
        file = make_handle(BIO_new_file("ocspresp.der", "rb"), BIO_free);
        if(!file) return false;
        auto const response = make_handle(d2i_OCSP_RESPONSE_bio(file.get(), nullptr), OCSP_RESPONSE_free);
        if(!response) return false;
        file.reset();
    
        // was the server response ok?
        if(OCSP_response_status(response.get()) != OCSP_RESPONSE_STATUS_SUCCESSFUL) return false;
    
        // verify response
        auto const basic_response = make_handle(OCSP_response_get1_basic(response.get()), OCSP_BASICRESP_free);
        if(!basic_response) return false;
    
        // check that the response is for the expected request
        auto const nonce_check_result = OCSP_check_nonce(request.get(), basic_response.get());
        if(nonce_check_result <= 0)
        {
            if(nonce_check_result == -1)
            {
                puts("WARNING: no nonce in response");
            }
            else
            {
                return false;
            }
        }
    
        // verify the response against the issuer certificate
        auto const issuers_certificate_stack = make_handle(sk_X509_new_null(), [](auto handle){ sk_X509_pop_free(handle, X509_free); });
        if(!issuers_certificate_stack) return false;
    
        file = make_handle(BIO_new_file("issuer.pem", "r"), BIO_free);
        if(!file) return false;
    
        auto const issuer = PEM_read_bio_X509(file.get(), nullptr, nullptr, nullptr);
        if(!issuer) return false;
        file.reset();
    
        sk_X509_push(issuers_certificate_stack.get(), issuer);
    
        // load default certificate store
        auto const store = make_handle(X509_STORE_new(), X509_STORE_free);
        if(!store) return false;
        auto const lookup = X509_STORE_add_lookup(store.get(), X509_LOOKUP_file());
        if(lookup == nullptr) return false;
    
        if(OCSP_basic_verify(basic_response.get(), issuers_certificate_stack.get(), store.get(), OCSP_TRUSTOTHER) != 1) return false;
    
        // check that all the certificates have a status ok results
        if(OCSP_resp_count(basic_response.get() == 0) return false;
        for (auto i = 0; i < OCSP_resp_count(basic_response.get()); i++)
        {
            auto const single_response = OCSP_resp_get0(basic_response.get(), i);
            if(single_response == nullptr) return false;
    
            if(OCSP_single_get0_status(single_response, nullptr, nullptr, nullptr, nullptr) != V_OCSP_CERTSTATUS_GOOD) return false;
        }
    
        return true;
    }
    

    如果您想查找特定证书(如 alice.pem)的状态,则使用从 OCSP_cert_to_id 返回的 OCSP_CERTID(请参阅生成请求)并将其与 OCSP_resp_find_status API 一起使用以查找该证书的状态,而不是像我在上面的代码中那样枚举所有证书。

    如果您要定期查询证书,您可能希望使用从状态返回的下一个更新时间戳来安排何时执行下一次检查调用。

    【讨论】:

    • 谢谢!你知道是否有办法将我从 OCSP 响应者收到的 OCSP_RESPONSE 解析为字符串,以便我可以在第一次握手时将其发送给客户端?
    • 对于响应没有简单的“字符串”操作。我已经使用示例响应处理更新了答案,包括响应验证基本响应状态检查。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多