Extract pem certificate information programmatically using openssl - c

Using the openssl command line is possible to extract, in a human readable mode, all the information contained in a .pem certificate; that is:
openssl x509 -noout -in <MyCertificate>.pem -text
What are the suitable steps in order to extract this information using the openssl API?

The X509_print_ex family of functions is your answer.
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/bio.h>
int main(int argc, char **argv)
{
X509 *x509;
BIO *i = BIO_new(BIO_s_file());
BIO *o = BIO_new_fp(stdout,BIO_NOCLOSE);
if((argc < 2) ||
(BIO_read_filename(i, argv[1]) <= 0) ||
((x509 = PEM_read_bio_X509_AUX(i, NULL, NULL, NULL)) == NULL)) {
return -1;
}
X509_print_ex(o, x509, XN_FLAG_COMPAT, X509_FLAG_COMPAT);
}

As additional information related to this question, in case of having a certificate with the DER format instead of PEM; it is also possible to extract the information in a human readable mode using the following code:
//Assuming that the DER certificate binary information is stored in
//a byte array (unsigned char) called "pData" whose size is "lenData"
X509* x509;
BIO* input = BIO_new_mem_buf((void*)pData, lenData);
//d2i_X509_bio: Decodes the binary DER certificate
//and parses it to a X509 structure
x509 = d2i_X509_bio(input, NULL);
if (x509 == NULL)
{
//Error in d2i_X509_bio
}
else
{
//"certificateFile" is the full path file
//where to store the certificate information
//in a human readable mode (instead of stdout)
FILE* fd = fopen(certificateFile, "w+");
BIO* output = BIO_new_fp(fd, BIO_NOCLOSE);
X509_print_ex(output, x509, XN_FLAG_COMPAT, X509_FLAG_COMPAT);
fclose(fd);
BIO_free_all(output);
}
BIO_free_all(input);

Related

how to pass PEM certificate as first arg of i2d_X509

