Convert X509_STORE_load_locations() call to load data from Memory - c

How can I convert the code below to load the file "cabundle.pem" from memory? The code is used in certificate verification (Source)
const char ca_bundlestr[] = "./cabundle.pem";
ret = X509_STORE_load_locations(store, ca_bundlestr, NULL);`
So what I currently did is put the cabundle.pem in string array and then add the cert to the store but it doesnt work since what I think I need to do is add it to the store using X509_STORE_CTX_trusted_stack but I do not know how to use STACK_OF(X509) I tried searching but I cant find anything.
const char ca_bundle[] = "-----BEGIN CERTIFICATE-----\n"
"MIIImDCCCD2gAwIBAgIRAMch/W0685E2zrArUB/79kUwCgYIKoZIzj0EAwIwgZIx\n"
"MIIImDCCC...............................................AwIwgZIx\n"
"CzAJBgNVB..........................................0ZXIxEDAOBgNV\n"
"-----END CERTIFICATE-----\n";
BIO *bio;
X509 *cert;
bio = BIO_new(BIO_s_mem());
BIO_puts(bio, ca_bundle);
cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
X509_STORE_add_cert(store, cert);
So how can I load my string array ca_bundle into a STACK_OF(X509) variable? Or if there is another way to do this please let me know. Thanks

I asked too early. I just found the answer to my question. Since the cabundle.pem contains more than 1 certificate you need to do it in a loop and read the next certificate then add it again to the store. You do not need the X509_STORE_CTX_trusted_stack since adding all the certificates to the store acts the same way as calling X509_STORE_load_locations
while (cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) {
X509_STORE_add_cert(store, cert);
}

Related

Writing PEM RSA private key in C

Hello i want my function to write a pem file from my RSA.
void write_privatekey(RSA *rsa, BIO *keybio)
{
EVP_PKEY *pkey;
BIO *bio_private;
pkey = PEM_read_bio_PrivateKey(keybio, &pkey, 0, 0);
bio_private = BIO_new_file("private_new.pem", "w+");
PEM_write_bio_PrivateKey(bio_private, pkey, NULL, NULL, 0, NULL, NULL);
}
but when i try to run this code it segfault
[1] 48767 segmentation fault ./corsair public.key
The OpenSSL APIs are not the most intuitive to use. However it should be a huge warning sign for you, that you passed a pointer to pkey to PEM_read_bio_PrivateKey and also assign its return value to it.
If you look at the reference manual the suggested stanza is
key = PEM_read_bio_PrivateKey(bp, NULL, pass_cb, …);
if( key == NULL ){
/* Error */
}
Your code snipped lacks a couple of things: It doesn't provide a pass phrase callback and it doesn't perform error checking. You absolutely must do both things.
After messing with the OpenSSL lib. and learned a way to dive into it documentation.
here it is the answer to write the PEM file from RSA object.
BIO *bio_private;
bio_private = BIO_new_file("private_new.pem", "w+");
PEM_write_bio_RSAPrivateKey(bio_private, rsa, 0, 0, 0, 0, 0);

Extracting the public certificate from a certificate

I would like to programmatically generate a certificate that contain only the public key using openssl.
So I basically need to do the following but using code.
openssl x509 -in certificate.crt -pubkey
Digging a bit it seem that I need to create a new certificate and copy all the information except the private key in it.
X509 * pNewKey = X509_new();
... Copy all the needed information ...
PEM_write_bio_X509(bioKey, &pNewKey, NULL, NULL);
Does someone have a better method?
I would like to programmatically generate a certificate that contain only the public key
To set the public key, take your public key in EVP_PKEY format and call X509_set_pubkey. Building upon your example code:
X509* x509 = X509_new();
EVP_PKEY* pkey = /***/;
int rc = X509_set_pubkey(x509, pkey);
ASSERT(rc == 1);
BIO* bio = BIO_new_file("filename.txt", "w");
ASSERT(bio != NULL);
rc = PEM_write_bio_X509(bio, x509, NULL, NULL);
ASSERT(rc == 1);
...
BIO_free(bio);
EVP_PKEY_free(pkey);
X509_free(x509);
For completeness, OpenSSL will save a certificate with no attributes, no version, no public key, and no signature.
So I basically need to do the following but using code.
openssl x509 -in certificate.crt -pubkey
OK, this is a different question. The above command will print the public key.
Use x509_get_pubkey:
EVP_PKEY* pkey = X509_get_pubkey(X509* x509);
Once you have the EVP_PKEY, you can get the type. You need to supply this function because OpenSSL does not provide it:
int EVP_PKEY_get_type(EVP_PKEY *pkey)
{
AC_ASSERT(pkey);
if (!pkey)
return NID_undef;
return EVP_PKEY_type(pkey->type);
}
Then, depending on the type, you can print the key:
if(type == EVP_PKEY_RSA || type == EVP_PKEY_RSA2)
{
RSA* rsa = EVP_PKEY_get1_RSA(pkey);
RSA_print_fp(stdout, rsa, 0);
RSA_free(rsa);
}
...
You have to break out the keys by type and then call the respective XXX_print_fp because OpenSSL does not provide an EVP_PKEY_print_fp.
The get1 in EVP_PKEY_get1_RSA means the reference count on the key is bumped. So you have to call a *_free on it. A get0 does not bump the reference count, and does not need a call to *_free.

How to encrypt data using RSA, with SHA-256 as hash function and MGF1 as mask generating function?

I was doing some experiments with cryptography. Now I have the public key of receiver and i want to encrypt some data and pass to the receiver.
I want to use RSAES-OAEP algorithm. with SHA-256 as hash function and MGF1 as mask generation function.
I want do this using openssl. I found a function RSA_public_encrypt() with this function we can specify the padding. One of the padding option available was
RSA_PKCS1_OAEP_PADDING
EME-OAEP as defined in PKCS #1 v2.0 with SHA-1 , MGF1 .
they are using sha-1.
I want to reconfigure the function to use SHA256 as hash function ans MGF1 as hash function. How can I do it ?
The following excerpt allows using OAEP with SHA256 for both the MGF and hash function. Tested with OpenSSL 1.0.2L
int flags = CMS_BINARY | CMS_PARTIAL | CMS_KEY_PARAM;
cms = CMS_encrypt(NULL, in, cipher, flags)
ri = CMS_add1_recipient_cert(cms, cert, flags);
pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_OAEP_PADDING);
EVP_PKEY_CTX_set_rsa_oaep_md(pctx, EVP_sha256());
EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, EVP_sha256());
With a newer OpenSSL 1.0.2+ you can do it using the command:
openssl pkeyutl -in PlaintextKeyMaterial.bin -out EncryptedKeyMaterial.bin -inkey PublicKey.bin -keyform DER -pubin -encrypt -pkeyopt rsa_padding_mode:oaep
-pkeyopt rsa_oaep_md:sha256
This is taken from AWS KMS doc here: https://aws.amazon.com/es/premiumsupport/knowledge-center/invalidciphertext-kms/
OpenSSL uses definitions from PKCS #1 v2.0 and so the default for EME-OAEP is SHA-1 and MGF1. If you need to use SHA-256, you'll need to do the encoding yourself. This isn't terribly difficult however, see PKCS #1 v2.2 PDF Page 18 for details.
In the latest version of Openssl(1.0.2k) the signature of the API is changed which gives us more flexibility. Please find the details below,
int RSA_padding_check_PKCS1_OAEP_mgf1(unsigned char *to, int tlen,
const unsigned char *from, int flen,
int num, const unsigned char *param,
int plen, const EVP_MD *md,
const EVP_MD *mgf1md)
You can pass the EVP_MD structure to invoke the SHA-256 hashing using this.
The PKCS#1 doc referred to above is more mathematical and doesn't give coding examples, and the CMS answer is for ASN.1/SMIME data and not really relevant for the question asked, which was how to replace RSA_public_encrypt() which deals with simple binary/text data. I spent a whole day with trial and error and online searching to find the answer to this, and eventually got the answer (which was to use OpenSSL's EVP API) from looking at the source code of "openssl pkeyutl" - once I discovered that it was not difficult.
In my case I was looking to replace RSA_private_decrypt() for decryption using the private key and this is how to do that - it should be pretty easy to put to together an RSA_public_encrypt() replacement based on this:
EVP_PKEY *privKey = NULL;
BIO *bioPrivKey;
int outLen = 0, ret;
if ((bioPrivKey = BIO_new(BIO_s_mem())))
{
// Read the private key from the RSA context into the memory BIO,
// then convert it to an EVP_PKEY:
if ((ret = PEM_write_bio_RSAPrivateKey(bioPrivKey, rsaCtxt, NULL, NULL, 0, NULL, NULL)) &&
(privKey = PEM_read_bio_PrivateKey(bioPrivKey, NULL, NULL, NULL)))
{
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(privKey, NULL);
EVP_PKEY_free(privKey);
if (ctx)
{
if (EVP_PKEY_decrypt_init(ctx) > 0)
{
EVP_PKEY_CTX_ctrl_str(ctx, "rsa_padding_mode", "oaep");
EVP_PKEY_CTX_ctrl_str(ctx, "rsa_oaep_md", "sha256");
EVP_PKEY_CTX_ctrl_str(ctx, "rsa_mgf1_md", "sha256");
outLen = dataOutMax;
ret = EVP_PKEY_decrypt(ctx, dataOut, &outLen, dataIn, inDataLen);
if (ret > 0 && outLen > 0 && outLen <= dataOutMax)
{
// Success :-)
}
}
EVP_PKEY_CTX_free(ctx);
}
}
BIO_free_all(bioPrivKey);
}
You can add error handling for the failure cases using ERR_get_error().

How to verify a X509 certificate in C

I have a certificate in X509 format. this a input parameters in a function.
What I would like to do is to verify the validity of the certificate.
How can it be done?
X509_verify_cert();
I found this function, but this does not accept a X509* certificate, it accepts X509_store and I only have a X509.
Thanks
best regards.
I am here just to post my answer as I found it with the above comments.
I had no certificate chain, so in the work I'm doing I only have a certificate generated by me programatically. I wanted to check the validity of it, so I created the following function, which checks the certificate against itself in other to verify the validity of it.
void check_certificate_validaty(X509* certificate)
{
int status;
X509_STORE_CTX *ctx;
ctx = X509_STORE_CTX_new();
X509_STORE *store = X509_STORE_new();
X509_STORE_add_cert(store, certificate);
X509_STORE_CTX_init(ctx, store, certificate, NULL);
status = X509_verify_cert(ctx);
if(status == 1)
{
printf("Certificate verified ok\n");
}else
{
printf("%s\n", X509_verify_cert_error_string(ctx->error));
}
}
Hope this helps someone :)
See the documentation here.
You need to create a certificate store using X509_STORE_CTX_new.
Then add certificate chain using X509_STORE_CTX_set_chain. Add trusted root certificate using X509_STORE_CTX_trusted_stack.
Finally add certificate to be verified using X509_STORE_CTX_set_cert.
After that call X509_verify_cert.
I hope this will help you to start on this.
To verify a certificate signature, you need the public key of an issuer certificate. This issuer certificate's signature is verified with another issuing certificate (or trusted root certificate). Thus if a certificate's signature verifies all the way up a chain to a trusted root, then that certificate is considered trusted.
Self-signed certificates' signatures are verified using their own public key, like the example below:
int verify_cert(const char* pem_c_str)
{
BIO *bio_mem = BIO_new(BIO_s_mem());
BIO_puts(bio_mem, pem_c_str);
X509 * x509 = PEM_read_bio_X509(bio_mem, NULL, NULL, NULL);
EVP_PKEY *pkey=X509_get_pubkey(x509);
int r= X509_verify(x509, pkey);
EVP_PKEY_free(pkey);
BIO_free(bio_mem);
X509_free(x509);
return r;
}
from: http://www.zedwood.com/article/openssl-c-verify-self-signed-certificate-signature

retrieve the client certificate chain from an ISAPI request

I would like to retrieve the entire client certificate chain from a request in ISAPI.
I already succeeded to get the first certificate in the client's certificate chain by invoking the code below:
LPEXTENSION_CONTROL_BLOCK ecb_;
...
CERT_CONTEXT_EX cce;
memset(&cce, 0, sizeof(CERT_CONTEXT_EX));
char certbuf[64*1024];
cce.cbAllocated = sizeof(certbuf);
cce.CertContext.pbCertEncoded = (BYTE *) &certbuf;
ecb_->ServerSupportFunction(ecb_->ConnID, HSE_REQ_GET_CERT_INFO_EX, &cce, 0, 0)
However, I did not find out how to retrieve the rest of the certificate chain from this CERT_CONTEXT_EX struct.
I just came across this old question. I'm sorry I didn't see it sooner.
Many years ago I wrote a sample that shows how do do this using CAPICOM. Unfortunately CAPICOM is being phased out by Microsoft, though it still works.
I found the old isapiCertPolicy sample on Koders:
http://www.koders.com/cpp/fid977D79B2C51AD2423E4F57B6B36C3806F167CF79.aspx
Here are the relevant code fragments:
#import "capicom.dll"
char CertificateBuf[8192];
CERT_CONTEXT_EX ccex;
ccex.cbAllocated = sizeof(CertificateBuf);
ccex.CertContext.pbCertEncoded = (BYTE*)CertificateBuf;
ccex.dwCertificateFlags = 0;
DWORD dwSize = sizeof(ccex);
fOk = pCtxt->ServerSupportFunction(
(enum SF_REQ_TYPE)HSE_REQ_GET_CERT_INFO_EX,
(LPVOID)&ccex,
&dwSize,
NULL);
_bstr_t bstrCert(
SysAllocStringLen(
(OLECHAR * )ccex.CertContext.pbCertEncoded,
(ccex.CertContext.cbCertEncoded+1)/2),
FALSE);
CAPICOM::ICertificate2Ptr Cert(__uuidof(CAPICOM::Certificate));
Cert->Import(bstrCert);
CAPICOM::IChainPtr Chain(__uuidof(CAPICOM::Chain));
BOOL fOk = Chain->Build(Cert);
CAPICOM::ICertificatesPtr Certs(NULL);
Certs = Chain->Certificates;
CAPICOM::ICertificate2Ptr ParentCert(Certs->Item[2])
The Chain object builds the certificate chain. If you can't use CAPICOM, you can get the certificate chain using the Crypto API's CertGetCertificateChain function, but it's more work.

Resources