How to verify key length of a PEM certificate using openSSL functions - c

How do I verify the key length of a PEM certificate that is generated in this way:
# openssl genrsa -des3 -out server.key 1024
# openssl req -new -key server.key -out server.csr
# cp server.key server.key.org
# openssl rsa -in server.key.org -out server.key
# openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
What I need is a C function using procedures from OpenSSL, that performs validation on a PEM certificate (I use it for the lighttpd HTTPS server), and returns the length of the key stored in the certificate (in this case, 1024).

After some tweaking, I believe have found the right routines.
The following should get you started with exploring other OpenSSL routines, in case you need to handle other types of certificates (x509, pem).
Also read through your local x509.h and pem.h for structures and functions that will recover other information you're after.
/* Compile with 'gcc -Wall -lcrypto foo.c' or similar...
---------------------------------------------------------
$ ./a.out server.crt
Opened: server.crt
RSA Public Key: (1024 bit)
$ ./a.out server.key
ERROR: could not read x509 data from server.key
*/
#include <stdio.h>
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
int main(int argc, char *argv[])
{
FILE *fp = NULL;
X509 *x509 = NULL;
EVP_PKEY *public_key = NULL;
fp = fopen(argv[1], "r");
if (fp) {
PEM_read_X509(fp, &x509, NULL, NULL);
fclose(fp);
if (x509) {
fprintf(stderr, "Opened PEM certificate file: %s\n", argv[1]);
/* do stuff with certificate... */
public_key = X509_get_pubkey(x509);
if (public_key) {
switch (public_key->type) {
case EVP_PKEY_RSA:
fprintf(stdout, "RSA Public Key: (%d bit)\n", BN_num_bits(public_key->pkey.rsa->n));
break;
default:
fprintf(stdout, "Unknown public key type? See OpenSSL documentation\n");
break;
}
EVP_PKEY_free(public_key);
}
X509_free(x509);
}
else {
fprintf(stderr, "ERROR: could not read x509 data from %s\n", argv[1]);
return EXIT_FAILURE;
}
}
else {
fprintf(stderr, "ERROR: could not open file!\n");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

Related

OpenSSL error: unable to verify the first certificate

I've been trying to make a simple client/server echo application for the sake of getting to know OpenSSL. I've been following Network Security with OpenSSL by John Viega, Matt Messier, Pravir Chandra (O'Reilly). Their example shows how to set up a root certificate authority, a server CA signed with the root CA, then server certificate signed with the server CA and, finally, a client certificate signed with the root CA and then import them in the C program.
I have made small changes to the program (such as not using threads at all) but most of it is their. My idea was to learn as I try this out but I've come to a problem.
When I try to connect the two, I get an error message saying "unable to get local issuer certificate" (error 20).
I would also like to state that the "previous version" worked (meaning that they progress in their examples).
Not sure if the problem is in the code, the certificates or both.
My OpenSSL version is OpenSSL 1.0.1f 6 Jan 2014. (as returned by the openssl version command)
My knowledge in this matter is very shallow at the moment and I've not had much luck finding an answer. I realize that I still have much reading to do and I will do so but this is a problem I need to overcome.
int seed_prng(int bytes) function is mine, a fix to the problem of not finding the seed_prng(void) function in all these libraries (also one of the things I found that is not fitting).
Perhaps, as this tutorial is 14 years old (at least), it is outdated and I should follow another one? If so, please recommend a tutorial with a high detail level, since the documentation of OpenSSL is not very friendly, in my experience.
Below, I provide all the files included in the process (except for the Makefile.)
The flags I use for the compilation are: -L/usr/lib -lssl -lcrypto -Wall
common.h :
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include <openssl/ssl.h>
#include <openssl/x509v3.h>
#include <openssl/rsa.h>
#include <openssl/objects.h>
#define PORT "8081"
#define SERVER "localhost"
#define CLIENT "localhost"
#define int_error(msg) handle_error(__FILE__, __LINE__, msg)
//Do not confuse with SSL_METHOD ; TLSv1_method() is also a viable option here
#define SSL_METHOD_ SSLv23_method()
#define SEED_PRNG_() seed_prng(30)
#define DEFAULT_DEPTH_ 4
#define DATA_SIZE_ 256
void handle_error(const char *file, int lineno, const char *msg) ;
void init_OpenSSL(void) ;
int seed_prng(int bytes) ;
int verify_callback(int ok, X509_STORE_CTX *store) ;
long post_connection_check(SSL *ssl, char *host) ;
common.c :
#include "common.h"
void handle_error(const char *file, int lineno, const char *msg)
{
fprintf(stderr, "** %s:%i %s\n", file, lineno, msg);
ERR_print_errors_fp(stderr);
exit(-1);
}
void init_OpenSSL(void)
{
if (!SSL_library_init())
{
fprintf(stderr, "** OpenSSL initialization failed!\n");
exit(-1);
}
SSL_load_error_strings();
}
//Not sure if this is good idea! Have to do some research
int seed_prng(int bytes)
{
if (!RAND_load_file("/dev/urandom", bytes))
{
return 0;
}
return 1;
}
int verify_callback(int ok, X509_STORE_CTX *store)
{
char data[DATA_SIZE_];
if (!ok)
{
X509 *cert = X509_STORE_CTX_get_current_cert(store);
int depth = X509_STORE_CTX_get_error_depth(store);
int err = X509_STORE_CTX_get_error(store);
fprintf(stderr, "-Error with certificate at depth: %i\n", depth);
X509_NAME_oneline(X509_get_issuer_name(cert), data, 256);
fprintf(stderr, " issuer = %s\n", data);
X509_NAME_oneline(X509_get_subject_name(cert), data, 256);
fprintf(stderr, " subject = %s\n", data);
fprintf(stderr, " err %i:%s\n", err,
X509_verify_cert_error_string(err));
}
return ok;
}
long post_connection_check(SSL *ssl, char *host)
{
X509 *cert;
X509_NAME *subj;
char data[DATA_SIZE_];
int extcount;
int ok = 0;
if (!(cert = SSL_get_peer_certificate(ssl)) || !host)
{
if (cert)
{
X509_free(cert);
}
return X509_V_ERR_APPLICATION_VERIFICATION;
}
if ((extcount = X509_get_ext_count(cert)) > 0)
{
int i;
for (i = 0; i < extcount; i++)
{
const char *extstr;
X509_EXTENSION *ext;
ext = X509_get_ext(cert, i);
extstr = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext)));
if (!strcmp(extstr, "subjectAltName"))
{
int j;
unsigned char *data;
STACK_OF(CONF_VALUE) *val;
CONF_VALUE *nval;
const X509V3_EXT_METHOD *meth;
if (!(meth = X509V3_EXT_get(ext)))
{
break;
}
data = ext->value->data;
val = meth->i2v(meth,(meth->d2i(NULL, (const unsigned char **)(&data), ext->value->length)), NULL);
for (j = 0; j < sk_CONF_VALUE_num(val); j++)
{
nval = sk_CONF_VALUE_value(val, j);
if (!strcmp(nval->name, "DNS") && !strcmp(nval->value, host))
{
ok = 1;
break;
}
}
}
if (ok)
{
break;
}
}
}
if (!ok && (subj = X509_get_subject_name(cert)) && X509_NAME_get_text_by_NID(subj, NID_commonName, data, DATA_SIZE_) > 0)
{
data[DEFAULT_DEPTH_ - 1] = 0;
if (strcasecmp(data, host) != 0)
{
if (cert)
{
X509_free(cert);
}
return X509_V_ERR_APPLICATION_VERIFICATION;
}
}
X509_free(cert);
return SSL_get_verify_result(ssl);
}
server.c :
#include "common.h"
#define BUF_SIZE_ 80
#define CERTFILE "certificates/serverNOKEY.pem"
#define CAFILE "certificates/rootcert.pem"
#define CADIR NULL
SSL_CTX *setup_server_ctx(void)
{
SSL_CTX *ctx;
//This specifies that either SSL or TLS can be used
//Later, we will "filter" out SSLv2
ctx = SSL_CTX_new(SSLv23_method());
//These two functions are used to load trusted CAs
if (SSL_CTX_load_verify_locations(ctx, CAFILE, CADIR) != 1)
{
int_error("Error loading CA file and/or directory");
}
if (SSL_CTX_set_default_verify_paths(ctx) != 1)
{
int_error("Error loading default CA file and/or directory");
}
//This loads a certificate from a file
if (SSL_CTX_use_certificate_chain_file(ctx, CERTFILE) != 1)
{
int_error("Error loading certificate from file");
}
//This loads a private key (in our code, from the same file but I think that it is not necessary)
if (SSL_CTX_use_PrivateKey_file(ctx, CERTFILE, SSL_FILETYPE_PEM) != 1)
{
int_error("Error loading private key from file");
}
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback);
SSL_CTX_set_verify_depth(ctx, DEFAULT_DEPTH_);
return ctx;
}
int do_server_loop(SSL *ssl)
{
int err, nread;
char buf[BUF_SIZE_];
//I think that this reading should be redone 'cause there's something wrong
do
{
for (nread = 0; nread < sizeof(buf) - 1; nread += err)
{
err = SSL_read(ssl, buf + nread, sizeof(buf) - nread);
printf("read %d bytes\n", err);
if (err <= 0)
{
break;
}
}
fwrite(buf, sizeof(char), nread, stdout);
} while (err > 0);
return (SSL_get_shutdown(ssl) & SSL_RECEIVED_SHUTDOWN) ? 1 : 0;
}
void server_part(SSL *ssl)
{
long err;
//accepting connection from ssl object (structure)
if (SSL_accept(ssl) <= 0)
{
int_error("Error accepting SSL connection");
}
if ((err = post_connection_check(ssl, CLIENT)) != X509_V_OK)
{
fprintf(stderr, "-Error: peer certificate: %s\n",
X509_verify_cert_error_string(err));
int_error("Error checking SSL object after connection");
}
fprintf(stderr, "SSL Connection opened\n");
//As I figured, SSL_shutdown is a clean way to go but SSL_clear
//will force the closing of the communication if it wasn't closed cleanly
if (do_server_loop(ssl))
{
//See this https://www.openssl.org/docs/manmaster/ssl/SSL_shutdown.html
SSL_shutdown(ssl);
}
else
{
// https://www.openssl.org/docs/manmaster/ssl/SSL_clear.html
SSL_clear(ssl);
}
fprintf(stderr, "SSL Connection closed\n");
SSL_free(ssl);
}
int main(int argc, char *argv[])
{
BIO *acc, *client;
SSL *ssl;
SSL_CTX *ctx;
init_OpenSSL();
//This is my function, gotta investigate it and see what should be there (maybe I got it right?)
SEED_PRNG_();
ctx = setup_server_ctx();
acc = BIO_new_accept(PORT);
if (!acc)
{
int_error("Error creating server socket");
}
if (BIO_do_accept(acc) <= 0)
{
int_error("Error binding server socket");
}
for (;;)
{
if (BIO_do_accept(acc) <= 0)
{
int_error("Error accepting connection");
}
client = BIO_pop(acc);
if (!(ssl = SSL_new(ctx)))
{
int_error("Error creating SSL context");
}
SSL_set_bio(ssl, client, client);
server_part(ssl);
}
SSL_CTX_free(ctx);
BIO_free(acc);
return 0;
}
client.c :
#include "common.h"
#define BUF_SIZE_ 80
#define CERTFILE "certificates/clientNOKEY.pem"
#define CAFILE "certificates/rootcert.pem"
#define CADIR NULL
SSL_CTX *setup_client_ctx(void)
{
SSL_CTX *ctx;
ctx = SSL_CTX_new(SSL_METHOD_);
if (SSL_CTX_load_verify_locations(ctx, CAFILE, CADIR) != 1)
{
int_error("Error loading CA file and/or directory");
}
if (SSL_CTX_set_default_verify_paths(ctx) != 1)
{
int_error("Error loading default CA file and/or directory");
}
if (SSL_CTX_use_certificate_chain_file(ctx, CERTFILE) != 1)
{
int_error("Error loading certificate from file");
}
if (SSL_CTX_use_PrivateKey_file(ctx, CERTFILE, SSL_FILETYPE_PEM) != 1)
{
int_error("Error loading private key from file");
}
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback);
SSL_CTX_set_verify_depth(ctx, DEFAULT_DEPTH_);
return ctx;
}
int do_client_loop(SSL *ssl)
{
int err, nwritten;
char buf[BUF_SIZE_];
for (;;)
{
if (!fgets(buf, sizeof(buf), stdin))
{
break;
}
//printf("ucitao: %s\n", buf);
for (nwritten = 0; nwritten < sizeof(buf); nwritten += err)
{
err = SSL_write(ssl, buf + nwritten, strlen(buf) - nwritten);
if (err <= 0)
{
return 0;
}
else
{
printf("Sent: %s\n", buf);
}
}
}
return 1;
}
int main(int argc, char *argv[])
{
BIO *conn;
SSL *ssl;
SSL_CTX *ctx;
long err;
init_OpenSSL();
SEED_PRNG_();
ctx = setup_client_ctx();
conn = BIO_new_connect(SERVER ":" PORT);
if (!conn)
{
int_error("Error creating connection BIO");
}
if (BIO_do_connect(conn) <= 0)
{
int_error("Error connecting to remote machine");
}
if (!(ssl = SSL_new(ctx)))
int_error("Error creating an SSL context");
SSL_set_bio(ssl, conn, conn);
if (SSL_connect(ssl) <= 0)
{
int_error("Error connecting SSL object");
}
if ((err = post_connection_check(ssl, SERVER)) != X509_V_OK)
{
fprintf(stderr, "-Error: peer certificate: %s\n",
X509_verify_cert_error_string(err));
int_error("Error checking SSL object after connection");
}
fprintf(stderr, "SSL Connection opened\n");
if (do_client_loop(ssl))
{
SSL_shutdown(ssl);
}
else
{
SSL_clear(ssl);
}
fprintf(stderr, "SSL Connection closed\n");
SSL_free(ssl);
SSL_CTX_free(ctx);
return 0;
}
The script I used to create the CAs, certificates and sign them:
#! /bin/bash
echo "Begin"
#the line below ensures that the script finishes after an unsuccessful command, not trying to execute any next command,
#since it's the assumption that every previous command was successful
set -e
echo "Creating the root CA"
openssl req -newkey rsa:1024 -sha1 -keyout rootkey.pem -out rootreq.pem
openssl x509 -req -in rootreq.pem -sha1 -extfile myopenssl.cnf -extensions v3_ca -signkey rootkey.pem -out rootcert.pem
cat rootcert.pem rootkey.pem > root.pem
openssl x509 -subject -issuer -noout -in root.pem
echo "Creating the server CA and signing it with the root CA"
openssl req -newkey rsa:1024 -sha1 -keyout serverCAkey.pem -out serverCAreq.pem
openssl x509 -req -in serverCAreq.pem -sha1 -extfile myopenssl.cnf -extensions v3_ca -CA root.pem -CAkey root.pem -CAcreateserial -out serverCAcert.pem
cat serverCAcert.pem serverCAkey.pem rootcert.pem > serverCA.pem
openssl x509 -subject -issuer -noout -in serverCA.pem
echo "Creating the server\'s certificate and signing it with the server CA"
openssl req -newkey rsa:1024 -sha1 -keyout serverkey.pem -out serverreq.pem
openssl x509 -req -in serverreq.pem -sha1 -extfile myopenssl.cnf -extensions usr_cert -CA serverCA.pem -CAkey serverCA.pem -CAcreateserial -out servercert.pem
cat servercert.pem serverkey.pem serverCAcert.pem rootcert.pem > server.pem
openssl x509 -subject -issuer -noout -in server.pem
echo "Creating the client certificate and signing it with the root CA"
openssl req -newkey rsa:1024 -sha1 -keyout clientkey.pem -out clientreq.pem
openssl x509 -req -in clientreq.pem -sha1 -extfile myopenssl.cnf -extensions usr_cert -CA root.pem -CAkey root.pem -CAcreateserial -out clientcert.pem
cat clientcert.pem clientkey.pem rootcert.pem > client.pem
openssl x509 -subject -issuer -noout -in client.pem
echo "creating dh512.pem and dh1024.pem"
openssl dhparam -check -text -5 512 -out dh512.pem
openssl dhparam -check -text -5 1024 -out dh1024.pem
echo "Making new keys which do not require passkey"
echo "Creating no passkey server key"
openssl rsa -in server.pem -out serverNOKEY.pem
openssl x509 -in server.pem >>serverNOKEY.pem
echo "serverNOKEY.pem created"
echo "Creating no passkey client key"
openssl rsa -in client.pem -out clientNOKEY.pem
openssl x509 -in client.pem >>clientNOKEY.pem
echo "clientNOKEY.pem created"
echo "Done! Success!"
I faced similar issue when I was setting up SSL Communications between java applications. To determine whether its a code issue or certificate issue itself you can run below openssl command. If certificate isn't getting verified it means there is problems in verifying certificates using root CA.
Verify a certificate
openssl verify certificate_name
Reference .
Also, as it seems you are working on self-signed certificate you can switch off verification of certificates in your code and proceed. In production environment when certificates are signed by Certificate Authority (CA) such errors are less likely to appear.

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.

Extract pem certificate information programmatically using openssl

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

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.

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