I'm creating self-signed certificate by:
openssl req -new -x509 -key privkey.pem -out cert.pem -days 1095
How do I pass cert.pem to i2d_X509?
I need something like:
len = i2d_X509(".\cert.pem", &buf);
but my certificate in a PEM file..
Here is my code: (I used the example in https://www.openssl.org/docs/crypto/d2i_X509.html)
#include <openssl/x509.h>
#include <stdio.h>
int main(void)
{
int len,i;
unsigned char *buf;
buf = NULL;
len = i2d_X509((X509*)".\cert.pem", &buf);
if (len < 0){
printf("error len < 0");
return -1;
}
printf("buf:");
for (i = 0; i < len ; i++)
printf("0x%02X", *(buf+i));
return 0;
}
How do I pass cert.pem to i2d_X509? ...
You don't/can't. You need to read the certificate with PEM_read_bio_X509. PEM_read_bio_X509 returns an X509*. Then you can pass it to i2d_X509.
Be sure to call X509_free on the pointer when done with it.
Or, do as Philippe suggests - convert it to ASN.1/DER and then use it with d2i_X509_fp.
Also see the OpenSSL man pages on the PEM Read/Write functions.

DSA signature verification in C do not match with signature verification in console. OpenSSL

I wrote a code to sign a message that apparently works fine, it can sign a message with a DSA private key (512 bits), and verify it later with the respective public key (no problems here). I´m using Windows 7.
But,
If I want to verify the sign in the console, openssl command always returns: Verification Failure.
#include <stdio.h>
#include <string.h>
#include <openssl\dsa.h>
#include <openssl\engine.h>
#include <openssl\pem.h>
int main(){
char privkey[] = {
"-----BEGIN DSA PRIVATE KEY-----\n"
"MIH4AgEAAkEA3F41fxvcwGZeFxXg2v0/5SR+cxTizT25QugwZgrC7u2zQYTO1Qu0\n"
"PPDKUrLxkaLzKsUEJbQ1DImnG/FxtRjH7QIVAOp+o1qPhOI4DtnvYS86ynTxhDcF\n"
"AkAyKbiUxJigARuuVVlGn4emXOtrT+Al+gmKbbVFfkS62RhSZexQ9+mBLv0/1R8T\n"
"k37AwuybnflijiPjLxB1ZL00AkA2DXjw+0PJOyrQfn2Q44uHyZMG2WfXqT7CIz26\n"
"ZiIAHDOkZQhOvPLqCKAXfwHgGrgl2JLovhVY8nPMdNk2vJijAhUAzK9TuVobhOE8\n"
"kU0xl8lqaI/PMyg=\n"
"-----END DSA PRIVATE KEY-----"
};
char pubkey[] = {
"-----BEGIN PUBLIC KEY-----\n"
"MIHwMIGoBgcqhkjOOAQBMIGcAkEA3F41fxvcwGZeFxXg2v0/5SR+cxTizT25Qugw\n"
"ZgrC7u2zQYTO1Qu0PPDKUrLxkaLzKsUEJbQ1DImnG/FxtRjH7QIVAOp+o1qPhOI4\n"
"DtnvYS86ynTxhDcFAkAyKbiUxJigARuuVVlGn4emXOtrT+Al+gmKbbVFfkS62RhS\n"
"ZexQ9+mBLv0/1R8Tk37AwuybnflijiPjLxB1ZL00A0MAAkA2DXjw+0PJOyrQfn2Q\n"
"44uHyZMG2WfXqT7CIz26ZiIAHDOkZQhOvPLqCKAXfwHgGrgl2JLovhVY8nPMdNk2\n"
"vJij\n"
"-----END PUBLIC KEY-----"
};
char message[] = {"Hello World!"};
//save message for console test
FILE *message_file = fopen ("message.txt","w");
fwrite(message, strlen(message), 1, message_file);
fclose(message_file);
//save private key for console test
FILE *privkey_file = fopen ("privkey.pem","w");
fwrite(privkey, strlen(privkey), 1, privkey_file);
fclose(privkey_file);
//save public key for console test
FILE *pubkey_file = fopen ("pubkey.pem","w");
fwrite(pubkey, strlen(pubkey), 1, pubkey_file);
fclose(pubkey_file);
//Prepare sign -----------------------------------------------------
BIO *priv_bio;
priv_bio = BIO_new_mem_buf(privkey, -1);
if(priv_bio == NULL){ERR_print_errors_fp(stdout);return 1;}
DSA *private_key;
private_key = PEM_read_bio_DSAPrivateKey(priv_bio, NULL, NULL, NULL);
if(private_key == NULL){ERR_print_errors_fp(stdout);return 2;}
unsigned int result, sign_length;
unsigned char signature[1000] = {0};
//generate sign
result = DSA_sign(NULL, (const unsigned char*)message, strlen(message),
(unsigned char*)signature, &sign_length, private_key);
if(result!=1){ERR_print_errors_fp(stdout);return 3;}
//save signature for console test
FILE *sign_file = fopen ("signature","wb");
fwrite((void*)signature, sign_length, 1, sign_file);
fclose(sign_file);
//verify sign -----------------------------------------------------
BIO *pub_bio;
pub_bio = BIO_new_mem_buf(pubkey, -1);
if(pub_bio == NULL){ERR_print_errors_fp(stdout);return 4;}
DSA *public_key;
public_key = PEM_read_bio_DSA_PUBKEY(pub_bio, NULL, NULL, NULL);
if(public_key == NULL){ERR_print_errors_fp(stdout);return 5;}
result = DSA_verify(NULL, (const unsigned char*)message, strlen(message),
signature, sign_length, public_key);
if(result>0){
printf("Verification OK\n");
}else{
printf("Verification Failure. Error = %i\n",result);
}
BIO_free_all(priv_bio);
DSA_free(private_key);
DSA_free(public_key);
//Console verification
system("openssl dgst -verify pubkey.pem -signature signature message.txt");
return 0;
}
Output:
Verification OK
Verification Failure
Solved:
Apply SHA1 to the digest (message) before DSA_sign, and
apply SHA1 to the digest (message) before DSA_verify.
This makes compatible the signature to work in console with OpenSSL.
To use DSA with openssl you must pass in the -dss1 to the dgst, otherwise it will use SHA1. Try this:
system("openssl dgst -dss1 -verify pubkey.pem -signature signature message.txt");

How to load a PKCS#12 file in OpenSSL programmatically?

In an SSL Server Application based on OpenSSL, how can we load a PKCS#12 file programmatically?
Also, can I load a PKCS#12 file having Certificate, Key & CAs in the same file in OpenSSL?
Yes you can load a PKCS#12 file containing certificate, key and CAs in the same file with OpenSSL.
Use d2i_PKCS12_fp() or d2i_PKCS12_bio() to load the PKCS#12 file.
Optionally use PKCS12_verify_mac() to verify the password.
Use PKCS12_parse() which decrypts and extracts key, certificate and CA chain for you.
From openssl-1.0.0d/demos/pkcs12/pkread.c:
#include <stdio.h>
#include <stdlib.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/pkcs12.h>
/* Simple PKCS#12 file reader */
int main(int argc, char **argv)
{
FILE *fp;
EVP_PKEY *pkey;
X509 *cert;
STACK_OF(X509) *ca = NULL;
PKCS12 *p12;
int i;
if (argc != 4) {
fprintf(stderr, "Usage: pkread p12file password opfile\n");
exit (1);
}
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
if (!(fp = fopen(argv[1], "rb"))) {
fprintf(stderr, "Error opening file %s\n", argv[1]);
exit(1);
}
p12 = d2i_PKCS12_fp(fp, NULL);
fclose (fp);
if (!p12) {
fprintf(stderr, "Error reading PKCS#12 file\n");
ERR_print_errors_fp(stderr);
exit (1);
}
if (!PKCS12_parse(p12, argv[2], &pkey, &cert, &ca)) {
fprintf(stderr, "Error parsing PKCS#12 file\n");
ERR_print_errors_fp(stderr);
exit (1);
}
PKCS12_free(p12);
if (!(fp = fopen(argv[3], "w"))) {
fprintf(stderr, "Error opening file %s\n", argv[1]);
exit(1);
}
if (pkey) {
fprintf(fp, "***Private Key***\n");
PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, NULL, NULL);
}
if (cert) {
fprintf(fp, "***User Certificate***\n");
PEM_write_X509_AUX(fp, cert);
}
if (ca && sk_X509_num(ca)) {
fprintf(fp, "***Other Certificates***\n");
for (i = 0; i < sk_X509_num(ca); i++)
PEM_write_X509_AUX(fp, sk_X509_value(ca, i));
}
sk_X509_pop_free(ca, X509_free);
X509_free(cert);
EVP_PKEY_free(pkey);
fclose(fp);
return 0;
}
Be warned that the code writes the certs out as trusted certificates (encrypted).
If you want unencrypted certificates, change the calls to PEM_write_X509_AUX() to PEM_write_X509().
Try man SSL, which gives you a list of OpenSSL functions. Something like SSL_load_client_CA_file might suit your needs; it depends if the certificate is in a file on disk or already in memory. There are lots of helper functions, one of them will do the trick. Also check out man PEM for PEM handling routines.
Edit: Hm, maybe a combination of d2i_PKCS12_fp and PKCS12_parse (both available from <openssl/pkcs12.h>) lets you read a certificate from file and parse it.

openssl: how to read a .crt file..?

I want to read the certifi.crt file using OpenSSL API (not in commands). I have no idea how to do that. If any one knows, please help me. Thank you.
If you give example code that will be very helpful.
If the ".crt" extension refers to a PEM text file (begins with -----BEGIN CERTIFICATE----- followed by base64), then get started in the OpenSSL docs here.
Here is some code to get you started (link with ssl, e.g. g++ a.c -lssl):
#include <stdio.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
int main(int argc, char** argv)
{
FILE* f = fopen("certifi.crt", "r");
if (f != NULL)
{
X509* x509 = PEM_read_X509(f, NULL, NULL, NULL);
if (x509 != NULL)
{
char* p = X509_NAME_oneline(X509_get_issuer_name(x509), 0, 0);
if (p)
{
printf("NAME: %s\n", p);
OPENSSL_free(p);
}
X509_free(x509);
}
}
return 0;
}

How to verify the password of a pkcs#12 certificate (.PXF) with openssl C API?

I have an .pxf (AFAIK PKCS#12) certificate. How can I confirm a given password for this certificate using the openssl C API?
One approach to finding answers like this is to find an OpenSSL utility that performs the same functionality as what you are trying to do. In this case, you can use the pkcs12 utility that comes with OpenSSL to verify the password.
The command to verify a pfx file is the following:
openssl pkcs12 -in mypfx.pfx -noout
With that information, you can then look at its source code ({openssl_src}/apps/pkcs12.c) to see how they do it.
The source code shows that it calls PKCS12_verify_mac to verify the password. First to verify that there is no password:
if( PKCS12_verify_mac(p12, NULL, 0) )
{
printf("PKCS12 has no password.\n");
}
And then if there is a password, verify it by passing it as an argument:
if( PKCS12_verify_mac(p12, password, -1) )
{
printf("PKCS12 password matches.\n");
}
OpenSSL also has demos for working with PKCS12 in openssl/demos/pkcs12. The pkread.c demo provides an example for parsing a pfx file with a password.
EVP_PKEY *pkey;
X509 *cert;
STACK_OF(X509) *ca = NULL;
if (!PKCS12_parse(p12, password, &pkey, &cert, &ca)) {
fprintf(stderr, "Error parsing PKCS#12 file\n");
ERR_print_errors_fp(stderr);
exit(1);
}
Full example, compiled with gcc -std=c99 verifypfx.c -o verifypfx -lcrypto:
#include <stdio.h>
#include <errno.h>
#include <openssl/pkcs12.h>
#include <openssl/err.h>
int main(int argc, char *argv[])
{
const char *password = "mypassword";
PKCS12 *p12;
// Load the pfx file.
FILE *fp = fopen("mypfx.pfx", "rb");
if( fp == NULL ) { perror("fopen"); return 1; }
p12 = d2i_PKCS12_fp(fp, NULL);
fclose(fp);
OpenSSL_add_all_algorithms();
ERR_load_PKCS12_strings();
if( p12 == NULL ) { ERR_print_errors_fp(stderr); exit(1); }
// Note: No password is not the same as zero-length password. Check for both.
if( PKCS12_verify_mac(p12, NULL, 0) )
{
printf("PKCS12 has no password.\n");
}
else if( PKCS12_verify_mac(p12, password, -1) )
{
printf("PKCS12 password matches.\n");
}
else
{
printf("Password not correct.\n");
}
return 0;
}
Use PKCS12_verify_mac(). eg.
FILE* f = fopen("myfile.pfx", "rb");
PKCS12* p12 = d2i_PKCS12_fp(f, NULL);
fclose(f);
if (!PKCS12_verify_mac(p12, (char*)"mypassword", strlen("mypassword")))
{
// handle failure
}

Resources