【发布时间】:2016-12-08 11:00:00
【问题描述】:
我正在尝试使用 libopenssl for c++ 生成 RSA 签名: 但是当我运行我的代码时,我得到了一个 SIGABRT。我对 libopenssl 内部的东西进行了一些深入的调试,以查看 Segfault 的来源。稍后我会谈到这一点。
首先我想明确一点,RSA PrivateKey 是从 .pem 文件成功加载的。所以我很确定这不是问题的根源。
所以我的问题是:如何避免 SIGABRT 以及它的原因是什么?
我这样做是为了我的理学学士学位。论文所以我真的很感谢你的帮助:)
签名生成函数:
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;
}
文件 openssl/crypto/mem.c 中的 SigAbrt 来源
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
}
堆栈跟踪
【问题讨论】:
-
SIGABRT 的原因是代码中的某个错误。避免它的唯一方法是找到并修复错误。如果没有minimal reproducible example(显示的代码在最小部分和完整部分都失败了),就不可能有进一步的答案。由于 C++ 的工作方式,错误可能出现在任何地方。仅仅因为程序在一个特定函数内崩溃并不意味着这就是错误所在。
-
嗯,好的,谢谢..我想我必须找到这个错误..因为当我做一个简约的例子时它可以工作..:(
-
当然可以。这证明你在某个地方有一个错误。当然,库中的错误总是有可能的。但一个非常不可能的。欢迎使用 C++。
-
另请参阅 OpenSSL wiki 上的 EVP Signing and Verifying。您应该能够复制/粘贴它,并且事情应该为您“正常工作”。此外,有关 C++ 中的 C 对象管理示例,请参阅 OpenSSL wiki 上的 EVP Symmetric Encryption and Decryption | C++ Programs。
-
" 我想我将不得不寻找这个错误......因为当我做一个简约的例子时它可以工作......" - Valgrind 通常可以提供帮助,但是 OpenSSL有如此多的内存泄漏,通常很难在 OpenSSL 上使用该工具。也许您可以使用 Address Sanitizer 构建并等待错误的读/写。
标签: c++ openssl rsa digital-signature