Converting a SSL Cert string into a valid X509_STORE_CTX - c++

I'm trying to get both of these certs into a X509_STORE_CTX, but when I go to read them out, they are both NULL. Any ideas?
The certs look like:
// Not the real certs. Just trying to illustrate that the certs are just a new line
// delimited string
const char *certA = "-----BEGIN CERTIFICATE-----\nMIIGWDCCBUCgAwI......\n.....\n"
SSL_library_init();
SSL_CTX * sslCtx = SSL_CTX_new(SSLv23_client_method());
X509_STORE *store = SSL_CTX_get_cert_store(sslCtx);
X509_STORE_CTX *store_ctx = X509_STORE_CTX_new();
BIO *bio;
X509 *certificate;
/*First cert*/
bio = BIO_new(BIO_s_mem());
BIO_write(bio,(const void*)certA ,sizeof(certA));
certificate = PEM_read_bio_X509(bio, NULL, NULL, NULL);
X509_STORE_add_cert(store, certificate);
/*second cert*/
bio = BIO_new(BIO_s_mem());
BIO_write(bio,(const void*)certB ,sizeof(certB));
certificate = PEM_read_bio_X509(bio, NULL, NULL, NULL);
X509_STORE_add_cert(store, certificate);
X509_STORE_CTX_init(store_ctx, store, NULL, NULL);

sizeof(certA) here will provide just the size of that const char* variable, which is the size of a pointer (mostly 4 or 8).
Try declaring the certificate contents as static const char certA[] instead.
Also using BIO_puts() and avoiding the sizeof() completely might be easier.

Related

How to store a private key and a certificate in a x509_STORE_CTX

I need a x509_STORE_CTX for Unreal engine to add the certificate to the SSL configuration. Right now I have this code
FILE* file = fopen(pathToPrivKey, "rb");
EVP_PKEY* privKey = PEM_read_PrivateKey(file, NULL, NULL, NULL);
fclose(file);
file = fopen(pathToCert, "rb");
X509* x509 = PEM_read_X509(file, NULL, NULL, NULL);
fclose(file);
X509_STORE* store = X509_STORE_new();
X509_STORE_CTX* ctx = X509_STORE_CTX_new();
X509_STORE_add_cert(store, x509);
X509_STORE_CTX_init(ctx, store, NULL, NULL);
int rc = X509_verify_cert(ctx);
int err = X509_STORE_CTX_get_error(ctx);
Having this, the results for rc and err are -1 and 69 respectively, so there is something wrong but I don't know what (I must say that I am pretty new to OpenSSL and what I did might not make any sense). I have tried before to validate the private key and got a good result, so I think that there might be something wrong in the way I am doing the rest.

Loading certificates from string buffers into chain for client verification using OpenSSL

I am trying to use SSL client verification to connect to a remote AWS IoT endpoint. I have three files:
- CA Root Certificate File
- Certificate File
- Private Key
The connection to the endpoint is successful if I use SSL_CTX_load_verify_locations, SSL_CTX_use_certificate_chain_file and SSL_CTX_use_PrivateKey_file.
if (!SSL_CTX_load_verify_locations(p_ssl_context_, root_ca_location_.c_str(), NULL)) {
AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, " Root CA Loading error");
return ResponseCode::NETWORK_SSL_ROOT_CRT_PARSE_ERROR;
}
// TODO: streamline error codes for TLS
if (0 < device_cert_location_.length() && 0 < device_private_key_location_.length()) {
AWS_LOG_DEBUG(OPENSSL_WRAPPER_LOG_TAG, "Device crt : %s", device_cert_location_.c_str());
if (!SSL_CTX_use_certificate_chain_file(p_ssl_context_, device_cert_location_.c_str())) {
AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, " Device Certificate Loading error");
return ResponseCode::NETWORK_SSL_DEVICE_CRT_PARSE_ERROR;
}
AWS_LOG_DEBUG(OPENSSL_WRAPPER_LOG_TAG, "Device privkey : %s", device_private_key_location_.c_str());
if (1 != SSL_CTX_use_PrivateKey_file(p_ssl_context_,
device_private_key_location_.c_str(),
SSL_FILETYPE_PEM)) {
AWS_LOG_ERROR(OPENSSL_WRAPPER_LOG_TAG, " Device Private Key Loading error");
return ResponseCode::NETWORK_SSL_KEY_PARSE_ERROR;
}
}
certificates_read_flag_ = true;
However, the call doesn't work if I construct the chain manually by adding the certificates using string buffers. The error returned is "An unknown occurred while waiting for the TLS handshake to complete.".
X509_STORE* store = SSL_CTX_get_cert_store(p_ssl_context_);
X509 *rootCACertificate, *deviceCertificate;
RSA *privateKey;
BIO *bio;
std::string rootCACertificateBuffer;
std::string deviceCertificateBuffer;
std::string privateKeyBuffer;
rootCACertificateBuffer =
"-----BEGIN CERTIFICATE-----\n"
"-----END CERTIFICATE-----\n";
deviceCertificateBuffer =
"-----BEGIN CERTIFICATE-----\n"
"-----END CERTIFICATE-----\n";
privateKeyBuffer =
"-----BEGIN RSA PRIVATE KEY-----\n"
"-----END RSA PRIVATE KEY-----\n";
bio = BIO_new(BIO_s_mem());
BIO_puts(bio, rootCACertificateBuffer.c_str());
rootCACertificate = PEM_read_bio_X509(bio, NULL, 0, NULL);
X509_STORE_add_cert(store, rootCACertificate);
BIO_free(bio);
bio = BIO_new(BIO_s_mem());
BIO_puts(bio, deviceCertificateBuffer.c_str());
deviceCertificate = PEM_read_bio_X509(bio, NULL, 0, NULL);
X509_STORE_add_cert(store, deviceCertificate);
BIO_free(bio);
bio = BIO_new(BIO_s_mem());
BIO_puts(bio, privateKeyBuffer.c_str());
privateKey = PEM_read_bio_RSAPrivateKey(bio, NULL, 0, NULL);
SSL_CTX_use_RSAPrivateKey(p_ssl_context_, privateKey);
BIO_free(bio);
SSL_CTX_build_cert_chain(p_ssl_context_,SSL_BUILD_CHAIN_FLAG_CHECK );
certificates_read_flag_ = true;

