Update
I have based my solution on this and this answers.
Background
I am trying to read a DER formatted certificate file and attempt to verify it.
My cert is in DER
format. I have confirmed this by:
Using openssl
command line:
openssl x509 -text -noout -inform DER -in Cert.cer
: displays certificate
openssl x509 -text -noout -in Cert.cer
: displays unable to load certificate
openssl x509 -inform der -in Cert.cer -out Cert.pem
: converts DER to PEM
I am using the below code to read:
static std::vector<char> ReadAllBytes(char const* filename)
{
std::cout << "in ReadAllBytes(" << filename << ")" << std::endl;
std::ifstream stream(filename, std::ios::in | std::ios::binary);
std::vector<char> contents((std::istreambuf_iterator<char>(stream)), std::istreambuf_iterator<char>());
std::cout << "out ReadAllBytes" << std::endl;
return contents;
}
int main(int argc, char **argv)
{
OpenSSL_add_all_algorithms();
auto readBytes = ReadAllBytes("Cert.cer");
std::cout << "after ReadAllBytes, read size:" << readBytes.size() << std::endl;
BIO *bio_mem = BIO_new(BIO_s_mem());
BIO_puts(bio_mem, readBytes.data());
X509 * x509 = d2i_X509_bio(bio_mem, NULL);
// PEM format
//X509 *x509 = PEM_read_bio_X509(bio_mem, NULL, NULL, NULL);
if(x509 == NULL){
unsigned int errCode = ERR_get_error();
printf("\nError: %s\n", ERR_error_string(errCode, NULL));
printf("\nLib: %s\n", ERR_lib_error_string(errCode));
printf("\nFunc: %s\n", ERR_func_error_string(errCode));
printf("\nReason: %s\n", ERR_reason_error_string(errCode));
}
BIO_free(bio_mem);
X509_free(x509);
}
The output:
in ReadAllBytes(Cert.cer)
out ReadAllBytes
after ReadAllBytes, read size:1033
Error: error:0D06B08E:lib(13):func(107):reason(142)
Lib: (null)
Func: (null)
Reason: (null)
Updated output after calling ERR_load_crypto_strings();
:
Error: error:0D06B08E:asn1 encoding routines:ASN1_D2I_READ_BIO:not enough data
Lib: asn1 encoding routines
Func: ASN1_D2I_READ_BIO
Reason: not enough data
Issue
d2i_X509_bio(bio_mem, NULL)
returns NULL
.
I have successfully read the PEM formatted cert after converting with: X509 *x509 = PEM_read_bio_X509(bio_mem, NULL, NULL, NULL);
Questions
Is there something wrong in my code that I have missed?
How can I read a DER
formatted x509 certificate file with openssl?
It looks like your problem is that you passed a data blob as a string.
BIO_puts
(put string) copies up to the first zero-valued byte. Odds are this is somewhere in the middle of your certificate, which is why you're getting "not enough data" (a DER length value ends up being bigger than the length of the BIO data). (If your certificate had no zeros then it'll read too far and copy too much; be really careful calling functions that take pointers but not length).
BIO_write
, on the other hand, writes the specified amount of data.
So instead of BIO_puts(bio_mem, readBytes.data())
you want BIO_write(bio_mem, readBytes.data(), readBytes.size())
.
Technically, you should write to BIO_write
in a loop, checking the return value (how many bytes it accepted for write), but the BIO_MEM
always either critically fails or succeeds in one call.
(It turns out that BIO_MEM isn't a stream (a data segment with a position) but a pipe (a data segment with a read position and a write position), so it doesn't need to be rewound after writing to it.)