Extracting client certificate & private key from .p12 file - c

Can anybody tell me how to use
PKCS12 *d2i_PKCS12_fp(FILE *fp, PKCS12 **p12);
int PKCS12_parse(PKCS12 *p12, const char *pass, EVP_PKEY **pkey, X509 **cert, STACK_OF(X509) **ca);
any documenatation reference will also work.

Without error-checking:
FILE *p12_file;
PKCS12 *p12_cert = NULL;
EVP_PKEY *pkey;
X509 *x509_cert;
STACK_OF(X509) *additional_certs = NULL;
p12_file = fopen("foo.p12", "rb");
d2i_PKCS12_fp(p12_file, &p12_cert);
fclose(p12_file);
PKCS12_parse(p12_cert, "password", &pkey, &x509_cert, &additional_certs);
The private key is now in pkey, the certificate in x509_cert and any additional certificates in additional_certs.

Here is openssl's page for parse: PKCS12_parse.html
Here is Apple's link to using openssl libs: see PKCS#12, Section 2: I/O
From Apple's site, here are the descriptions:
int PKCS12_parse(PKCS12 *p12, char *pass, EVP_PKEY **pkey, X509 **cert,
STACK **ca);
This function takes a PKCS12 structure and a password (ASCII, null terminated)
and returns the private key, the corresponding certificate and any CA
certificates. If any of these is not required it can be passed as a NULL.
The 'ca' parameter should be either NULL, a pointer to NULL or a valid STACK
structure. Typically to read in a PKCS#12 file you might do:
p12 = d2i_PKCS12_fp(fp, NULL);
PKCS12_parse(p12, password, &pkey, &cert, NULL); /* CAs not wanted */
PKCS12_free(p12);

Related

How to extract public key from private key using openssl in C

I know in command line that given a pem file of private key, you can extract the public key from it.
Wondering how the similar function can be achieved using openssl's C library?
First, read the key:
EVP_PKEY *key;
FILE *fpkey;
OpenSSL_add_all_algorithms();
key = EVP_PKEY_new();
fpkey = fopen ("key.pem", "r");
PEM_read_PrivateKey(fpkey, &key, NULL, NULL);
fclose(fpkey);
Now that you have the EVP_PKEY structure, you can save the public key:
FILE* fppubkey = fopen("pubkey.pem", "wb");
PEM_write_PUBKEY(fppubkey, key);
fclose(fppubkey);
Make sure to add error checking.

Extracting the public certificate from a certificate

I would like to programmatically generate a certificate that contain only the public key using openssl.
So I basically need to do the following but using code.
openssl x509 -in certificate.crt -pubkey
Digging a bit it seem that I need to create a new certificate and copy all the information except the private key in it.
X509 * pNewKey = X509_new();
... Copy all the needed information ...
PEM_write_bio_X509(bioKey, &pNewKey, NULL, NULL);
Does someone have a better method?
I would like to programmatically generate a certificate that contain only the public key
To set the public key, take your public key in EVP_PKEY format and call X509_set_pubkey. Building upon your example code:
X509* x509 = X509_new();
EVP_PKEY* pkey = /***/;
int rc = X509_set_pubkey(x509, pkey);
ASSERT(rc == 1);
BIO* bio = BIO_new_file("filename.txt", "w");
ASSERT(bio != NULL);
rc = PEM_write_bio_X509(bio, x509, NULL, NULL);
ASSERT(rc == 1);
...
BIO_free(bio);
EVP_PKEY_free(pkey);
X509_free(x509);
For completeness, OpenSSL will save a certificate with no attributes, no version, no public key, and no signature.
So I basically need to do the following but using code.
openssl x509 -in certificate.crt -pubkey
OK, this is a different question. The above command will print the public key.
Use x509_get_pubkey:
EVP_PKEY* pkey = X509_get_pubkey(X509* x509);
Once you have the EVP_PKEY, you can get the type. You need to supply this function because OpenSSL does not provide it:
int EVP_PKEY_get_type(EVP_PKEY *pkey)
{
AC_ASSERT(pkey);
if (!pkey)
return NID_undef;
return EVP_PKEY_type(pkey->type);
}
Then, depending on the type, you can print the key:
if(type == EVP_PKEY_RSA || type == EVP_PKEY_RSA2)
{
RSA* rsa = EVP_PKEY_get1_RSA(pkey);
RSA_print_fp(stdout, rsa, 0);
RSA_free(rsa);
}
...
You have to break out the keys by type and then call the respective XXX_print_fp because OpenSSL does not provide an EVP_PKEY_print_fp.
The get1 in EVP_PKEY_get1_RSA means the reference count on the key is bumped. So you have to call a *_free on it. A get0 does not bump the reference count, and does not need a call to *_free.

How to verify a X509 certificate in C