Verify signature in C++

I have a function that verifies signature in C++ using Openssl functions.
the verify does not work.
int verify(char *msg, int msg_len, char *signature, int signature_len, char *cert_str, int cert_len) {
X509* cert = d2i_X509(NULL, &cert_str, cert_len);
EVP_PKEY* key = X509_get_pubkey(cert);
EVP_MD_CTX* ctx = EVP_MD_CTX_create();
EVP_MD_CTX_init(ctx);
X509_ALGOR *palg = NULL;
ASN1_OBJECT *paobj = NULL;
X509_get0_signature(NULL, &palg, cert);
TRACE_ASSERT(T_PLUGIN, palg);
X509_ALGOR_get0(&paobj, NULL, NULL, palg);
int alg = OBJ_obj2nid(paobj);
const EVP_MD* md = EVP_get_digestbynid(alg);
EVP_VerifyInit_ex(ctx, md, NULL);
EVP_VerifyUpdate(ctx, msg, msg_len);
return EVP_VerifyFinal(ctx, signature, signature_len, key) == 1);
for some unknown reason the verify return 0 on things that should pass verification.
the msg, signature and cert_str are bytearrays converted to char*.
the conversions work fine as far as I've checked.
Am I missing anything, did something wrong?
Thanks.

BIO to EVP_PKEY (Public and Private)

I am stuck on how to convert a BIO* to its EVP_PKEY counterparts so that i can later use it in encryption. Currently my keygen routine looks like this:
bool SecureCrypto::GenerateRSAKeys()
{
BIGNUM* BigNum = nullptr;
BIGNUM* BigNum2 = nullptr;
BigNum = BN_new();
if (BN_set_word(BigNum, RSA_F4) <= 0)
return false;
BigNum2 = BN_new();
if (BN_set_word(BigNum2, RSA_F4) <= 0)
return false;
m_ServerKeyPair = RSA_new();
m_ClientKeyPair = RSA_new();
RSA_generate_key_ex(m_ServerKeyPair,RSA_KeyLen, BigNum, NULL);
RSA_generate_key_ex(m_ClientKeyPair,RSA_KeyLen, BigNum2, NULL);
PEM_write_bio_RSAPublicKey(m_ServerPublicKeyBIO, m_ServerKeyPair);
PEM_write_bio_RSAPrivateKey(m_ServerPrivateKeyBIO,
m_ServerKeyPair,EVP_aes_256_cbc(), (unsigned char*)RSA_PrivKeyPassPhrase.c_str(),
RSA_PrivKeyPassPhrase.size(), NULL, NULL);
PEM_write_bio_RSAPublicKey(m_ClientPublicBIO, m_ClientKeyPair);
PEM_write_bio_RSAPrivateKey(m_ClientPrivateBIO, m_ClientKeyPair, EVP_aes_256_cbc(),
(unsigned char*)RSA_PrivKeyPassPhrase.c_str(), RSA_PrivKeyPassPhrase.size(), NULL,
NULL);
BN_free(BigNum);
BN_free(BigNum2);
return true;
}
Later on i need to convert m_ServerPrivateKeyBIO into a EVP_PKEY for use with EVP_SealInit.
I only know of PEM_read_bio_PrivateKey(), but everytime i call it i get a return value of 0 (fail).I call it as such:
PEM_read_bio_PrivateKey(m_ServerPrivateKeyBIO, NULL, NULL, "Enc Key");
I plan on the server doing encryption with its private key then sending data to client and client decrypting it with the servers public key, i would appreciate any help here, as the OpenSSL docs don't help at all.
P.S i have client and server keys being generated for a test, obviously this would not happen in final code.

