| RSA BSAFE Micro Edition Suite |
Streamlined security for mobile and embedded devices |
 
![]() |
/* $Id: verify.c,v 1.40 2005/02/07 01:38:21 jmckee Exp $ */ /* * Copyright (C) 1998-2003 RSA Security Inc. * * This file shall only be used to demonstrate how to interface to an * RSA Security Inc. licensed development product. * * You have a royalty-free right to use, reproduce and distribute this * demonstration file, provided that you agree that RSA Security Inc. * has no warranty, implied or otherwise, or liability for this * demonstration file (including any modified version). This software * is provided "as is" without warranties or representations of any * kind. RSA Security disclaims all conditions and warranties, statutory * and otherwise, both express and implied, with respect to the software, * its quality and performance, including but not limited to, all * implied warranties of merchantability, fitness for a particular * purpose, title and noninfringement of third party rights. Without * limiting the foregoing, RSA Security does not warrant that the * software is error-free or that errors in the product will be * corrected. You agree that RSA Security shall not be liable for any * direct, indirect, incidental, special, consequential, punitive or * other damages whatsoever resulting from your use of this software * or any modified version. * * */ #include "r_prod.h" #include "r_cert_r.h" #include "r_pkey_mth.h" /* * The CA certificate, in binary form, can be used to verify a client * certificate */ static unsigned char ca_x509_certificate[607] = { 0x30, 0x82, 0x02, 0x5B, 0x30, 0x82, 0x01, 0xC4, 0x02, 0x03, 0x00, 0x98, 0x83, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04, 0x05, 0x00, 0x30, 0x75, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x0C, 0x30, 0x0A, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x03, 0x51, 0x6C, 0x64, 0x31, 0x11, 0x30, 0x0F, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x08, 0x42, 0x72, 0x69, 0x73, 0x62, 0x61, 0x6E, 0x65, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x0C, 0x52, 0x53, 0x41, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x13, 0x0B, 0x45, 0x6E, 0x67, 0x69, 0x6E, 0x65, 0x65, 0x72, 0x69, 0x6E, 0x67, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0F, 0x43, 0x41, 0x31, 0x20, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x30, 0x1E, 0x17, 0x0D, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A, 0x17, 0x0D, 0x30, 0x31, 0x30, 0x36, 0x33, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A, 0x30, 0x75, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x0C, 0x30, 0x0A, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x03, 0x51, 0x6C, 0x64, 0x31, 0x11, 0x30, 0x0F, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x08, 0x42, 0x72, 0x69, 0x73, 0x62, 0x61, 0x6E, 0x65, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x0C, 0x52, 0x53, 0x41, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x13, 0x0B, 0x45, 0x6E, 0x67, 0x69, 0x6E, 0x65, 0x65, 0x72, 0x69, 0x6E, 0x67, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0F, 0x43, 0x41, 0x32, 0x20, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x30, 0x81, 0x9F, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8D, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0x95, 0xA2, 0xFE, 0x0B, 0x2A, 0xD2, 0x52, 0x02, 0x68, 0xE9, 0xDA, 0x5B, 0x01, 0x0C, 0x20, 0xF9, 0x32, 0xC1, 0x18, 0x90, 0xBD, 0xA5, 0x79, 0x8B, 0x62, 0x30, 0x9F, 0xF1, 0x6C, 0x1A, 0x77, 0x5C, 0xC6, 0xEB, 0x14, 0x1E, 0xD4, 0xBB, 0x8A, 0x88, 0xEA, 0x35, 0xB4, 0x74, 0xA0, 0xE8, 0x43, 0xA6, 0x3E, 0xD4, 0x95, 0x63, 0xB6, 0xA3, 0xC1, 0x57, 0x9B, 0x50, 0xAD, 0x74, 0xA9, 0x4F, 0xDF, 0xA6, 0x66, 0xCF, 0xCF, 0xEB, 0x02, 0xE0, 0xEA, 0x10, 0xB1, 0x6D, 0x5F, 0x4E, 0xEE, 0xE4, 0xD4, 0xFB, 0x31, 0xB4, 0xC4, 0x3D, 0xD2, 0x39, 0x7E, 0x78, 0x3A, 0x3B, 0x9A, 0xC1, 0xE2, 0x6F, 0x16, 0x98, 0xEF, 0x9A, 0xDC, 0xE8, 0xFE, 0x01, 0xA7, 0x05, 0x9D, 0x75, 0x35, 0xC6, 0x96, 0x82, 0x82, 0xF3, 0xC7, 0xA9, 0xA6, 0x4F, 0xE2, 0x1D, 0x02, 0xD2, 0x38, 0x46, 0x15, 0xFA, 0xC7, 0x65, 0xE2, 0x63, 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x08, 0x42, 0x5E, 0x93, 0x44, 0xF1, 0x3A, 0x5A, 0xD7, 0x15, 0x8F, 0x51, 0xE0, 0x00, 0x56, 0x02, 0x07, 0xFE, 0xFF, 0xFF, 0x90, 0x30, 0xE2, 0xC3, 0xD6, 0xB6, 0x08, 0xED, 0x89, 0x60, 0x62, 0x5B, 0x39, 0x95, 0x3B, 0xF1, 0xF3, 0x90, 0xFF, 0x6C, 0x0D, 0xDE, 0x28, 0xB2, 0xA8, 0xE6, 0x2E, 0xE7, 0xF5, 0x12, 0x5C, 0x92, 0xA8, 0x97, 0x74, 0x70, 0x84, 0x75, 0xFA, 0x46, 0xFC, 0x99, 0xE4, 0x23, 0x6F, 0x68, 0x5A, 0xB7, 0x6D, 0x5A, 0xF6, 0x8A, 0x6A, 0x8C, 0xB6, 0xE2, 0xF6, 0xA5, 0xE8, 0x8B, 0xB1, 0x7E, 0xE8, 0x43, 0x7A, 0x1B, 0xA7, 0x28, 0xF1, 0xFA, 0x4D, 0x6D, 0xC3, 0x1B, 0xF9, 0xFD, 0x1C, 0x74, 0x65, 0x8D, 0x48, 0x36, 0xD8, 0x30, 0xFF, 0xC9, 0xA9, 0x9F, 0x0E, 0x41, 0xA7, 0x7C, 0xBE, 0xD8, 0x3B, 0x88, 0xA5, 0x97, 0xC8, 0x67, 0x14, 0x92, 0xBB, 0xCA, 0x27, 0x12, 0xCF, 0x03, }; /* The client certificate in binary form */ static unsigned char client_x509_certificate[607]= { 0x30, 0x82, 0x02, 0x5B, 0x30, 0x82, 0x01, 0xC4, 0x02, 0x02, 0x43, 0x2E, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04, 0x05, 0x00, 0x30, 0x75, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x0C, 0x30, 0x0A, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x03, 0x51, 0x6C, 0x64, 0x31, 0x11, 0x30, 0x0F, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x08, 0x42, 0x72, 0x69, 0x73, 0x62, 0x61, 0x6E, 0x65, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x0C, 0x52, 0x53, 0x41, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x13, 0x0B, 0x45, 0x6E, 0x67, 0x69, 0x6E, 0x65, 0x65, 0x72, 0x69, 0x6E, 0x67, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0F, 0x43, 0x41, 0x32, 0x20, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x30, 0x1E, 0x17, 0x0D, 0x30, 0x31, 0x30, 0x33, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A, 0x17, 0x0D, 0x30, 0x31, 0x30, 0x34, 0x32, 0x38, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A, 0x30, 0x76, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x0C, 0x30, 0x0A, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x03, 0x51, 0x6C, 0x64, 0x31, 0x11, 0x30, 0x0F, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x08, 0x42, 0x72, 0x69, 0x73, 0x62, 0x61, 0x6E, 0x65, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x0C, 0x52, 0x53, 0x41, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x13, 0x0B, 0x45, 0x6E, 0x67, 0x69, 0x6E, 0x65, 0x65, 0x72, 0x69, 0x6E, 0x67, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x10, 0x4C, 0x65, 0x61, 0x66, 0x20, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x30, 0x81, 0x9F, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8D, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xD9, 0x70, 0xDE, 0x12, 0x79, 0x8B, 0xFC, 0x89, 0x04, 0xA0, 0x82, 0xA1, 0x8B, 0xB9, 0x87, 0x25, 0xCF, 0xAE, 0x01, 0xF3, 0xE7, 0x22, 0x9F, 0x5B, 0x2E, 0xD0, 0x66, 0xA9, 0x05, 0xAB, 0x72, 0x6D, 0x87, 0xF7, 0x98, 0x7F, 0xF9, 0x59, 0xD9, 0x00, 0xE8, 0x0B, 0xA1, 0x73, 0xF4, 0xD9, 0xA2, 0x51, 0x6F, 0xE3, 0xD9, 0xA8, 0x93, 0x2A, 0xC9, 0x4F, 0xA5, 0x96, 0x80, 0x2A, 0xFB, 0x49, 0x67, 0x51, 0x62, 0xE3, 0xB9, 0x26, 0xA7, 0x50, 0xE7, 0x2C, 0xDA, 0x64, 0xE1, 0x74, 0xCA, 0x1D, 0xBF, 0xEC, 0x8C, 0xE3, 0xCD, 0x59, 0x7F, 0xA1, 0x13, 0x37, 0xAA, 0xAB, 0x6F, 0xEA, 0x43, 0x29, 0x0D, 0x7B, 0x16, 0x16, 0x1F, 0xBC, 0xBD, 0xCF, 0xA6, 0xE0, 0x82, 0xE1, 0x85, 0x4C, 0x7E, 0x0D, 0x4B, 0x72, 0x5F, 0x0F, 0x54, 0x19, 0xB1, 0xD6, 0x50, 0x7C, 0xCC, 0x4B, 0x05, 0x04, 0xFD, 0x63, 0x53, 0x8D, 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x02, 0xC2, 0x7A, 0x1F, 0xAC, 0x3C, 0xDB, 0x6B, 0x21, 0x65, 0xB9, 0xA2, 0x2D, 0xBB, 0x90, 0xCD, 0x20, 0xB0, 0xE0, 0xF3, 0xEE, 0xEB, 0x2A, 0x99, 0xCD, 0x25, 0x74, 0x81, 0xEA, 0x66, 0x7D, 0xFD, 0x9E, 0xA2, 0xEB, 0x35, 0x4F, 0x4A, 0x18, 0xF6, 0xA6, 0xD7, 0x6F, 0xB9, 0xCB, 0x0D, 0x91, 0xC3, 0x3D, 0xE3, 0x3A, 0x71, 0x77, 0x4C, 0x5E, 0x59, 0xA3, 0xA6, 0x87, 0xEC, 0x02, 0x75, 0x0F, 0x5B, 0x66, 0x43, 0x9A, 0x96, 0x40, 0x83, 0x5D, 0x7D, 0xF4, 0x28, 0x82, 0xED, 0x04, 0xDA, 0xDD, 0x63, 0x4A, 0xDA, 0xAD, 0xBB, 0xB0, 0x82, 0xD4, 0x57, 0xFD, 0x86, 0x08, 0xB6, 0x9C, 0x58, 0xB6, 0x94, 0xDD, 0x87, 0x42, 0x27, 0x46, 0xE3, 0xB0, 0x86, 0xAD, 0x3D, 0xB4, 0x77, 0x2B, 0xB3, 0xD5, 0x59, 0xC2, 0xD4, 0x13, 0x73, 0xE0, 0x9E, 0x4B, 0x88, 0xB0, 0xB6, 0x90, 0x69, 0x28, 0x0C, 0xF4, 0x3A, }; /* * The list of algorithms required in the application via the * resource list from cryp_ops.h */ R_CR_IMP_METHOD my_custom_cipher_list[] = { R_CR_DIGEST_MD5, R_CR_PKEY_RSA, R_CR_PKEY_RSA_PKCS1, R_CR_SIG_RSA_MD5, R_CR_END_OF_LIST }; /* * Defines the function to return the address of the custom * cipher list. */ R_CR_DEFINE_CUSTOM_CIPHER_LIST(my_custom_cipher_list, my_custom_list_retriever); /* * Indicates the list of the cryptographic methods included in the application. * The application accesses these methods via the method table defined below. * The custom method is a fixed size table and requires the correct number of * entries for successful operation. There is a list of macros (defined in * cryp_ops.h) that define groups of cryptographic method functionality. A * macro from each group (in the correct order) is required to ensure all * elements of the R_CR_METHOD structure are defined. The various macros of * each group of cryptographic methods include a subset of methods for the * group. */ R_CR_METHOD my_methods= { R_CR_METHOD_REQUIRED, R_CR_METHOD_ERRINFO_NOT_IMPLEMENTED, R_CR_METHOD_INFO, R_CR_METHOD_SYM_ENC_NOT_IMPLEMENTED, R_CR_METHOD_SYM_DEC_NOT_IMPLEMENTED, R_CR_METHOD_SIGN_NOT_IMPLEMENTED, R_CR_METHOD_VERIFY, R_CR_METHOD_ASYM_ENC, R_CR_METHOD_ASYM_DEC, R_CR_METHOD_DIGEST, R_CR_METHOD_MAC_NOT_IMPLEMENTED, R_CR_METHOD_VERIFY_MAC_NOT_IMPLEMENTED, R_CR_METHOD_KE_NOT_IMPLEMENTED, R_CR_METHOD_KEY_GEN_NOT_IMPLEMENTED, R_CR_METHOD_RAND_SEED_NOT_IMPLEMENTED, R_CR_METHOD_RAND_GEN_NOT_IMPLEMENTED }; /* * Creates a function to return the custom methods. The custom methods list * is a structure of #R_CR_METHOD. */ R_CR_DEFINE_CUSTOM_METHOD_TABLE(my_methods, my_get_methods); /* * This is the overall resource list for the program which: * * - Requires a library module (select a minimal implementation). * - Uses the minimal cryptographic module, and provides a * cipher list (see above). * - Requires the signature map to perform sign/verify operations. * - Requires the PKEY module for extracting the public key and verification. * - Requires the X.509 module for handling the certificate. Use a subset of * the X.509 module required to verify (no creation). */ R_RES_LIST my_resource_list[] = { R_LIB_RES_SMALL, /* * Binds a custom algorithm list and method table to the * cryptographic module */ R_CR_RES_CRYPTO_CUSTOM_METHOD(my_get_methods, my_custom_list_retriever), R_CR_RES_SIGNATURE_MAP, R_PKEY_RES_RSA, R_CERT_RES_X509_VERIFY, R_RES_END_OF_LIST /* Mark the end of the resource list */ }; /* * Demonstrates how to verify a certificate with the CA certificate and how to * load in certificates from an array. * * @param argc [In] A count of the command line arguments. * @param argv [In] An array of command line argument strings. * * @return 0 indicates success.<br> * !=0 indicates error. * * @note If there was an error, the error value is displayed where * possible. */ int main(int argc, char *argv[]) { int ret = R_ERROR_NONE; /* The return value */ R_LIB_CTX *lib_ctx = NULL; /* The library context */ R_CERT_CTX *x509_cert_ctx = NULL; /* The certificate context */ R_CERT *ca_cert = NULL; /* The CA certificate */ R_CERT *client_cert = NULL; /* The client certificate */ R_PKEY *pkey = NULL; /* The public key */ unsigned char *p; /* A pointer into a binary buffer */ unsigned int consumed_len; /* The Bytes used in converting the * certificate from binary */ BIO *bio_err = NULL; /* The standard error output */ int verified; /* The signature verified */ /* * Create a BIO to stderr to report error messages and the verification * result. BIOs are the Basic Input/Output mechanism provided by RSA and * are recommended for all input and output from applications. */ if ((bio_err = BIO_new_fp(stderr, BIO_NOCLOSE)) == NULL) { goto err; } /* * Create the library context. Retrieve the custom resource list and create * a library context to provide access to all configurable aspects of the * library. A user-defined resource list demonstrates how to select modules * to include in the resource list and application. */ if ((ret = R_LIB_CTX_new(my_resource_list,0, &lib_ctx)) != R_ERROR_NONE) { BIO_printf(bio_err,"Failed to create a library context\n"); goto err; } /* * This custom resource list supports X.509 certificates only. To configure * this sample for WTLS certificates, replace the X.509 resource list item * (R_CERT_RES_X509) with the WTLS resource list item (R_CERT_RES_WTLS). * Use the WTLS type (R_CERT_TYPE_WTLS) to create the context and * certificates. */ /* * Create a certificate context. All certificate operations require a * certificate context which provides access to the certificate * functionality. */ ret = R_CERT_CTX_new(lib_ctx, R_RES_FLAG_DEF, R_CERT_TYPE_X509, &x509_cert_ctx); if (ret != R_ERROR_NONE) { goto err; } /* * Load the CA certificate into a new certificate object. The certificate * object stores all certificate information. The CA certificate is defined * above in binary format. */ p = ca_x509_certificate; ret = R_CERT_from_binary(x509_cert_ctx, R_FLAG_SHARE_DATA, R_CERT_TYPE_X509, sizeof(ca_x509_certificate), (const unsigned char *)p, &consumed_len, &ca_cert); if ((ret != R_ERROR_NONE) || (ca_cert == NULL)) { BIO_printf(bio_err, "Failed to load the certificate - exiting\n"); goto err; } /* * Obtain a reference to the public key in the CA certificate for * the verification process. */ ret = R_CERT_public_key_to_R_PKEY(ca_cert, R_FLAG_SHARE_DATA, &pkey); if ((ret != R_ERROR_NONE) || (pkey == NULL)) { BIO_printf(bio_err, "Failed to obtain the public key - exiting\n"); goto err; } /* * Load the client certificate into a new certificate object. The * certificate object stores all certificate information. The client * certificate is defined above in binary format. */ p = client_x509_certificate; ret = R_CERT_from_binary(x509_cert_ctx, R_FLAG_SHARE_DATA, R_CERT_TYPE_X509, sizeof(client_x509_certificate), (const unsigned char *)p, &consumed_len, &client_cert); if ((ret != R_ERROR_NONE) || (client_cert == NULL)) { BIO_printf(bio_err, "Failed to load the certificate - exiting\n"); goto err; } /* * Verify the client certificate using the public key of the CA * certificate */ ret = R_CERT_verify(client_cert, pkey, &verified); if (ret != R_ERROR_NONE) { BIO_printf(bio_err, "R_CERT_verify failure\n"); goto err; } if (!verified) { ret = R_ERROR_FAILED; BIO_printf(bio_err, "Failed to verify the certificate\n"); goto err; } else { BIO_printf(bio_err, "Successfully verified the certificate\n"); } /* Indicates success */ ret = R_ERROR_NONE; err: /* * Clean up. Report errors if there is an output stream using both the * error and the string representation. Destroy the dynamically allocated * objects and return an exit code. */ if ((ret != R_ERROR_NONE) && (bio_err != NULL)) { BIO_printf(bio_err, "Error: (%d) %s\n", ret, R_LIB_CTX_get_error_string(lib_ctx, R_RES_MOD_ID_LIBRARY, ret)); } /* Free the allocated memory */ if (pkey != NULL) { R_PKEY_free(pkey); } if (client_cert != NULL) { R_CERT_free(client_cert); } if (ca_cert != NULL) { R_CERT_free(ca_cert); } if (x509_cert_ctx != NULL) { R_CERT_CTX_free(x509_cert_ctx); } if (lib_ctx != NULL) { PRODUCT_LIBRARY_FREE(lib_ctx); } if (bio_err != NULL) { BIO_free(bio_err); } /* Return the exit code */ return(R_ERROR_EXIT_CODE(ret)); }