I have a certificate in X509 format. this a input parameters in a function.
What I would like to do is to verify the validity of the certificate.
How can it be done?
X509_verify_cert();
I found this function, but this does not accept a X509* certificate, it accepts X509_store and I only have a X509.
Thanks
best regards.
I am here just to post my answer as I found it with the above comments.
I had no certificate chain, so in the work I'm doing I only have a certificate generated by me programatically. I wanted to check the validity of it, so I created the following function, which checks the certificate against itself in other to verify the validity of it.
void check_certificate_validaty(X509* certificate)
{
int status;
X509_STORE_CTX *ctx;
ctx = X509_STORE_CTX_new();
X509_STORE *store = X509_STORE_new();
X509_STORE_add_cert(store, certificate);
X509_STORE_CTX_init(ctx, store, certificate, NULL);
status = X509_verify_cert(ctx);
if(status == 1)
{
printf("Certificate verified ok\n");
}else
{
printf("%s\n", X509_verify_cert_error_string(ctx->error));
}
}
Hope this helps someone :)
See the documentation here.
You need to create a certificate store using X509_STORE_CTX_new.
Then add certificate chain using X509_STORE_CTX_set_chain. Add trusted root certificate using X509_STORE_CTX_trusted_stack.
Finally add certificate to be verified using X509_STORE_CTX_set_cert.
After that call X509_verify_cert.
I hope this will help you to start on this.
To verify a certificate signature, you need the public key of an issuer certificate. This issuer certificate's signature is verified with another issuing certificate (or trusted root certificate). Thus if a certificate's signature verifies all the way up a chain to a trusted root, then that certificate is considered trusted.
Self-signed certificates' signatures are verified using their own public key, like the example below:
int verify_cert(const char* pem_c_str)
{
BIO *bio_mem = BIO_new(BIO_s_mem());
BIO_puts(bio_mem, pem_c_str);
X509 * x509 = PEM_read_bio_X509(bio_mem, NULL, NULL, NULL);
EVP_PKEY *pkey=X509_get_pubkey(x509);
int r= X509_verify(x509, pkey);
EVP_PKEY_free(pkey);
BIO_free(bio_mem);
X509_free(x509);
return r;
}
from: http://www.zedwood.com/article/openssl-c-verify-self-signed-certificate-signature

Extract RSA public key from a x509 char array with openssl

Here is a certificate in x509 format that stores the public key and the modulo:
const unsigned char *certificateDataBytes = {/*data*/};
Using OpenSSL and C, how can I convert it into an RSA object? I've tried several methods but I can't get it to work in RSA_public_encrypt
I think you mean public key into RSA * structure.
Since, you have certificate in bytes, if it is in DER encoded bytes, then you need to first convert it into X509 * structure.
X509 * cert;
EVP_PKEY * pubkey;
//length is the length of the certificateDataBytes in terms of bytes.
cert = d2i_x509 (NULL, certificateDataBytes, length);
pubkey = X509_get_pubkey (cert);
Please note that if certificate has RSA public key, then you can get RSA public key as follows:
RSA * rsa
rsa = EVP_PKEY_get1_RSA(pubkey);
//Now rsa contains RSA public key. Use it.
//After use, free the pubkey
EVP_PKEY_free (pubkey);
I hope this must solve your purpose.
If certificate encoding is different, use different function. Once, you get X509 *, rest step is same.

How do I decrypt a private key file and sign some text using openssl calls in C?

I have 2 separate programs (spliced together below). The first generates the key pair and saves to files (works fine). The second opens the private key, decrypting with a pass phrase and then I need it to sign a string of text. The code below fails on the PEM_read_PrivateKey() (last) call (can't see why). Can anyone point me at what I am doing wrong and then what openssl calls I should make to use the private key to sign some text?
int main (int argc, char *argv[])
{
char *priv_pem = "priv.pem";
char *pub_pem = "pub.pem";
char *pass = "Password";
FILE *fp;
int bits = 4096;
unsigned long exp = RSA_F4;
RSA *rsa;
EVP_PKEY *pkey;
// GENERATE KEY
rsa=RSA_generate_key(bits,exp,NULL,NULL);
if (RSA_check_key(rsa)!=1)
Exit(1,"Error whilst checking key","");
pkey = EVP_PKEY_new();
EVP_PKEY_assign_RSA(pkey, rsa);
// WRITE ENCRYPTED PRIVATE KEY
if (!(fp = fopen(priv_pem, "w")))
Exit(2,"Error opening PEM file",priv_pem);
if (!PEM_write_PrivateKey(fp,pkey,EVP_aes_256_cbc(),NULL,0,NULL,pass))
Exit(3,"Error writing PEM file",priv_pem);
fclose(fp);
// WRITE PUBLIC KEY
if (!(fp = fopen(pub_pem, "w")))
Exit(4,"Error opening PEM file",pub_pem);
if (!PEM_write_PUBKEY(fp, pkey))
Exit(5,"Error writing PEM file",pub_pem);
fclose(fp);
// ------- End of key generation program -------
// ------- Start of text signing program -------
// READ IN ENCRYPTED PRIVATE KEY
if (!(fp = fopen(priv_pem, "r")))
Exit(6,"Error reading encrypted private key file",priv_pem);
if (!PEM_read_PrivateKey(fp,&pkey,NULL,pass))
Exit(7,"Error decrypting private key file",priv_pem);
fclose(fp);
// Sign some text using the private key....
// FREE
RSA_free(rsa);
return 0;
}
Have you initialised pkey to NULL before you pass &pkey to PEM_read_PrivateKey()? If not, it will attempt to re-use the EVP_PKEY structure that pkey points to - and if pkey is uninitialised, it will be looking at a random spot in memory.
You can use ERR_print_errors_fp(stderr); to dump the OpenSSL error stack to stderr when an error occurs - this is often helpful in finding the problem.
Thanks #caf for your help.
By trial and error I fixed PEM_read_PrivateKey() error by adding the following to the start:
if (EVP_get_cipherbyname("aes-256-cbc") == NULL)
OpenSSL_add_all_algorithms();
However, I'm still looking for the best (practice) way of generating the keys and then using the private key for signing. From my limited understanding, I am looking for openssl methods that adhere to RSA's "PKCS #1 v2.0: RSA Cryptography Standard"

Resources