Introduction


The following 'C' example program pkcs12test.c shows how to create a PKCS12 certifcate bundle, using the OpenSSL library functions. A PKCS12 certifcate bundle is typically used to safely transport certificates with their public keys between systems. Microsoft Windows S/Mime email encryption uses PKCS12 to import the e-mail certificates.


/*--------------------------------------------------------------*
 * file:        pkcs12test.c                                    *
 * purpose:     tests creating a pkcs12 certifcate bundle for   *
 *              use with Windows S/MIME                         *
 * author:      12/13/2007 Frank4DD                             *
 *                                                              *
 * compiler:    gcc pkcs12test.c -o pkcs12test -lssl -lcrypto   *
 * ------------------------------------------------------------ */

#include <stdio.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/pkcs12.h>
#include <openssl/err.h>

int main() {

   X509           *cert, *cacert;
   STACK_OF(X509) *cacertstack;
   PKCS12         *pkcs12bundle;
   EVP_PKEY       *cert_privkey;
   FILE           *cacertfile, *certfile, *keyfile, *pkcs12file;
   int            bytes = 0;

/* ------------------------------------------------------------ *
 * 1.) These function calls are essential to make PEM_read and  *
 *     other openssl functions work.                            *
 * ------------------------------------------------------------ */
   OpenSSL_add_all_algorithms();
   ERR_load_crypto_strings();

/*--------------------------------------------------------------*
 * 2.) we load the certificates private key                     *
 *    ( for this test, it has no password )                     *
 *--------------------------------------------------------------*/
   if ((cert_privkey = EVP_PKEY_new()) == NULL)
      printf("Error creating EVP_PKEY structure.\n");

   if (! (keyfile = fopen("./testkey.pem", "r"))) {
      printf("Error cant read certificate private key file.\n");
      exit(-1);
   }

   if (! (cert_privkey = PEM_read_PrivateKey(keyfile, NULL, NULL, NULL)))
      printf("Error loading certificate private key content.\n");
   fclose(keyfile);

/*--------------------------------------------------------------*
 * 3.) we load the corresponding certificate                    *
 *--------------------------------------------------------------*/
   if (! (certfile = fopen("./testcert.pem", "r"))) {
      printf("Error cant read certificate file.\n");
    exit(-1);
   }

   if (! (cert = PEM_read_X509(certfile, NULL, NULL, NULL)))
      printf("Error loading cert into memory.\n");
   fclose(certfile);

/*--------------------------------------------------------------*
 * 4.) we load the CA certificate who signed it                 *
 *--------------------------------------------------------------*/
   if (! (cacertfile = fopen("./cacert.pem", "r"))) {
      printf("Error cant read cert store certificate file.\n");
      exit(-1);
   }

   if (! (cacert = PEM_read_X509(cacertfile,NULL,NULL,NULL)))
      printf("Error loading CA certificate into memory.\n");
   fclose(cacertfile);

/*--------------------------------------------------------------*
 * 5.) we load the CA certificate on the stack                  *
 *--------------------------------------------------------------*/
   if ((cacertstack = sk_X509_new_null()) == NULL)
      printf("Error creating STACK_OF(X509) structure.\n");
   sk_X509_push(cacertstack, cacert);

/*--------------------------------------------------------------*
 * 6.) we create the PKCS12 structure and fill it with our data *
 *--------------------------------------------------------------*/
   if ((pkcs12bundle = PKCS12_new()) == NULL)
      printf("Error creating PKCS12 structure.\n");

   /* values of zero use the openssl default values */
   pkcs12bundle = PKCS12_create(
          "test",      // certbundle access password
          "pkcs12test",// friendly certname
          cert_privkey,// the certificate private key
          cert,        // the main certificate
          cacertstack, // stack of CA cert chain
          0,           // int nid_key (default 3DES)
          0,           // int nid_cert (40bitRC2)
          0,           // int iter (default 2048)
          0,           // int mac_iter (default 1)
          0            // int keytype (default no flag)
   );
   if ( pkcs12bundle == NULL)
      printf("Error generating a valid PKCS12 certificate.\n");

/*--------------------------------------------------------------*
 * 7.) we write the PKCS12 structure out to file                *
 *--------------------------------------------------------------*/
   if (! (pkcs12file = fopen("./testcert.p12", "w"))) {
      printf("Error cant open pkcs12 certificate file for writing.\n");
      exit(-1);
   }

   bytes = i2d_PKCS12_fp(pkcs12file, pkcs12bundle);
   if (bytes <= 0) printf("Error writing PKCS12 certificate.\n");

/*--------------------------------------------------------------*
 * 8.) we are done, let's clean up                              *
 *--------------------------------------------------------------*/
   fclose(pkcs12file);
   X509_free(cert);
   X509_free(cacert);
   sk_X509_free(cacertstack);
   PKCS12_free(pkcs12bundle);
   return(0);
}

Compile the program


Compile the test program with:

fm@susie114:~> gcc pkcs12test.c -o pkcs12test -lssl -lcrypto

Example Output


Before running the compiled program, make sure you have the following required files in the same directory: cacert.pem + testkey.pem + testcert.pem. Below is a quick reference how to create them with openssl, assuming there is a existing (typically self-signed) CA set up:

  1. Create a RSA key pair file
  2. fm@susie114:~> openssl genrsa -out testkey.pem 1024
  3. Create a Certificate Request
  4. fm@susie114:~> openssl req -new -key ./testkey.pem -out ./testcert.req
  5. Sign the Certificate Request and create a Certificate
  6. fm@susie114:~> openssl ca -in ./testcert.req -out ./testcert.pem

Now you can run the pkcs12test program. If successful, a new file named testcert.p12 has been generated. Its functionality can be validated by importing it into Internet Explorer, using the password "test". *


OpenSSL Logo

Topics:

Source:

Documentation: