OpenSSL技术问题:输出指针为NULL时BIGNUM的bin2bn未分配新实例
Let's tackle this head-on—you're absolutely right that there's a mismatch between the OpenSSL 1.1.0 manual's description of BN_bin2bn() and its actual behavior when passing NULL for the ret parameter. Let's break down the problem, share a complete test case, and cover fixes/workarounds.
First, let's recap the manual's promise:
According to the OpenSSL 1.1.0 documentation:
BN_bin2bn()converts the big-endian positive integer pointed to bys(of lengthlen) into a BIGNUM and stores it inret; ifretis NULL, a new BIGNUM instance is created.
But in practice, when you pass NULL as ret, the function often fails to allocate that new BIGNUM. Here's a fully fleshed-out minimal test case that reproduces the issue (I expanded your snippet to include hex-to-binary conversion, which is necessary to test the actual BN_bin2bn() call):
#include <iostream> #include <boost/algorithm/hex.hpp> #include <openssl/bn.h> #include <openssl/err.h> #include <vector> int main() { std::string in_hex = "200ec31326d7a933222e3b43a7d6c920a1d2e8a74d1e6f4980ca78b2d9c1aaba6c2ad71f0f1d0cbb40695f27be048982589bc"; // Convert hex string to binary buffer (required for BN_bin2bn) std::vector<unsigned char> bin_buf; try { boost::algorithm::unhex(in_hex.begin(), in_hex.end(), std::back_inserter(bin_buf)); } catch (const std::exception& e) { std::cerr << "Hex decoding failed: " << e.what() << std::endl; return 1; } // Attempt to use BN_bin2bn with NULL ret (as per manual) BIGNUM* bn = BN_bin2bn(bin_buf.data(), bin_buf.size(), NULL); if (!bn) { // Print detailed OpenSSL error unsigned long err_code = ERR_get_error(); char err_msg[256]; ERR_error_string(err_code, err_msg); std::cerr << "BN_bin2bn failed to allocate new BIGNUM: " << err_msg << std::endl; return 1; } // Verify the BIGNUM was created (optional) char* bn_hex = BN_bn2hex(bn); std::cout << "Successfully created BIGNUM: " << bn_hex << std::endl; // Cleanup OPENSSL_free(bn_hex); BN_free(bn); return 0; }
Common Causes & Troubleshooting Steps
- Wrong OpenSSL Version: Double-check you're linking against OpenSSL 1.1.0, not an older branch (like 1.0.2) where
BN_bin2bn()didn't support NULLret. Runopenssl versionin your build environment to confirm. - Memory Allocation Failure: Under the hood,
BN_bin2bn()callsBN_new()whenretis NULL. If your system is low on memory or has heap corruption, this can fail. The error logging in the test case above will help diagnose this. - Early 1.1.0 Regression: OpenSSL 1.1.0 had several patch releases—early versions (like 1.1.0a) had bugs that were fixed later. Upgrading to the latest 1.1.0 patch (e.g., 1.1.0l) might resolve the issue.
Reliable Workaround
If the automatic allocation still doesn't work, bypass it by explicitly creating the BIGNUM first. This is actually more explicit and avoids relying on the manual's potentially incorrect promise:
// Explicitly allocate BIGNUM first BIGNUM* bn = BN_new(); if (!bn) { std::cerr << "BN_new failed to allocate BIGNUM" << std::endl; return 1; } // Pass the pre-allocated BIGNUM to BN_bin2bn if (!BN_bin2bn(bin_buf.data(), bin_buf.size(), bn)) { unsigned long err_code = ERR_get_error(); char err_msg[256]; ERR_error_string(err_code, err_msg); std::cerr << "BN_bin2bn failed: " << err_msg << std::endl; BN_free(bn); return 1; }
This approach gives you full control over the BIGNUM's lifecycle and avoids any ambiguity from the documentation.
内容的提问来源于stack exchange,提问作者The Quantum Physicist

