Is a X509 certificate in DER format ASN1 encoded? - c++

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.

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);

Read X509-Certificate to process it

I need to read a X509 certificate in C++. I couldn't find a way to do that with the GnuTLS library. The certificate has to be read in PEM or DER format, so that I can process it twith functions of the GnuTLS library. Is there a pendant to the bio files provided in openssl, which allow me to read the certificate and concert it into processable format?
Actually it is important to generate a variable which contains a tuple of the certificate and the length of the certificate. The certificate can be read using fopen() and fread(). The tuple can be processed with gnutls_x509_crt_import(). That solves the problem for me.

Parse DER x509 in C or C++

I am writting a program in C/C++ on a linux plattofrm to parse X509. Most importantly right now is the public key but I might need other info as well.
I have used the code (in Open SSL) from this post http://www.zedwood.com/article/c-openssl-parse-x509-certificate-pem and it works fine, but my certifcates are in DER format and I therefore need to convert them prior to this (which I can do in the command prompt).
What I need is to do this conversion in code, or other code that does the same on DER certificate directly.
I have tried to replace som components in the code to make it DER instad of PEM but no luck (have been trying to use some id2 commands but I am not even sure if that is correct).
Any help would be apprectiated.
simply use d2i_X509_bio instead of PEM_read_bio_X509 to read the certificate. See how to convert the Certificate String into X509 structure.? and http://www.openssl.org/docs/crypto/d2i_X509.html

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);
}

Converting between Windows CryptoAPI and OpenSSL x509 formats

I have a CERT_CONTEXT structure which I've extracted from a smart card on Windows via the CryptoAPI. I need to convert this structure into a DER encoded byte array which is consistent with OpenSSL. The closest match I've got so far is via CryptEncodeObject using X509_ASN_ENCODING and the X509_CERT_TO_BE_SIGNED modifier which takes the CERT_INFO structure as input.
The problem is that it doesn't match with the output produced by the OpenSSL i2d_X509 function. Using a 2048 bit x509 certificate as input, OpenSSL produces 1789 bytes of encoded output whilst the Windows CryptoAPI produces 1638 bytes of encoded output.
The only option left that I can see is to create an X509 cert on the fly using the values from the CERT_CONTEXT structure and the encode the resulting object directly with the i2d_X509 function. The only problem with this is that I can't extract the private key from the smart card, so this may cause problems with the x509 cert creation routines.
If anyone can provide any insight/advice/tips into these matters, I'd be much obliged.
DER encoded certificate can be obtained from (ctx->pbCertEncoded, ctx->cbCertEncoded) buffer where ctx is a PCCERT_CONTEXT object. Still you won't be able to recover the private key.