在 EVP_SignFinal 生成 RSA 签名时如何避免 SIGABRT

How to avoid SIGABRT when generating RSA Signature at EVP_SignFinal

我正在尝试使用适用于 C++ 的 libopenssl 生成 RSA 签名: 但是当我 运行 我的代码时,我得到了一个 SIGABRT。我对 libopenssl 内部的东西进行了一些深入的调试,以查看段错误的来源。我稍后会谈到这个。

首先我想说明一下,RSA 私钥已从 .pem 文件成功加载。所以我很确定这不是问题的根源。

所以我的问题是:如何避免 SIGABRT 以及它的原因是什么?

我这样做是为了 B.Sc。论文所以我真的很感谢你的帮助:)


签名生成函数:

DocumentSignature* RSASignatureGenerator::generateSignature(ContentHash* ch, CryptographicKey* pK) throw(PDVSException) {
    OpenSSL_add_all_algorithms();
    OpenSSL_add_all_ciphers();
    OpenSSL_add_all_digests();

    if(pK == nullptr)
        throw MissingPrivateKeyException();

    if(pK->getKeyType() != CryptographicKey::KeyType::RSA_PRIVATE || !dynamic_cast<RSAPrivateKey*>(pK))
        throw KeyTypeMissmatchException(pK->getPem()->getPath().string(), "Generate RSA Signature");

    //get msg to encrypt
    const char* msg = ch->getStringHash().c_str();

    //get openssl rsa key
    RSA* rsaPK = dynamic_cast<RSAPrivateKey*>(pK)->createOpenSSLRSAKeyObject();

    //create openssl signing context
    EVP_MD_CTX* rsaSignCtx = EVP_MD_CTX_create();
    EVP_PKEY* priKey  = EVP_PKEY_new();
    EVP_PKEY_assign_RSA(priKey, rsaPK);

    //init ctxt
    if (EVP_SignInit(rsaSignCtx, EVP_sha256()) <=0)
        throw RSASignatureGenerationException();

    //add data to sign
    if (EVP_SignUpdate(rsaSignCtx, msg, std::strlen(msg)) <= 0) {
        throw RSASignatureGenerationException();
    }

    //create result byte signature struct
    DocumentSignature::ByteSignature* byteSig = new DocumentSignature::ByteSignature();
    //set size to max possible
    byteSig->size = EVP_MAX_MD_SIZE;
    //alloc buffer memory
    byteSig->data = (unsigned char*)malloc(byteSig->size);

    //do signing
    if (EVP_SignFinal(rsaSignCtx, byteSig->data, (unsigned int*) &byteSig->size, priKey) <= 0)
        throw RSASignatureGenerationException();


    DocumentSignature* res = new DocumentSignature(ch);
    res->setByteSignature(byteSig);

    EVP_MD_CTX_destroy(rsaSignCtx);
    //TODO open SSL Memory leaks -> where to free open ssl stuff?!

    return res;
}

RSA* rsaPK = dynamic_cast(pK)->createOpenSSLRSAKeyObject();

virtual RSA* createOpenSSLRSAKeyObject() throw (PDVSException) override {
        RSA* rsa = NULL;
        const char* c_string = _pem->getContent().c_str();
        BIO * keybio = BIO_new_mem_buf((void*)c_string, -1);

        if (keybio==NULL)
            throw OpenSSLRSAPrivateKeyObjectCreationException(_pem->getPath());

        rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa, NULL, NULL);

        if(rsa == nullptr)
            throw OpenSSLRSAPrivateKeyObjectCreationException(_pem->getPath());

        //BIO_free(keybio);

        return rsa;
    }

文件中的 SigAbrt 来源 openssl/crypto/mem.c

void CRYPTO_free(void *str, const char *file, int line)
{
    if (free_impl != NULL && free_impl != &CRYPTO_free) {
        free_impl(str, file, line);
        return;
    }

#ifndef OPENSSL_NO_CRYPTO_MDEBUG
    if (call_malloc_debug) {
        CRYPTO_mem_debug_free(str, 0, file, line);
        free(str);
        CRYPTO_mem_debug_free(str, 1, file, line);
    } else {
        free(str);
    }
#else
    free(str); // <<<<<<< HERE
#endif
}

堆栈跟踪

stacktrace screenshot from debugger (clion - gdb based)

我刚发现 Bug(我真的不确定这是否是 libopenssl 的 Bug..)

//set size to max possible
byteSig->size = EVP_MAX_MD_SIZE;
//alloc buffer memory
byteSig->data = (unsigned char*)malloc(byteSig->size);

问题出在我将缓冲区大小设置为 EVP_MAX_MD_SIZE!

(在我看来)非常非常奇怪的事情是,你必须保持未初始化的大小! (甚至没有设置为 0 - 只是 "size_t size;" )。

奇怪的是你也必须像我一样分配内存。我不明白这一点,因为然后分配了未定义大小的内存..

真正奇怪的是 libopenssl 在内部将大小设置回 0 并自行分配内存。(我通过浏览 libopenssl 源代码检测到这一点)