I am trying to generate a signing request. Apparentely there is an error somewhere in the code (or UB most likelly) which leads to:
- garbage output locally
- returned code 139 on godbolt
#include <memory>
#include <stdexcept>
#include <string>
#include <iostream>
namespace {
std::string make_csr();
} // namespace
int main(int, char **) {
try {
std::cout << ::make_csr() << std::endl;
return 0;
}
catch (const std::exception &e)
{
std::cerr << "Failed with error: " << e.what() << std::endl;
return -1;
}
}
#include <openssl/aes.h>
#include <openssl/bn.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
namespace ssl_utils {
template <typename T> void free(T *);
template <typename T> T *make();
template <typename T> class raii_obj {
private:
struct _free {
void operator()(T *ptr) const { ssl_utils::free(ptr); }
};
public:
using type = T;
using ptr = std::unique_ptr<type, _free>;
static ptr make() { return ptr(ssl_utils::make<type>()); }
};
using raii_bignum = raii_obj<BIGNUM>;
using raii_evp_pkey = raii_obj<EVP_PKEY>;
using raii_x509_req = raii_obj<X509_REQ>;
} // namespace ssl_utils
namespace {
std::string make_csr() {
constexpr size_t privateKeyLength{2048};
auto pBignum = ssl_utils::raii_bignum::make();
auto pKey = ssl_utils::raii_evp_pkey::make();
RSA *rsa = RSA_new();
if (!(static_cast<bool>(pBignum) && //
static_cast<bool>(rsa) && //
BN_set_word(pBignum.get(), RSA_F4) &&
RSA_generate_key_ex(rsa, //
privateKeyLength, //
pBignum.get(), //
nullptr) &&
EVP_PKEY_assign_RSA(pKey.get(), rsa))) {
throw std::runtime_error("Failed to generate RSA key!");
}
auto pReq = ssl_utils::raii_x509_req::make();
X509_REQ_set_version(pReq.get(), 0L);
X509_REQ_set_pubkey(pReq.get(), pKey.get());
X509_NAME *const pName = X509_REQ_get_subject_name(pReq.get());
X509_NAME_add_entry_by_txt(
pName, LN_pkcs9_emailAddress, MBSTRING_UTF8,
reinterpret_cast<const unsigned char *>(
"[email protected]"),
-1, -1, 0);
if (!X509_REQ_sign(pReq.get(), pKey.get(), EVP_md5()) ||
!X509_REQ_verify(pReq.get(), pKey.get()))
throw std::runtime_error("CSR signing failed!");
unsigned char *request = request;
const std::string::size_type reqSize =
i2d_X509_REQ(pReq.get(), &request);
std::string strReq{reinterpret_cast<char *>(request), reqSize};
// CRYPTO_free(request); // does not compile
return strReq;
}
}
namespace ssl_utils {
template <> BIGNUM *make() { return BN_new(); }
template <> void free(BIGNUM *ptr) { BN_free(ptr); }
template <> EVP_PKEY *make() { return EVP_PKEY_new(); }
template <> void free(EVP_PKEY *ptr) { EVP_PKEY_free(ptr); }
template <> X509_REQ *make() { return X509_REQ_new(); }
template <> void free(X509_REQ *ptr) { X509_REQ_free(ptr); }
} // namespace ssl_utils
When debugging on my local machine, I don't see any of the X509_REQ_sign
, X509_REQ_verify
or i2d_X509_REQ
calls failing. So my first thought was that the console's encoding was to blame:
0�j0�R 0%1#0! *�H��
[email protected]�"0
*�H��
� 0�
� ��*��6�
�*x���~����V'U&�, x�c|ϊ����t�!cjBS 3��pI�?�i�弒 s�8���2�r��N�f�T�sq�>Ն�0���#��Z�\�Td_�?im$m]�Ts�RW"�M���Xr��Z r�J���Q$���,ɏ4��)8`R�����)ދAn��B�Di:W�������}
x(ʴ���v�&%�X����k}�P��U�7��ƀ{��l��O!<A��"I���R
�%�o!v�k�̳ � 0
*�H��
� J�V��K����Pj�u"���nX&yK��e�p��������/V��A��r����Р�c�s�ֶ�>�T4�7���5j������BF�s0D��f�-j�w�c �[:���5cf����0�u�`����&$�"�� ���?��dR��2��w ��v���}5qA�8�Rw� ���J��B��Y�n����Z�ۭ]gLt���gۿY��Q3B#k����bш�VWjN�5P�
���B��Ţ���۪�� ��
But then I checked the code at godbold and found out that it crashes at some point there.
I am using OpenSSL for MinGW-w64 from Msys2 package (version "1.1.1q").
CodePudding user response:
The root issue is here, the typo:
unsigned char *request = request;
It is initialized with an unspecified value and should be
unsigned char *request = nullptr;
Otherwise i2d_X509_REQ
tries to realloc
the invalid pointer.
CRYPTO_free(request); // does not compile
should be
OPENSSL_free(request);