-
Notifications
You must be signed in to change notification settings - Fork 51
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SIGSEGV on pk_decrypt() #98
Comments
I did some ltraces but can not figure out why it crashes:
|
After recompiling openssl with symbols and debug enabled I got this:
|
Replicated with this C program: #include <stdio.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
static void decrypt(EVP_PKEY *key, const char *str, size_t inlen, int rsaPadding) {
size_t outlen;
EVP_PKEY_CTX *ctx;
BIO *bio;
BUF_MEM *buf;
int base_type = EVP_PKEY_base_id(key);
bio = BIO_new(BIO_s_mem());
if (!bio)
goto sslerr;
BIO_reset(bio);
BIO_get_mem_ptr(bio, &buf);
if (!(ctx = EVP_PKEY_CTX_new(key, NULL)))
goto sslerr;
if (EVP_PKEY_decrypt_init(ctx) <= 0)
goto sslerr;
if (base_type == EVP_PKEY_RSA && !EVP_PKEY_CTX_set_rsa_padding(ctx, rsaPadding))
goto sslerr;
if (EVP_PKEY_decrypt(ctx, NULL, &outlen, (const unsigned char *)str, inlen) <= 0)
goto sslerr;
if (!BUF_MEM_grow_clean(buf, outlen))
goto sslerr;
if (EVP_PKEY_decrypt(ctx, (unsigned char *)buf->data, &outlen, (const unsigned char *)str, inlen) <= 0)
goto sslerr;
EVP_PKEY_CTX_free(ctx);
ctx = NULL;
fwrite(buf->data, 1, outlen, stdout);
BIO_reset(bio);
BIO_free(bio);
return;
sslerr:
exit(4);
}
static const char pem[] = "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDG526ikLUwCMRZfmzSjT5nYhWj\nVbnL5T8j29b0s+gZg1/SEqOeRnpGqEpbExcLOJ3Qk/SVBjdx4swDFDNen5vzUSb2\nepH4qyRFJpS+qFGKuqxpEV/B5qJ7NVg/Kv4HY3ZED/9rM8NC7ZogWM+RSadNfSc6\nGyhWJptupptJgCfqFQIDAQAB\n-----END PUBLIC KEY-----";
static const char str[] = {
0x40, 0x19, 0xa2, 0x44, 0xe4, 0xd6, 0xfe, 0x9b, 0x6b, 0x4d, 0x39, 0xe1,
0xac, 0x46, 0xb5, 0x7f, 0x72, 0x74, 0x46, 0x22, 0x8a, 0x32, 0x8e, 0xb6,
0x4e, 0x15, 0x7b, 0x80, 0xc0, 0xae, 0x92, 0x20, 0xa8, 0x2c, 0x52, 0x03,
0xed, 0xc4, 0x83, 0x2a, 0x24, 0x56, 0x45, 0x13, 0x3e, 0x1c, 0xcc, 0x54,
0x0b, 0x0a, 0x62, 0xb5, 0xab, 0x2b, 0xec, 0xce, 0x5c, 0xc9, 0x71, 0xe8,
0x10, 0x07, 0x67, 0x9a, 0x06, 0x7d, 0xae, 0xf6, 0xa4, 0x25, 0x20, 0x17,
0x1f, 0x70, 0x71, 0xb2, 0xfc, 0xab, 0xb8, 0x5a, 0xcb, 0xc0, 0x22, 0x73,
0x80, 0x05, 0xb2, 0xaf, 0x2e, 0x8d, 0xef, 0x3a, 0x8b, 0x21, 0xfe, 0x59,
0x62, 0xaf, 0x4e, 0x2d, 0xc7, 0x5f, 0x30, 0xd5, 0x4c, 0xb7, 0xa6, 0xee,
0xc9, 0x02, 0xdf, 0x81, 0x96, 0x9b, 0x6b, 0x85, 0x98, 0xe3, 0x51, 0x68,
0x6c, 0xe9, 0x5a, 0x19, 0x38, 0x89, 0xf0, 0x35
};
int main() {
EVP_PKEY *pub;
BIO *bio = BIO_new_mem_buf((void *)pem, sizeof pem);
if (!bio)
goto sslerr;
/*
* BIO_reset is a rewind for read-only
* memory buffers. See mem_ctrl in
* crypto/bio/bss_mem.c of OpenSSL source.
*/
BIO_reset(bio);
pub = PEM_read_bio_PUBKEY(bio, NULL, 0, "");
if (!pub)
goto sslerr;
decrypt(pub, str, sizeof str, RSA_PKCS1_PADDING);
return 0;
sslerr:
ERR_print_errors_fp(stderr);
return 1;
} Looking at the problem from a higher level: you're trying to decrypt using a public key. We probably need to add a check for this; but there's no way for this operation to work in the first place. |
Was able to perform just that - but I had to expose RSA_public_decrypt and use that instead of EVP_PKEY_decrypt. It works perfectly with this.
|
So you're trying to extract the digest from a signed message? |
I had a look into preventing the segfault: as far as I can see it requires manual upfront validation. Which needs to happen on a per key-type basis. union {
RSA *rsa;
DH *dh;
DSA *dsa;
#ifndef OPENSSL_NO_EC
EC_KEY *ec;
#endif
} base_key = { EVP_PKEY_get0(key) };
/* Validate that required parameters are present, openssl doesn't do this itself */
switch (EVP_PKEY_base_id(key)) {
case EVP_PKEY_RSA: {
const BIGNUM *d = NULL;
RSA_get0_key(base_key.rsa, NULL, NULL, &d);
luaL_argcheck(L, d != NULL, 1, "private key missing");
}
break;
default:
/* do nothing */
break;
} This brings up questions about how this can happen in the first place: in this case it's importing a key from a PEM without the private portion. One option I considered was to just fill in the private portion with dummy values on import. But that seems like a poor choice: keys could come from elsewhere in an application. e.g. out of an SSL session. This led me to the conclusion that |
I'm not decoding a digest - in this application a secret blob is encrypted with the private key and whoever has the public key can decrypt the blob. It works fine with RSA_public_decrypt now. Recommend to expose the RSA_ commands as well, here is the patch that exposes RSA_public_decrypt:
|
Hello, I have recreated the same seg-fault in a slightly different way on the current code base (e4cdcc5 on 13 Aug 2018). My test does create a public key which has no corresponding private key part (as discussed in comment 98 above). By hacking openssl.c in pk_decrypt (which was were I found the problem first) I found that the seg-fault (for me) happens on the call to 'BIO_get_mem_ptr(bio, &buf);' (line 3864). My work around was to call toPEM("public") on each key just after it is created. I suspect this might perform something like the work around suggested in comment 98 above). Since I have (what I think is a robust) work around, this is currently not a high priority issue. My test scripts and short analysis can be found in my branch: Many thanks for writing and maintaining a very useful Lua module. Regards, |
Oh? that's interesting.... you think there's something inside of
Note that this projects has tests in the |
First of, thanks for creating this! I have tried to do a simple public-key decryption (cleartext is encrypted with the private key) and I run into a SIGSEGV :(
I checked and the b64 decoded message matches what I have and it also decrypts using the same pubkey and openssl rsautl.
The text was updated successfully, but these errors were encountered: