I'm developing an application based on OpenSSL version 0.9.8a API and I need to verify an RSA signature (4096 bit RSA key) using an RSA public key pubkey.
This is my code:
const EVP_MD* md = EVP_get_digestbyname("SHA512");
if (!md)
{
return false;
}
if(EVP_DigestInit_ex(ctx, md, NULL)<=0)
{
return false;
}
if(EVP_DigestVerifyInit( ctx, NULL, md, NULL, pubKey)<=0)
{
return false;
}
if (EVP_DigestUpdate(ctx, Msg, MsgLen) <= 0)
{
return false;
}
int res = EVP_DigestFinal_ex(ctx, MsgHash, &MsgHashLen);
The problem is that the EVP_DigestVerifyInit function is not defined in openssl0.9.8a.
Is there an other way to verify an RSA signature in the version that predate OpenSSL version 1.0.0?
Here are my inputs:
/* Text_message saved to "sample.txt" file (text ends with the last chacracter '\n') */
My secret message.\n
/* generated RSA public key */
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAl44E9YikPF9RzjAWxZXO
/GaJVCVdQOjp6pmSgL38WvS7glqMwQFwBzSqAiuvVkf3j9C+9Cgs2pypamfDBabC
CZX9+c4oE9zxW2wz0yT5dKL+lUuvIeKfDTMvttjHPtMn23S4ASqLZFAeJX0bCd9H
6l2/8KBjV+uinVlwvKGjXbE5ds2/8S2gei17WvdTb2ypvAUhdw7dc8IaSosG5lOa
EycLN6XKq0z8UX336PiuY0FzLa2B3FOOc6TuPpjkRuf73YKt/Xtm+78ztkfwHLUs
v+EX0TJpB8jE4DISiogNrceOPOnFipppxau2t0VjLivmYTnvSbJzIbOmutFGX8HV
17m3tUpATCdVDuMJ3ouCWOjIJSvw60gizOUHqmMBX+qG95mQ1h3QGP7SExYDKgfp
VpIEAVsnv+CvZTGOEIYcO9ROI2FM6fBgDxkHAdWFCkBVK6o5JxYmsHAXOfFVh+FD
K/pxCBuQINn5B6xanBJYmtpbtq7D0UcvVn6HP7w/9X/pvdU90+KMx1p5AZ6WFeNB
BWLp4whPnU6VEFo+UwXyrCWPIlq3vAz/TjxOXW0Plw+xtsoyw15C8+mS9/4x9XyV
O9v4vlvsRL46T/h4axVsbf2B5w4JC4VoNTuomObecQ0s3v+v54ZYJNsp/tLMa02n
+N9hImCjf+Y6HF8s6BKQ1B0CAwEAAQ==
-----END PUBLIC KEY-----
/* base64 encoded Signatue saved to "PKGC_sample_singed.enc64" file */
NIInzKblrnRZ3olbVUSJbYQhnn9VvDaadcsLNLAVRS/2rryzQr8FVo7ty4oQYqQT
KwRkwVakCxqs+Dg+wHCHQ+K6D6d43nGodC0kNgD1++vYeorUbpK7QNdMu+73g5pW
TiYCicKp6DfeYGWPLI0aYivQJqwNMxqrFd/CdNWhIap4f4fZb5WHcszqlsLCqtrr
qVLP3fXVlHzfiA6jqx2GVE5m43iXLB2H3DwXmjS8eX0veRTlcU5lOtoH/yAGRxmL
p3Mg/s3LSdiAL4Gki4nSORWVmsJ0IwtRttLAl5wYN2VAWz8n21wjCTcr9f2k7BQy
/W74zug+8rbnejFoS50YOKB27PKUTcv0Qn5tWYrk/BK4FPovXyj+tPHZ+jIvAdvX
7UbGl1fkyylb2C6DUxlPPZRxjiaoA4xKwaSFrwcMQnVFphE/LuyQ5aBQZVtAI8Sj
K4zws2BjbCUh+JWzJawCZmIt8IEq1IavW/t/YaMIqR4IMMnHghZGhN8Hm34UOIwB
uyTx1bX/AlKIs7h2ibKSL5JKunQ2IbLqvPeyhjLoFdqiv57JsIzA154xFyl1uXlj
Y32kmtn2LO8SsJcJmDFaD63sj3+WbTR+BRw0QZf9lE94Fa/MPooF0I49aNIx59Wa
2uRR9r0oBgMkpNH+kNmCXcRdPyWIbILGZShkKMcp0Oo=
/* The following steps describe openssl command line used to sign then verify the signature */
/* ***** Step 1: sign the message ***** */
/* Sing the message using the RSA private key genrated before */
dgst -sha512 -sign '/PATH...private_key.pem' -out '/PATH.../PKGC_sample_signed.binr' '/PATH.../sample.txt'
/* Base64 Encoding the signature */
base64 -in '/PATH.../PKGC_sample_signed.binr' -out '/PATH.../PKGC_sample_singed.enc64'
/* ***** Step 2: signature verification ***** */
/* Base64 Decode the signature */
base64 -d -in '/PATH.../PKGC_sample_singed.enc64' -out '/PATH.../PKGC_sample_signed.decod64'
/* Verify the signature using the public key */
dgst -sha512 -verify '/PATH.../public_key.pem' -signature '/PATH.../PKGC_sample_signed.decod64' '/PATH.../sample.txt'
==> I get Verify OK.
Related
I need to test if a ECC certificate in PEM format is of good shape in C using the wolfssl library.
I do not want to test any further information only if it is a certificate and not any random Base64 encoded bytes between the
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
lines.
What is the easiest way to do so?
You can use the wolfSSL_X509_load_certificate_file to check if it's a valid certificate, as shown in the example bellow.
You can find the function documentation here.
#include <wolfssl/openssl/x509.h>
int is_x509_cert(const char* pem_cert_file_path) {
WOLFSSL_X509 *cert = wolfSSL_X509_load_certificate_file(pem_cert_file_path, SSL_FILETYPE_PEM);
if (cert != NULL) {
wolfSSL_X509_free(cert);
return 1;
} else {
return 0;
}
}
I'll explain all the steps I've done so far and conclude with my question.
using OpenSSL 1.0.1e-fips 11 Feb 2013
Generating a private and public key
openssl genrsa -des3 -out private.pem 2048
openssl rsa -in private.pem -outform PEM -pubout -out public.pem
signing a message with digest and private key
openssl dgst -sha256 -sign private.pem -out message.secret message.txt
at this point I have a public key, a signed message ( with digest ) and the original message.
Part 1 - using CLI ( this one works )
Using the CLI I manage to verify the digest:
openssl dgst -sha256 -verify public.pem -signature message.secret message.txt
I get "Verified OK" as a return value.
Part 2 - Using C program
My program looks like this:
where:
msg is message.txt
signature is message.secret
pkey is the public key ( achieved using PEM_read_PUBKEY )
int verify_it(const byte* msg, size_t msg_len, byte* signature, EVP_PKEY* pkey) {
EVP_MD_CTX *ctx;
size_t sig_len;
int bool_ret;
int ret_val;
ret_val = EXIT_SUCCESS;
ctx = NULL;
do
{
ctx = EVP_MD_CTX_create();
const EVP_MD* md = EVP_get_digestbyname( "SHA256" );
EVP_DigestInit_ex( ctx, md, NULL );
EVP_DigestVerifyInit( ctx, NULL, md, NULL, pkey );
EVP_DigestVerifyUpdate(ctx, msg, msg_len);
sig_len = 256;
if ( !EVP_DigestVerifyFinal( ctx, signature, sig_len )
ERR_print_errors_fp( stdout )
);
} while(0);
return ret_val;
}
this code returns a verification failure ( value of 0 ).
also the function ERR_print_errors_fp( stdout ) prints the following message:
140332412258152:error:04091077:lib(4):func(145):reason(119):rsa_sign.c:176
EDIT
thanks to #deniss I've managed to fix this one problem ( signature length was bad - probably a '\0' mid signature - so i just edit the length to be 256 )
but now I'm getting another problem -
140195987986280:error:04091068:lib(4):func(145):reason(104):rsa_sign.c:293
checking it with openssl errstr I've got
error:04091068:rsa routines:INT_RSA_VERIFY:bad signature
the way I acquire my signature is like this:
secret_fp = fopen( "message.secret", "rb" );
fseek( secret_fp, 0, SEEK_END );
file_len = ftell( secret_fp );
fseek( secret_fp, 0, SEEK_SET );
signature = malloc( file_len );
fread( signature, file_len, 1, secret_fp );
You can always decode openssl error codes into meaningful messages with
openssl errstr <error-code>
Code 04091077 stands for error:04091077:rsa routines:INT_RSA_VERIFY:wrong signature length.
The most probable explanation:
message.secret is binary file
it has zero byte somewhere in the middle
strlen trims signature on this byte
I generated a public/private keypair with openssl:
openssl genrsa -out private.pem 1024
openssl pkcs8 -topk8 -in private.pem -outform DER -out private.der -nocrypt
openssl rsa -in private.pem -pubout -outform DER -out public.der
Now after that I created test code with Python, that was encrypting and deciphering strings. I took the example straight from PyCrypto documentation, encrypting:
string_to_encrypt = str(raw_input("Enter a string to encrypt: "))
print "Encrypting: %s" % string_to_encrypt
key = RSA.importKey(open('./public.der').read())
cipher = PKCS1_OAEP.new(key)
ciphertext = cipher.encrypt(string_to_encrypt)
and decrypting:
dec_key = RSA.importKey(open('./private.der').read())
d_cipher = PKCS1_OAEP.new(dec_key)
dec_message = d_cipher.decrypt(ciphertext)
Now this works as expected, and next I wanted to try deciphering same using C. I transfer the data via socket to the C application.. but now I'm unable to get the message back to clear text, even though the deciphering is not throwing errors.
Before I try to decipher the text, I print out the data to the screen, and the bytes match on both ends. The receiving function looks like this:
char* decrypt_packet(char* encrypted_buffer, int size) {
FILE *keyfile = fopen("./private.pem", "r");
RSA *rsa_pri = PEM_read_RSAPrivateKey (keyfile, NULL, NULL, NULL);
int rsa_private_len = RSA_size(rsa_pri);
for(i; i < size;i++)
printf("%02x:",(unsigned char)encrypted_buffer[i]);
printf("\n");
char * decrypt = (char*)malloc(rsa_private_len+1);
memset(decrypt,0,rsa_private_len+1); //Zero the buffer for printing
int res = RSA_private_decrypt(rsa_private_len, (unsigned char*)encrypted_buffer, (unsigned char*)decrypt, rsa_pri , RSA_NO_PADDING);
if(res == -1) {
ERR_load_crypto_strings();
printf("ERROR: %s\n",ERR_error_string(ERR_get_error(),NULL));
}
printf("size decrypt: %i\n", res);
printf("decrypted: %s\n", decrypt);
....
The deciphering doesn't fail, but the output is garbage (here sending just a test string "hello world"):
received buffer:
82:9d:a7:f7:3c:d6:71:12:01:31:ba:c6:a2:90:94:90:fd:69:d3:fe:14:11:2f:af:a9:8a:25:99:55:d2:84:1f:dc:e3:5e:a9:be:7b:8a:ac:cd:38:76:a2:91:ec:24:da:06:c7:8d:67:c8:15:19:73:c8:57:ce:a5:87:f0:da:db:c2:6d:5b:55:a3:ba:7e:7d:ca:6b:02:23:fd:fe:cb:b4:04:53:e2:74:c3:91:77:ee:5f:7a:61:7a:87:a6:42:37:28:c6:9c:cb:6a:46:f4:c0:bd:fe:8a:92:da:86:53:3b:5c:e2:e3:79:81:2c:32:28:9c:4c:be:0a:fa:75:7b:b2:
size decrypt: 128
decrypted: dÕf`5åiõuy<òáµÛ~G=/
Ä
I have chosen to use RSA_NO_PADDING? I have no idea really if this is correct.
But if I use something else, the decrypt function complains: RSA_padding_check_PKCS1_type_2:block type is not 02 or RSA_padding_check_PKCS1_OAEP:oaep decoding error
Am I correctly calling the RSA_private_decrypt function ? Could the problem be that I'm reading the private.pem file in C (in Python I was reading the .der file)?
One more thing came to mind. I used default openssl from Ubuntu to generate the keys, but my C application I'm linking against a downloaded and compiled source. The Makefile contains:
SOURCE_FILES = main.c client_handler.c
CC=gcc
$(CC) $(SOURCE_FILES) -o client_control_srv -lpthread -lssl -lcrypto -I/home/jlumme/openssl-1.0.1f_x86/include
Thanks for any tips!
Looks like my key generation was messed up.
I regenerated the keys:
openssl genrsa -out mykey_priv.pem 1024
openssl rsa -in mykey_priv.pem -out mykey_publ.der -outform DER -pubout
and now it works with the same code. As CBHacking pointed out, I also needed to have padding set to RSA_PKCS1_OAEP_PADDING.
I'm trying to read a RSA public key generated with openssl like this:
Private Key:
openssl genrsa -out mykey.pem 1024
Public Key afterwards:
openssl rsa -in mykey.pem -pubout > somewhere.pub
Then I try to read:
FILE *keyfile = fopen("somewhere.pub", "r");
RSA *rsa_pub = PEM_read_RSAPublicKey(keyfile, NULL, NULL, NULL);
//rsa_pub == NULL!
When I'm reading the private key it works
FILE *keyfile = fopen("mykey.pem", "r");
RSA *rsa_pri = PEM_read_RSAPrivateKey(keyfile, NULL, NULL, NULL);
//all good
Any ideas?
I've read that openssl generate a X509 key of the RSA public key. But I could not manage to load even a X509 pub key.
Thanks
You might try PEM_read_RSA_PUBKEY() instead of PEM_read_RSAPublicKey().
This is all about formats.
The default public key file format generated by openssl is the PEM format.
PEM_read_RSA_PUBKEY() reads the PEM format. PEM_read_RSAPublicKey() reads the PKCS#1 format.
So if you want to stick to PEM_read_RSAPublicKey() you could generate the public key file using the PKCS#1 format by specifying the -outform DER option when generating the public key.
it seems there are two format of rsa public key, with different encoding.
A. RSA_PUBKEY
RSA* rsaPubKey = PEM_read_bio_RSA_PUBKEY( bio, NULL, 0, pass ) ;
read PUBKEY with this format
-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----
generated by
$ openssl rsa -in key.pri -pubout -out key.pub1
B. RSAPublicKey
RSA* rsaPubKey = PEM_read_bio_RSAPublicKey( bio, NULL, 0, pass ) ;
read PublicKey with this format
-----BEGIN RSA PUBLIC KEY-----
...
-----END RSA PUBLIC KEY-----
generated by
$ openssl rsa -in key.pri -RSAPublicKey_out -out key.pub2
convert
A to B format
$ openssl rsa -in key.pub1 -pubin -RSAPublicKey_out -out key.pub2_
B to A format
$ openssl rsa -in key.pub2 -RSAPublicKey_in -pubout -out key.pub1_
The openssl rsa utility saves the public key using the
function PEM_write_bio_RSA_PUBKEY and not PEM_write_bio_RSAPubicKey. So,
if you want your program to be compatible with its output, then you
should use PEM_write_bio_RSA_PUBKEY and PEM_read_bio_RSA_PUBKEY for
saving/loading public key files.
http://openssl.6102.n7.nabble.com/RSA-public-private-keys-only-work-when-created-programatically-td12532.html
Here is a certificate in x509 format that stores the public key and the modulo:
const unsigned char *certificateDataBytes = {/*data*/};
Using OpenSSL and C, how can I convert it into an RSA object? I've tried several methods but I can't get it to work in RSA_public_encrypt
I think you mean public key into RSA * structure.
Since, you have certificate in bytes, if it is in DER encoded bytes, then you need to first convert it into X509 * structure.
X509 * cert;
EVP_PKEY * pubkey;
//length is the length of the certificateDataBytes in terms of bytes.
cert = d2i_x509 (NULL, certificateDataBytes, length);
pubkey = X509_get_pubkey (cert);
Please note that if certificate has RSA public key, then you can get RSA public key as follows:
RSA * rsa
rsa = EVP_PKEY_get1_RSA(pubkey);
//Now rsa contains RSA public key. Use it.
//After use, free the pubkey
EVP_PKEY_free (pubkey);
I hope this must solve your purpose.
If certificate encoding is different, use different function. Once, you get X509 *, rest step is same.