Is there any OpenSSL function to convert PKCS7 file to PEM - c++

Is there any openssl api function to convert PKCS7 file to PEM. I am able to convert a PKCS12 file to PEM using PKCS12_parse() function which returns key and certificate given the password. There is no similar function for pkcs7.
My pkcs7 input has just the certificate in binary format. I am able to do the conversion using command
openssl pkcs7 -inform DER -in input.p7b -printcerts -text
How do I do this in a C program? I am able to read it to a PKCS7 structure like this
FILE* fp;
if (!(fp = fopen("ca.p7b", "rb"))) {
fprintf(stderr, "Error reading input pkcs7 file\n" );
exit(1);
}
PKCS7 *p7;
p7 = d2i_PKCS7_fp(cafp, NULL);

After some googling I am able to do that.
if(p7->d.sign->cert != NULL){
PEM_write_X509(fp, sk_X509_value(p7->d.sign->cert, 0));
}
where p7 is a pointer to pkcs7 struct and fp is the file pointer to PEM file

Related

Convert DER encoded X509 certificate buffer to windows CERT_CONTEXT structure

I have a X509 certificate, which was created using OpenSSL and exported to DER blob using OpenSSL i2d_X509() function.
Is there any way to convert DER certificate blob into Windows CERT_CONTEXT structure?
I know, that it could be done using temporary file, CertOpenStore(CERT_STORE_PROV_FILENAME) and CertEnumCertificatesInStore() functions. But could not find any way without using temporary file.
Got it.
It can be done using ::CertCreateCertificateContext function:
std::vector<BYTE> certificate;
// ... acquire DER encoded certificate using i2d_X509()
// ...
PCCERT_CONTEXT context = ::CertCreateCertificateContext(
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
certificate.data(),
certificate.size());
// ...
// ...
::CertFreeCertificateContext(context);

Microsoft CryptoAPI: how to convert PUBLICKEYBLOB to DER/PEM?

I have a generated RSA key pair stored as PRIVATEKEYBLOB and PUBLICKEYBLOB, and I need to be able to convert these keys to DER or PEM formats so I could use it in PHP or Python. I figured out that I could use CryptEncodeObject function to convert my PRIVATEKEYBLOB to DER. In order to do that I need to use PKCS_RSA_PRIVATE_KEY encoding flag. But I couldn't find any clue on how to convert PUBLICKEYBLOB to DER.
Here is my code for PRIVATEKEYBLOB convertion:
LPCSTR type = PKCS_RSA_PRIVATE_KEY;
DWORD encd = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
DWORD dlen = 0;
if(!CryptEncodeObject(encd, type, key, null, &dlen))
{ LOG_ERROR(); return false; }
// Buffer allocation (der variable)
if(!CryptEncodeObject(encd, type, key, der, &dlen))
{ LOG_ERROR(); return false; }
I test my keys by comparing them to the output of openssl tool:
openssl rsa -pubin -inform MS\ PUBLICKEYBLOB -in pub.ms -outform DER -out pub.der
openssl rsa -inform MS\ PRIVATEKEYBLOB -in pri.ms -outform DER -out pri.der
ADDED: I tried RSA_CSP_PUBLICKEYBLOB with X509_ASN_ENCODING, but the result is different to the output of openssl tool, and the key import failes. The openssl's exported DER is 25 bytes longer, and only first 3 bytes are equal in both keys. Here is the picture of key comparison:
If we look closely at this picture, we can see that openssl's key version has some kind of additional 24 bytes header after the 3rd byte. Haven't figured out what is it as of yet, but if I concatinate this hardcoded header with the output I get from CryptEncodeObject with RSA_CSP_PUBLICKEYBLOB it all works fine. Not sure if that header is always the same or not though.
Use RSA_CSP_PUBLICKEYBLOB as documented in
https://msdn.microsoft.com/en-us/library/windows/desktop/aa378145(v=vs.85).aspx
I struggled with PUBLICKEYBLOB -> PEM/DER formats until I found a post about pulling one from a smart card and converting it. The gist of it is, MS PUBLICKEYBLOB needs to have the first 32 bytes removed, then reverse the order and add 02 03 01 00 01 to the end. That will give you DER format. You can then base64 encode to get PEM and then add the requisite begin/end public key lines.
You can refer to the original post for background.

Load PEM encoded private RSA key in Crypto++

Often times, user will have PEM encoded RSA private keys. Crypto++ requires that these keys be in DER format to load. I've been asking people to manually convert their PEM files to DER beforehand using openssl like this:
openssl pkcs8 -in in_file.pem -out out_file.der -topk8 -nocrypt -outform der
That works fine, but some people don't understand how to do that nor do they want to. So I would like to convert PEM files to DER files automatically within the program.
Is it as simple as striping the "-----BEGIN CERTIFICATE-----" and "-----END CERTIFICATE-----" from the PEM or is some other transformation required as well? I've been told that between those markers that it's just b64 encoded DER. Here's some code that demonstrates the issue:
// load the private key
CryptoPP::RSA::PrivateKey PK;
CryptoPP::ByteQueue bytes;
try
{
CryptoPP::FileSource File( rsa.c_str(), true, new CryptoPP::Base64Decoder() );
File.TransferTo( bytes );
bytes.MessageEnd();
// This line Causes BERDecodeError when a PEM encoded file is used
PK.Load( bytes );
}
catch ( CryptoPP::BERDecodeErr )
{
// Convert PEM to DER and try to load the key again
}
I'd like to avoid making system calls to openssl and do the transformation entirely in Crypto++ so that users can provide either format and things "just work". Thanks for any advice.
Yes, it's a DER stream encoded with Base64. Note though, in addition to striping both BEGIN and END markers, in case of RSA key format you also need to strip any flags that may be inserted between the BEGIN marker and the encoded data. Only the remaining part can be successfully Base64 decoded. It appears that you feed the full certificate file to the decoder and that needs fixing.
... I would like to convert PEM files to DER files automatically within the program.
In July 2014, a PEM Pack was provided for the Crypto++ library. The PEM Pack is a partial implementation of message encryption which allows you to read and write PEM encoded keys and parameters, including encrypted private keys. The additional files include support for RSA, DSA, EC, ECDSA keys and Diffie-Hellman parameters.
Its an add-on to the library, and not part of the library proper. You download a ZIP and add five source files to the library. Then you build the library (Crypto++ automatically picks them up). The ZIP contains five additional source files, a script to create test keys using OpenSSL, a C++ program to test reading and writing the keys, and a script to verify the keys written by Crypto++ using OpenSSL.
Here's how you would use it:
CryptoPP::RSA::PrivateKey pk;
CryptoPP::FileSource file("<rsa-key-file.pem>", true);
CryptoPP::PEM_Load(file, pk);
CryptoPP::AutoSeededRandomPool prng;
bool = pk.Validate(prng, 3);
if (! valid)
throw ...
If the keys is encrypted, then here's how you would load it. The PEM Pack re-implement's OpenSSL's EVP_BytesToKey, so the key derivation will work and you can interop:
CryptoPP::RSA::PrivateKey pk;
CryptoPP::FileSource file("<rsa-key-file.pem>", true);
std::string pass = "<super secret password>";
CryptoPP::PEM_Load(file, pk, pass.data(), pass.size());
CryptoPP::AutoSeededRandomPool prng;
bool = pk.Validate(prng, 3);
if (! valid)
throw ...
There's also a PEM_Save, so you can write the keys directly from Crypto++. For example:
// Generate it or load it from somewhere
CryptoPP::RSA::PrivateKey pk = ...;
CryptoPP::FileSink file("<rsa-key-file.pem>", true);
CryptoPP::PEM_Save(file, pk);
And PEM_Save for an encrypted key (or key you intend to encrypt):
// Generate it or load it from somewhere
CryptoPP::RSA::PrivateKey pk = ...;
CryptoPP::FileSink file("<rsa-key-file.pem>", true);
std::string pass = "<super secret password>";
CryptoPP::PEM_Save(file, pk, "AES-128-CBC", pass.data(), pass.size());
PEM_Load does not need an algorithm because its encoded in the encapsulated header. PEM_Save needs an algorithm because there is no default algorithm.
I know this is an old question but other's might find this useful. Once you strip the markers you're left with the 'inner' key material. According to http://www.cryptopp.com/wiki/Keys_and_Formats#BER_and_DER_Encoding you can use BERDecodePrivateKey to load this. So, to load an openssl key that has had its markers stripped you can do something like
bool LoadKey(RandomNumberGenerator& rng, const std::string& file,
RSA::PrivateKey& key)
{
ByteQueue q;
FileSource KeyFile(file.c_str(), true, new Base64Decoder);
KeyFile.TransferTo(q);
key.BERDecodePrivateKey(q,false,0); // last 2 params unused
return key.Validate(rng, 2);
}

Is a X509 certificate in DER format ASN1 encoded?

I'm using OpenSSl to encrypt and decrypt files based on CMS/SMIME. Normally I load certificates with rcert = PEM_read_bio_X509(tbio, NULL, 0, NULL); but this is only for PEM formatted files I guess. I haven't found any der.h header or something similar.
So is there a way in OpenSSL to load DER formatted certificates? I've found the load function for ASN1 format which uses OpenSSL intern.
if (format == FORMAT_ASN1)
x=d2i_X509_bio(cert,NULL);
But can that be used for DER which is binary?
DER is indeed encoded using ASN.1, and the d2i_*() family of functions is the way to load a DER file.

OpenSSL command to C++ [duplicate]

Is there any openssl api function to convert PKCS7 file to PEM. I am able to convert a PKCS12 file to PEM using PKCS12_parse() function which returns key and certificate given the password. There is no similar function for pkcs7.
My pkcs7 input has just the certificate in binary format. I am able to do the conversion using command
openssl pkcs7 -inform DER -in input.p7b -printcerts -text
How do I do this in a C program? I am able to read it to a PKCS7 structure like this
FILE* fp;
if (!(fp = fopen("ca.p7b", "rb"))) {
fprintf(stderr, "Error reading input pkcs7 file\n" );
exit(1);
}
PKCS7 *p7;
p7 = d2i_PKCS7_fp(cafp, NULL);
After some googling I am able to do that.
if(p7->d.sign->cert != NULL){
PEM_write_X509(fp, sk_X509_value(p7->d.sign->cert, 0));
}
where p7 is a pointer to pkcs7 struct and fp is the file pointer to PEM file