Introduction


The example 'C' program certrenewal.c demonstrates how to create a new CSR request from a existing X.509 digitial certificate, using the OpenSSL library functions. This is helpful to renew expiring certificates.

Example Code Listing


/* ------------------------------------------------------------ *
 * file:        certrenewal.c                                   *
 * purpose:     Example code for OpenSSL certificate renewal    *
 * author:      10/28/2012 Frank4DD                             *
 * based on:    openssl-[x.x.x]/crypto/x509/x509_req.c          *
 *                                                              *
 * gcc -o certrenewal certrenewal.c -lssl -lcrypto              *
 * ------------------------------------------------------------ */

#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/x509.h>

int main() {

  const char cert_filestr[] = "./cert-file.pem";
  const char pkey_filestr[] = "./pkey-file.pem";
  BIO              *certbio = NULL;
  BIO              *pkeybio = NULL;
  BIO               *outbio = NULL;
  X509                *cert = NULL;
  X509_REQ         *certreq = NULL;
  EVP_PKEY            *pkey = NULL;
  EVP_MD      const *digest = EVP_sha256();
  int ret;

  /* ---------------------------------------------------------- *
   * These function calls initialize openssl for correct work.  *
   * ---------------------------------------------------------- */
  OpenSSL_add_all_algorithms();
  ERR_load_BIO_strings();
  ERR_load_crypto_strings();

  /* ---------------------------------------------------------- *
   * Create the Input/Output BIO's.                             *
   * ---------------------------------------------------------- */
  certbio = BIO_new(BIO_s_file());
  pkeybio = BIO_new(BIO_s_file());
  outbio  = BIO_new_fp(stdout, BIO_NOCLOSE);

  /* ---------------------------------------------------------- *
   * Load the old certificate from file (PEM).                  *
   * ---------------------------------------------------------- */
  ret = BIO_read_filename(certbio, cert_filestr);
  if (! (cert = PEM_read_bio_X509(certbio, NULL, 0, NULL))) {
    BIO_printf(outbio, "Error loading cert into memory\n");
    exit(-1);
  }

  /* ---------------------------------------------------------- *
   * Load the original private key from file (PEM).             *
   * ---------------------------------------------------------- */
  ret = BIO_read_filename(pkeybio, pkey_filestr);
  if (! (pkey = PEM_read_bio_PrivateKey(pkeybio, NULL, 0, NULL))) {
    BIO_printf(outbio, "Error loading private key into memory\n");
    exit(-1);
  }

  /* ---------------------------------------------------------- *
   * Convert the old certificate into a new request             *
   * Returns NULL on error                                      *
   * ---------------------------------------------------------- */
  if ((certreq = X509_to_X509_REQ(cert, pkey, digest)) == NULL) {
    BIO_printf(outbio, "Error converting certificate into request.\n");
    exit(-1);
  }

  /* ---------------------------------------------------------- *
   * Print the new certificate request (PEM)                    *
   * ---------------------------------------------------------- */
  PEM_write_bio_X509_REQ(outbio, certreq);

  X509_free(cert);
  X509_REQ_free(certreq);
  EVP_PKEY_free(pkey);
  BIO_free_all(certbio);
  BIO_free_all(pkeybio);
  BIO_free_all(outbio);
  exit(0);
}

Compiling the Code


Compile the test program with:

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

Example Output


The example program expects a certificate file called cert-file.pem and the matching key file pkey-file.pem in the same directory. If the certificate and its key are both found and loaded, a new CSR is created and displayed in PEM format:

fm@susie114:~> ./certrenewal
-----BEGIN CERTIFICATE REQUEST-----
MIIBBDCBrwIBADBKMQswCQYDVQQGEwJKUDEOMAwGA1UECAwFVG9reW8xETAPBgNV
BAoMCEZyYW5rNEREMRgwFgYDVQQDDA93d3cuZXhhbXBsZS5jb20wXDANBgkqhkiG
9w0BAQEFAANLADBIAkEAm/xmkHmEQrurE/0re/jeFRLl8ZPjBop7uLHhnia7lQG/
5zDtZIUC3RVpqDSwBuw/NTweGyuP+o8AG98HxqxTBwIDAQABoAAwDQYJKoZIhvcN
AQEFBQADQQByOV52Y17y8xw1V/xvru3rLPrVxYAXS5SgvNpfBsj38lNVtTvuH/Mg
roBgmjSpnqKqBiBDkoY2YUET2qmGjAu9
-----END CERTIFICATE REQUEST-----

Remarks


In order to get a new certificate request from a existing certificate, OpenSSL conveniently provides the function X509_to_X509_REQ(). In order to use it, we need to get the certificate along with the original certificate private key to sign the new request. We also have to specify the signing method, i.e. SHA256 (SHA-1 is outdated, and phased out). The function returns NULL on failure, or a pointer to the new CSR structure if successful.

The renewal function does not check if the provided private key matches the original public key included in the certificate. This is a problem we need to catch because if a wrong key is used here, we will get a fine-looking certificate request that contains the original, old certificate public key, but is now signed with the wrongly supplied private key. The result is that the CA's request signing will fail with error "Signature did not match the certificate request".


OpenSSL Logo

Topics:

Source:

Documentation: