Clear Text Signing using OpenSSL in C Code - c

I am trying to sign a email message using OpenSSL. I want to perform Clear Text Signing on the email message.
I know I can do this using command prompt with the command:
openssl smime -sign -in hw.txt -text -out signed.msg -signer mycert.pem
But how do I do this using C Code?
This is what I am doing right now:
int flgs = PKCS7_DETACHED | PKCS7_TEXT;
PKCS7 * p7 = PKCS7_sign(signCert, pKey, certs, bio, flgs);
if(p7 != NULL) {
int res = PKCS7_final(p7, bio, flags);
__android_log_print(ANDROID_LOG_DEBUG, "OpenSSLJni", "\nFinal result is: %d", res);
FILE *outfile = fopen("/storage/sdcard0/sign_output.txt", "w");
BIO* out = BIO_new_fp(outfile, BIO_NOCLOSE) ;// BIO_new_file(outfile, "");
BIO_reset(bio);
SMIME_write_PKCS7(out, p7, bio, flags);
return true;
}
But I in the output file I am only getting the signature not both the body and signature.
Any pointers?

Finally did it.
It was just a missing flag.
int flgs = PKCS7_STREAM | PKCS7_DETACHED | PKCS7_BINARY ;
Added this flag and it started working perfectly.

Related

verifying digest signed with private key using a C program

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

pre-generated public/private RSA keys, unable to decrypt in C (works in python)

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.

How to use OpenSSL to validate a *.SF / *.RSA signature created by the Jarsigner

I have an archive I want to sign and I want to validate it in C with OpenSSL.
To sign the archive the jarsigner seemed like a good idea, considering I wouldn't have to create something on my own, and it seems to work great. With OpenSSL I can validate the different digest values, but I can't get it to validate the *.SF *.RSA signature.
The steps I have taken:
Create a keystore
$ keytool -genkeypair -alias <alias> -keystore <keystore> -validity 360 -keyalg RSA -keysize 2048 -sigalg SHA256withRSA
Sign the archive
$ jarsigner -keystore <keystore> -signedjar <signedFile>.zip <fileToSign>.zip <alias>
Snipped of C validation code
BIO *in = NULL, *indata = NULL;
PKCS7 *p7 = NULL;
int flags = PKCS7_DETACHED;
flags |= PKCS7_NOVERIFY;
flags |= PKCS7_BINARY;
OpenSSL_add_all_algorithms();
/* load *.RSA (PKCS7) file */
if (!(in = BIO_new_file(path, "r"))) {
printf ("Can't open input file %s\n", path);
status = FAILURE;
}
if (!(p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL))) {
printf ("Error in reading PKCS7 PEM file.\n");
status = FAILURE;
}
/* load *.SF file */
if (!(indata = BIO_new_file(path, "r"))) {
printf("Can't read content file %s\n", path);
status = FAILURE;
}
/* validate signature */
if (PKCS7_verify(p7, NULL, NULL, indata, NULL, flags))
printf("Signature verification successful!\n");
else {
printf("Signature verification failed!\n");
status = FAILURE;
}
The error
It fails in "PEM_read_bio_PKCS7(...)".
I'm looking for either a way to validate it in the terminal or with C using OpenSSL. C is preferred ;) but I can always convert the command to code in case you only know how to do it manually.
If you want to do check the certificate chain using command-line tools, here is how:
unzip -p your.jar META-INF/*.RSA | openssl pkcs7 -inform DER -text -print_certs
I am an idiot. At the start of this project I knew that the signature format had to be either DER or PEM. I thought I had configured this correctly, but somehow it ended up in the situation where the Jarsigner's signature was in DER format when I wanted to verify a PEM signature.
My solution is to always expect a DER signature. This is default for the Jarsigner. For my OpenSSL signer/verifier I had to make sure the outform and inform was der: -outform der and -inform der.
Code wise I had to change this:
if (!(p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL))) {
into this:
if (!(p7 = d2i_PKCS7_bio(in, NULL))) {

Erratic openssl/rsa behaviour: RSA_EAY_PRIVATE_DECRYPT:padding check failed

I have written a program that runs permanently using <openssl/rsa> C library.
It basically decrypts a password given in argument. The problem is that sometimes it works flawlessly, and some other times it fails (with the same pubkey/privkey/password, returning this error:
message: error:04065072:rsa routines:RSA_EAY_PRIVATE_DECRYPT:padding check failed
Has anyone ever experienced that?
Why this kind of error is returned, generally?
Some more details
It retrieves the private key at the initialisation of the program with the following:
#define PRIVFILE "<correct-path>/privkey.pem"
EVP_PKEY *privKey;
int size_key;
FILE *fp = fopen(PRIVFILE, "r");
if (!fp)
{
<logs>
return -1;
}
PEM_read_PrivateKey(fp, &privKey, 0, NULL);
fclose (fp);
if (privKey == NULL)
{
ERR_print_errors_fp (stderr);
return -1;
}
size_key = EVP_PKEY_size(privKey);
Later, during a listening loop, a method call the private decryption algorithm
int len_enc = size_key;
unsigned char* enc_pw;
unsigned char* dec_pw;
int len_dec = 8;
char* err = malloc(130);
enc_pw = malloc(len_enc);
dec_pw = malloc(len_dec);
memset(enc_pw, 0, len_enc);
memset(dec_pw, 0, len_dec);
memcpy(enc_pw, value, len_enc); //value being the raw ciphered data to decrypt
ERR_load_crypto_strings();
if (RSA_private_decrypt(len_enc, enc_pw, dec_pw, privKey->pkey.rsa,RSA_PKCS1_OAEP_PADDING) == -1)
{
ERR_error_string(ERR_get_error(), err);
radlog(L_ERR, "message: %s", err);
}
free(enc_pw);
free(dec_pw);
free(err);
I have done encryption on the data with perl using Crypt::OpenSSL::RSA:
my $rsa_pub = Crypt::OpenSSL::RSA->new_public_key( $key_string);
my $ciphertext = $rsa_pub->encrypt( $plaintext);
There is some base64 encoding/decoding that i didn't mention to make it a little bit shorter. The problem does not come from that.
private key and public key are generated with openssl genrsa:
openssl genrsa -out privkey.pem 1024 and openssl rsa -in privkey.pem -pubout > pubkey.pub
It seems to work for some time, but occasionally (during a peak of request, if that matters) i get these errors for ciphered data that seemed valid before:
message: error:04065072:rsa routines:RSA_EAY_PRIVATE_DECRYPT:padding check failed
Is it a multi threaded application?
I was getting the same problem yesterday and, in my case, it was related to more than one thread using the key (one for decript and many others for encript). The problem was solved protecting the key with a mutex semaphore.
The service is up and stable since yesterday.

How do I decrypt a private key file and sign some text using openssl calls in C?

I have 2 separate programs (spliced together below). The first generates the key pair and saves to files (works fine). The second opens the private key, decrypting with a pass phrase and then I need it to sign a string of text. The code below fails on the PEM_read_PrivateKey() (last) call (can't see why). Can anyone point me at what I am doing wrong and then what openssl calls I should make to use the private key to sign some text?
int main (int argc, char *argv[])
{
char *priv_pem = "priv.pem";
char *pub_pem = "pub.pem";
char *pass = "Password";
FILE *fp;
int bits = 4096;
unsigned long exp = RSA_F4;
RSA *rsa;
EVP_PKEY *pkey;
// GENERATE KEY
rsa=RSA_generate_key(bits,exp,NULL,NULL);
if (RSA_check_key(rsa)!=1)
Exit(1,"Error whilst checking key","");
pkey = EVP_PKEY_new();
EVP_PKEY_assign_RSA(pkey, rsa);
// WRITE ENCRYPTED PRIVATE KEY
if (!(fp = fopen(priv_pem, "w")))
Exit(2,"Error opening PEM file",priv_pem);
if (!PEM_write_PrivateKey(fp,pkey,EVP_aes_256_cbc(),NULL,0,NULL,pass))
Exit(3,"Error writing PEM file",priv_pem);
fclose(fp);
// WRITE PUBLIC KEY
if (!(fp = fopen(pub_pem, "w")))
Exit(4,"Error opening PEM file",pub_pem);
if (!PEM_write_PUBKEY(fp, pkey))
Exit(5,"Error writing PEM file",pub_pem);
fclose(fp);
// ------- End of key generation program -------
// ------- Start of text signing program -------
// READ IN ENCRYPTED PRIVATE KEY
if (!(fp = fopen(priv_pem, "r")))
Exit(6,"Error reading encrypted private key file",priv_pem);
if (!PEM_read_PrivateKey(fp,&pkey,NULL,pass))
Exit(7,"Error decrypting private key file",priv_pem);
fclose(fp);
// Sign some text using the private key....
// FREE
RSA_free(rsa);
return 0;
}
Have you initialised pkey to NULL before you pass &pkey to PEM_read_PrivateKey()? If not, it will attempt to re-use the EVP_PKEY structure that pkey points to - and if pkey is uninitialised, it will be looking at a random spot in memory.
You can use ERR_print_errors_fp(stderr); to dump the OpenSSL error stack to stderr when an error occurs - this is often helpful in finding the problem.
Thanks #caf for your help.
By trial and error I fixed PEM_read_PrivateKey() error by adding the following to the start:
if (EVP_get_cipherbyname("aes-256-cbc") == NULL)
OpenSSL_add_all_algorithms();
However, I'm still looking for the best (practice) way of generating the keys and then using the private key for signing. From my limited understanding, I am looking for openssl methods that adhere to RSA's "PKCS #1 v2.0: RSA Cryptography Standard"

Resources