How do I get the RSA* object from a char array that contains the public key in OpenSSL?

Im trying to encrypt and decrypt messages while storing the private and public keys on char vectors. I have tried d2i_PublicKey(...) and using EVP_PKEY objects in EVP_set1_RSA(...). I also do not know what are all the parameters in EVP_set1_RSA(...). Please help. Here is my code:
#include <stdio.h>
//RSA
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <arpa/inet.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/x509.h>
#define RSA_KEY_LENGTH 2048
#define PUB_EXP 3
#define PRINT_KEYS
//RSA
int main()
{
printf("\ngenerating keys...\n");
RSA *keypair = RSA_generate_key(RSA_KEY_LENGTH, PUB_EXP, NULL, NULL);
// ---------
printf("Converting Keys to char array..\n");
char *pri_key = NULL; // Private key
char *pub_key = NULL; // Public key
size_t pri_len; // Length of private key
size_t pub_len; // Length of public key
BIO *pri = BIO_new(BIO_s_mem());
BIO *pub = BIO_new(BIO_s_mem());
PEM_write_bio_RSAPrivateKey(pri, keypair, NULL, NULL, 0, NULL, NULL);
PEM_write_bio_RSAPublicKey(pub, keypair);
pri_len = BIO_pending(pri);
pub_len = BIO_pending(pub);
pri_key = (char*)malloc(pri_len + 1);
pub_key = (char*)malloc(pub_len + 1);
BIO_read(pri, pri_key, pri_len);
BIO_read(pub, pub_key, pub_len);
pri_key[pri_len] = '\0';
pub_key[pub_len] = '\0';
// ---------
char msg[RSA_KEY_LENGTH/8] = "HOLA, ESPERO QUE ME ENCRIPTES";
char *encrypt = NULL; // Encrypted message
char *decrypt = NULL; // Decrypted message
printf("encrypting: %s\n", msg);
/*
* Here I want to obtain an RSA *PublicKey to use it for the encryption
*/
int encrypt_len;
err = (char*)malloc(130);
printf("++++\n");
if((encrypt_len = RSA_public_encrypt(strlen(msg), (unsigned char*)msg, (unsigned char*)encrypt, PublicKey, RSA_PKCS1_OAEP_PADDING)) == -1) {
printf("err++++\n");
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), err);
fprintf(stderr, "Error encrypting message: %s\n", err);
}
return 0;
}
I've found a solution to this issue among other Stack-Overflow posts and namely here :Reading Public/Private Key from Memory with OpenSSL
The answer you waere looking for is answered by #SquareRootOfTwentyThree is his last line of code,
After extracting the Public key into a BIO variable called pub:
PEM_write_bio_RSAPublicKey(pub, keypair);
create a RSA variable and put pub inside it:
RSA *keypair2 = NULL;
PEM_read_bio_RSAPublicKey( pub, &keypair2, NULL, NULL);
After you've done this you can successfully encrypt the message as usual, using keypair2:
Encryption:
encrypt = (char*)malloc(RSA_size(keypair));
int encrypt_len;
err = (char*)malloc(130);
if((encrypt_len = RSA_public_encrypt(strlen(msg)+1, (unsigned char*)msg, (unsigned char*)encrypt, keypair2 ,RSA_PKCS1_OAEP_PADDING)) == -1) {
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), err);
fprintf(stderr, "Error encrypting message: %s\n", err);
}
you can then decrypt it as usual, using the original keypair, without having to use it at your first encryption
Decryption:
decrypt = (char*)malloc(encrypt_len);
if(RSA_private_decrypt(encrypt_len, (unsigned char*)encrypt, (unsigned char*)decrypt, keypair, RSA_PKCS1_OAEP_PADDING) == -1) {
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), err);
fprintf(stderr, "Error decrypting message: %s\n", err);
}
This might help if you want to transfer the "pub" variable over a network, use it to encrypt a message, then send the encrypted data back to the original machine to get it decrypted.
If you really want to use char variables, as you said in your question, you can of course copy the memory as raw to a char variable (from the BIO one) using memcpy, but don't forget to add the "\0" at the end, here, this post should help: Separating public and private keys from RSA keypair variable