RSA BSAFE Micro Edition Suite

Streamlined security for mobile and embedded devices

Search  Print

cm_adv.c

/* $Id: cm_adv.c,v 1.43 2005/08/08 05:33:30 jlevander 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.
 *
 *
 */

/*
 * @file
 * This sample demonstrates advanced PKCS #7 signed data operations using two
 * user-supplied application-specific callback functions, which are added to
 * the resource list.
 *
 * In the time verification function, the certificate is extracted from the
 * verification details object. The notBefore and notAfter times are extracted
 * from the certificate and printed. No actual action is taken on the time
 * information in this sample.
 *
 * In the certificate details verification function the certificate is
 * extracted from the verification details object. The extension information
 * is extracted from the certificate and printed. No actual action is taken
 * on the extension information in this sample.
 */

#include "r_prod.h"
#include "cm_com.h"

#define MAX_BUF_LEN 256
#define STRING_SEPERATOR " "

static int set_resources(BIO *bio_out, R_RES_LIST **res_list, int set);
static R_VERIFY_TIME_FUNC_T *get_vfy_time_func(void *imp_data);
static R_VERIFY_DETAIL_FUNC_T *get_vfy_detail_func(void *imp_data);
static int vfy_time_func(R_VERIFY_STATE *state, R_VERIFY_DETAILS *detail);
static int vfy_detail_func(R_VERIFY_STATE *state, R_VERIFY_DETAILS *detail,
    int index);

/* Usage help message. */
static char *cm_adv_usage[] =
{
    "usage: cm_adv [options]\n",
    "where options are:\n",
    " -cm_msg file           - The file containing the cryptographic message\n",
    " -data_msg file         - File containing the data if it's not part of\n",
    "                          the cryptographic message\n",
    " -single                - The cryptographic message and detached data are"
    "\n",
    "                          in the same file, the cryptographic message "
    "first\n",
    "                          followed by the detached data\n",
    " -wrap                  - The detached message is wrapped\n",
    "                          structure and should be unwrapped before use\n",
    " -certs list            - List of certificates (colon separated)\n",
    " -certtype encoding     - Encoding of the certificates - only X509\n",
    "                          (default) supported\n",
#ifdef NO_PEM
    " -certform format       - Format of the certificates (BIN only)\n"
#else
    " -certform format       - Format of the certificates\n"
    "                          - one of BIN (default), PEM\n",
#endif
    " -vfy_opts option       - Certificate verification options - one of"
    "NONE, DEF,\n",
    "                          ALL, NO_COMPLETE\n",
    " -set_vfy               - Sets the additional verification functions\n",
    "                          for verification of the name and times in a\n"
    "                          certificate\n",
    " -no_signer             - Do not verify the signers\n",
    " -no_data               - Do not verify the data\n",
    " -print_signer          - Print the certificate information for each of"
    "the\n",
    "                          signers in the cryptographic message\n",
    " -print_data            - Print the signed data of the cryptographic"
    "message\n",
    " -time YYYYMMDDHHMMSSZ  - Set the verification time rather than use the\n",
    "                          system time\n",
#ifdef NO_SOFTWARE_CRYPTO
    " -no_fips140            - Use non FIPS140 crypto implementations\n",
#endif /* NO_SOFTWARE_CRYPTO */
    NULL
};

/*
 * Main sample program entry point
 *
 * @param argc  [In]  The number of arguments typed on the command line.
 * @param argv  [In]  The array of individual arguments from the command line.
 *
 * @returns  R_ERROR_NONE indicates success.<br>
 *           See @ref R_ERROR_IDS for valid values.
 */
int main(int argc, char **argv)
{
    R_RES_LIST       *res_list  = NULL;
    R_LIB_CTX        *lib_ctx   = NULL;
    R_CM_CTX         *ctx       = NULL;
    R_CM             *obj       = NULL;
    R_CM             *data_obj  = NULL;
    R_CERT_CTX       *cert_ctx  = NULL;
    R_CERT_STORE_CTX *store_ctx = NULL;
    R_VERIFY_CTX     *vfy_ctx   = NULL;
    BIO              *bio_out   = NULL;
    R_ITEM            data      = { 0, NULL };
    R_TITEM           msg_data  = { R_FLAG_SHARE_DATA, 0, NULL };
    char             *cm_file;
    char             *datafile;
    char             *certfile;
    char             *certtype  = NULL;
    char             *certform;
    char             *options;
    unsigned char    *cm_data   = NULL;
    unsigned int      num_used;
    unsigned int      cm_len;
    int               ret       = R_ERROR_NONE;
    int               is_verified;
    R_CM_TYPE         data_type;
    int               wrap = 0;
    int               single = 0;
    int               print_sig;
    int               print_data;
    int               no_signer = 0;
    int               no_data = 0;
    int               vfy_opts;
    unsigned int      slen;
    char             *vfy_time = NULL;

    /* Set the defaults */
    cm_file    = NULL;
    datafile   = NULL;
    certfile   = NULL;
    certtype   = "X509";
    certform   = "BIN";
    options    = NULL;
    vfy_opts   = 0;
    print_sig  = 0;
    print_data = 0;
    single     = 0;
    wrap       = 0;
    no_signer  = 0;
    no_data    = 0;

    res_list = PRODUCT_DEFAULT_RESOURCE_LIST();

    /*
     * Create a BIO to stdout. BIOs are the Basic Input/Output mechanism
     * provided by RSA and are recommended for all input and output from
     * applications.
     */
    if ((bio_out = BIO_new_fp(stdout, BIO_NOCLOSE)) == NULL)
    {
        ret = R_ERROR_ALLOC_FAILURE;
        goto end;
    }

    /* Parse the command line parameters */

    /* Skip the program name */
    argc--;
    argv++;

    /* Process all command line options */
    while (argc >= 1)
    {
        if (Strcmp(*argv, "-cm_msg") == 0)
        {
            if (--argc < 1)
            {
                goto bad;
            }
            cm_file = *(++argv);
        }
        else if (Strcmp(*argv, "-data_msg") == 0)
        {
            if (--argc < 1)
            {
                goto bad;
            }
            datafile = *(++argv);
        }
        else if (Strcmp(*argv, "-single") == 0)
        {
            single = 1;
        }
        else if (Strcmp(*argv, "-wrap") == 0)
        {
            wrap = 1;
        }
        else if (Strcmp(*argv, "-certs") == 0)
        {
            if (--argc < 1)
            {
                goto bad;
            }
            certfile = *(++argv);
        }
        else if (Strcmp(*argv, "-certtype") == 0)
        {
            if (--argc < 1)
            {
                goto bad;
            }
            certtype = *(++argv);
        }
        else if (Strcmp(*argv, "-certform") == 0)
        {
            if (--argc < 1)
            {
                goto bad;
            }
            certform = *(++argv);
        }
        else if (Strcmp(*argv, "-vfy_opts") == 0)
        {
            if (--argc < 1)
            {
                goto bad;
            }
            options = *(++argv);
        }
        else if (Strcmp(*argv, "-set_vfy") == 0)
        {
            vfy_opts = 1;
        }
        else if (Strcmp(*argv, "-no_signer") == 0)
        {
            no_signer = 1;
        }
        else if (Strcmp(*argv, "-no_data") == 0)
        {
            no_data = 1;
        }
        else if (Strcmp(*argv, "-print_signer") == 0)
        {
            print_sig = 1;
        }
        else if (Strcmp(*argv, "-print_data") == 0)
        {
            print_data = 1;
        }
        else if (Strcmp(*argv, "-time") == 0)
        {
            if (--argc < 1)
            {
                goto bad;
            }
            vfy_time = *(++argv);
        }
#ifdef NO_SOFTWARE_CRYPTO
        else if (Strcmp(*argv, "-no_fips140") == 0)
        {
            res_list = PRODUCT_NON_FIPS_140_MODE_RESOURCE_LIST();
        }
#endif /* NO_SOFTWARE_CRYPTO */
        else
        {
            BIO_printf(bio_out, "Unknown option %s\n", *argv);
            goto bad;
        }
        argc--;
        argv++;
    }

    /* Simple checks first */
    if (cm_file == NULL)
    {
        BIO_printf(bio_out, "Input file required\n");
        goto bad;
    }

    /* Display the help menu if an invalid command line option was entered */
    if (0)
    {
        char **pp;
bad:
        for (pp = cm_adv_usage; (*pp != NULL); pp++)
        {
            BIO_printf(bio_out, *pp);
        }
        goto end;
    }

    /*
     * Create a library context to provide access to all configurable aspects
     * of the library. The default list is updated with extra functions to
     * perform extended verification.
     */

    /* Update the resource list if required */
    if ((ret = set_resources(bio_out, &res_list, vfy_opts)) != R_ERROR_NONE)
    {
        goto end;
    }

    /* Create a new library context */
    if ((ret = PRODUCT_LIBRARY_NEW(res_list, R_RES_FLAG_DEF, &lib_ctx)) !=
        R_ERROR_NONE)
    {
        BIO_printf(bio_out, "Library new failure\n");
        goto end;
    }

    /*
     * Set up the certificate-related functionality.
     * If any certificates are specified:
     *    - Create a certificate context.
     *    - Create a store context.
     *    - Create a store object.
     * For each certificate:
     *    - Read the certificate from file.
     *    - Set the certificate against the store object.
     *    - Set the certificate trust level.
     *    - Add the certificate to the store (using the store object).
     */
    if ((ret = load_certificates(bio_out, lib_ctx, certfile, certtype,
        certform, &cert_ctx, &store_ctx)) != R_ERROR_NONE)
    {
        goto end;
    }

    /* Create a verification context and sets the verification options */
    if ((ret = set_verification(bio_out, lib_ctx, options, vfy_time, &vfy_ctx))
        != R_ERROR_NONE)
    {
        goto end;
    }

    /* Create a new cryptographic message context */
    if ((ret = R_CM_CTX_new(lib_ctx, R_RES_FLAG_DEF, R_CM_TYPE_DEFAULT,
        &ctx)) != R_ERROR_NONE)
    {
        BIO_printf(bio_out, "R_CM_CTX_new failure\n");
        goto end;
    }

    /*
     * Read the data from cryptographic message file into the buffer. The
     * cryptographic message is in binary form and simply copied to a
     * buffer pointed to by cm_data.
     */
    if ((ret = data_from_file(bio_out, cm_file, &cm_data, &cm_len)) !=
        R_ERROR_NONE)
    {
        goto end;
    }

    /*
     * Load the cryptographic message buffer into a cryptographic message
     * object. Process the cryptographic message depending on the format:
     *    - Attached data: The data is inside the cryptographic message.
     *    - Detached data: The data is detached from the cryptographic
     *                     message.
     * The detached data may be in a separate file or in the same file as
     * the cryptographic message and appended to the cryptographic message.
     * Furthermore the data may be wrapped (whether attached or not).
     * All of these variations need to be determined before the data can
     * be accessed.
     */
    if ((ret = R_CM_from_binary(ctx, R_FLAG_SHARE_DATA, R_CM_TYPE_UNKNOWN,
        R_CM_ENCODING_FORMAT_WRAPPED, cm_len,
        cm_data, &num_used, &obj)) != R_ERROR_NONE)
    {
        BIO_printf(bio_out, "From binary failure on cryptographic message\n");
        goto end;
    }

    /*
     * Access the data to verify. Determine where the actual data is and point
     * the msg_data structure at it.
     *
     * If the data is detached but in the same file, the data follows the
     * cryptographic message. Point to the data after the cryptographic message
     * that was just read above.
     *
     * If the data is detached but in a separate file, read the data from the
     * specified file.
     *
     * If the data is attached it is inside the cryptographic message and no
     * further action needs to be taken.
     */
    if (single == 1)
    {
        /*
         * Set the data message with the remainder of the data (if the data is
         * detached but in the same file as the cryptographic message)
         */
        msg_data.data = cm_data + num_used;
        msg_data.len  = cm_len  - num_used;
    }
    else if (datafile != NULL)
    {
        /*
         * If there is any message data read that as well (if the data is
         * detached but in a separate file to the cryptographic message)
         */
        if ((ret = data_from_file(bio_out, datafile, &data.data, &slen)) !=
            R_ERROR_NONE)
        {
            goto end;
        }

        /* Use the data as is */
        msg_data.data = data.data;
        msg_data.len  = data.len = slen;
    }

    /*
     * Determine the content type of the cryptographic message. This indicates
     * how to handle the attached data within the cryptographic message.
     */
    if ((ret = R_CM_get_info(obj, R_CM_INFO_TYPE, &data_type)) != R_ERROR_NONE)
    {
        BIO_printf(bio_out, "Retrieve content type failure\n");
        goto end;
    }

    /*
     * Load the data to be verified into a cryptographic message.
     * See the individual cases below.
     */
    if ((datafile == NULL) && (single == 0))
    {
        /* Attached data */
        if (data_type != R_CM_TYPE_DATA)
        {
            /*
             * If the content is not plain data, access the
             * actual message.
             */
            if ((ret = R_CM_content_to_R_CM(obj, R_FLAG_SHARE_DATA,
                &data_obj)) != R_ERROR_NONE)
            {
                BIO_printf(bio_out, "R_CM_content_to_R_CM failure\n");
                goto end;
            }
        }
        else
        {
            /*
             * In this case a plain data message was handed to this application
             * so the signedData object (obj) is really the data object.
             */
            data_obj = obj;
            obj      = NULL;
        }
    }
    else if (wrap == 1)
    {
        /*
         * Detached the wrapped data case. If the detached data is wrapped,
         * strip it off.
         */
        if ((ret = R_CM_from_binary(ctx, R_FLAG_SHARE_DATA, R_CM_TYPE_UNKNOWN,
            R_CM_ENCODING_FORMAT_WRAPPED,
            msg_data.len, msg_data.data, &num_used, &data_obj)) != R_ERROR_NONE)
        {
            BIO_printf(bio_out,
                "R_CM_from_binary failure on the wrapped data\n");
            goto end;
        }
    }
    else
    {
        /*
         * As the data is detached and not wrapped, create a new
         * cryptographic message and set the data against it.
         */
        if ((ret = R_CM_new(ctx, R_CM_TYPE_DATA, &data_obj)) != R_ERROR_NONE)
        {
            BIO_printf(bio_out, "R_CM_new failure\n");
            goto end;
        }

        /* Set the data against the object */
        if ((ret = R_CM_set_info(data_obj, R_CM_INFO_DATA, &msg_data)) !=
            R_ERROR_NONE)
        {
            BIO_printf(bio_out, "Set content data failure\n");
            goto end;
        }
    }

    /* If the data is plain data, it can only be printed */
    if (data_type == R_CM_TYPE_DATA)
    {
        goto print_data;
    }

    /*
     * Verify the signer unless it is not required. If the signers are not
     * verified, the key that will be used to verify the data is not
     * authenticated, making the verification process less secure.
     */
    if (no_signer != 1)
    {
        /* Verify all the signers */
        if ((ret = R_CM_signer_verify(obj, store_ctx, vfy_ctx, R_CM_INDEX_ALL,
            &is_verified)) != R_ERROR_NONE)
        {
            BIO_printf(bio_out, "\nR_CM_signer_verify failed\n");
            goto end;
        }

        if (!is_verified)
        {
            ret = R_ERROR_FAILED;
            BIO_printf(bio_out, "\nVerify signer failed\n");
            goto end;
        }

        /* Print all the verification information for the signers */
        if ((ret = print_signer_info(bio_out, obj, cert_ctx, print_sig)) !=
            R_ERROR_NONE)
        {
            goto end;
        }
    }

    /*
     * Verify the data. The actual data is in data_obj and all the
     * cryptographic information required to perform the verification (for
     * example, signer info) is in obj. Verify the data unless it is not
     * required. If the data is not verified it is not proved that a signer
     * actually signed the data, making the verification process less secure.
     */
    if (no_data != 1)
    {
        /* Finally verify the data */
        if ((ret = R_CM_signature_verify(obj, R_CM_INDEX_ALL, data_obj,
            &is_verified)) != R_ERROR_NONE)
        {
            BIO_printf(bio_out, "R_CM_signature_verify failed\n");
            goto end;
        }

        if (!is_verified)
        {
            ret = R_ERROR_FAILED;
            BIO_printf(bio_out, "Verify data failed\n");
            goto end;
        }
    }

print_data:

    /* Print the message */
    if (print_data == 1)
    {
        if ((ret = R_CM_write(data_obj, bio_out, R_FORMAT_TEXT, NULL,
            R_CM_ENCODING_FORMAT_RAW)) != R_ERROR_NONE)
        {
            BIO_printf(bio_out, "Failed to write decrypted data\n");
            goto end;
        }
    }

end:

    /*
     * 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_out != NULL))
    {
        BIO_printf(bio_out, "ERROR: (%d) %s\n", ret,
            R_LIB_CTX_get_error_string(lib_ctx, R_RES_MOD_ID_LIBRARY, ret));
    }

    if (cm_data != NULL)
    {
        Free(cm_data);
    }
    if (data.data != NULL)
    {
        Free(data.data);
    }
    if (obj != NULL)
    {
        R_CM_free(obj);
    }
    if (data_obj != NULL)
    {
        R_CM_free(data_obj);
    }
    if (ctx != NULL)
    {
        R_CM_CTX_free(ctx);
    }
    if (vfy_ctx != NULL)
    {
        R_VERIFY_CTX_free(vfy_ctx);
    }
    if (store_ctx != NULL)
    {
        R_CERT_STORE_CTX_free(store_ctx);
    }
    /*
     * The certificate context cannot be freed until the store has been emptied
     * as the certificates in the store hold a reference back to the
     * certificate context
     */
    if (cert_ctx != NULL)
    {
        R_CERT_CTX_free(cert_ctx);
    }
    if (lib_ctx != NULL)
    {
        PRODUCT_LIBRARY_FREE(lib_ctx);
    }
    if (bio_out != NULL)
    {
        BIO_free(bio_out);
    }

    return(R_ERROR_EXIT_CODE(ret));
}

/*
 * Sets the resource list with extra verification functions.
 *
 * @param bio_out   [Out]  The BIO for error messages.
 * @param res_list  [Out]  The resource list.
 * @param set       [In]   The flag to indicate if action it to be taken.
 *                         Non-zero indicates action is required.
 *
 * @returns  R_ERROR_NONE indicates success.
 *           See @ref R_ERROR_IDS for valid values.
 */
static int set_resources(BIO *bio_out, R_RES_LIST **res_list, int set)
{
    int ret = R_ERROR_NONE;

    /* If nothing needs to be set then simply return */
    if (set)
    {
        /* Set the certificate's time verification callback */
        if ((ret = R_VERIFY_set_time_verify_func(res_list,
            get_vfy_time_func)) != R_ERROR_NONE)
        {
            BIO_printf(bio_out, "Set time callback failure\n");
        }
        /* Set the details verification callback */
        else if ((ret = R_VERIFY_set_detail_verify_func(res_list,
            get_vfy_detail_func)) != R_ERROR_NONE)
        {
            BIO_printf(bio_out, "Set details callback failure\n");
        }
    }

    return(ret);
}

/*
 * Details the time verification get function that is inserted into the
 * resource list.
 *
 * @param imp_data  [In]   Not used.
 *
 * @returns  A pointer to the details time verification function.
 */
static R_VERIFY_TIME_FUNC_T *get_vfy_time_func(void *imp_data)
{
    return(&vfy_time_func);
}

/*
 * Details the verification get function that is inserted into the resource
 * list.
 *
 * @param imp_data  [In]   Not used.
 *
 * @returns  A pointer to the details verification function.
 */
static R_VERIFY_DETAIL_FUNC_T *get_vfy_detail_func(void *imp_data)
{
    return(&vfy_detail_func);
}

/*
 * Application-specific details time verification function that will be set in
 * the resource list.
 *
 * @param state     [In]   The verification state object.
 * @param detail    [In]   The verification details object.
 *
 * @returns  R_ERROR_NONE indicates success.
 *           See @ref R_ERROR_IDS for valid values.
 *
 * @note     The certificate is extracted from the verify details object. The
 *           notBefore and notAfter times are extracted from the certificate
 *           and printed. No actual action is taken on the time information
 *           in this sample.
 */
static int vfy_time_func(R_VERIFY_STATE *state, R_VERIFY_DETAILS *detail)
{
    int ret;
    R_VERIFY_CTX  *vfy_ctx;
    R_CERT        *cert;
    BIO           *bio_out;
    unsigned char *data;
    unsigned int   length;

    /* Access the verification context */
    if ((ret = R_VERIFY_STATE_get_R_VERIFY_CTX(state, &vfy_ctx)) !=
        R_ERROR_NONE)
    {
        goto done;
    }

    /* Extract the BIO for printing */
    if ((ret = R_VERIFY_CTX_get_info(vfy_ctx, R_VERIFY_CTX_INFO_CALLBACK_ARG,
        &bio_out)) != R_ERROR_NONE)
    {
        goto done;
    }

    /* Print something to show that verification time has been reached */
    BIO_printf(bio_out, "\n\t\t-----  REACHED VFY_TIME_FUNC  ----\n\n");

    /* Extract the certificate from the details */
    if ((ret = R_VERIFY_DETAILS_cert_to_R_CERT(detail,
        R_VERIFY_DETAIL_FLAG_BY_REFERENCE, &cert)) != R_ERROR_NONE)
    {
        goto done;
    }

    /* Retrieve the notBefore field and print its data */
    R_CERT_not_before_to_binary(cert, 0, NULL, &length);
    data = (unsigned char *)Malloc(length);
    R_CERT_not_before_to_binary(cert, length, data, &length);
    BIO_printf(bio_out, "NOT BEFORE DATA:\n");
    if ((data != NULL) && (length != 0))
    {
        BIO_dump(bio_out, data, length);
    }
    else
    {
        BIO_printf(bio_out, "\tNot available\n\n");
    }

    if (data != NULL)
    {
        Free(data);
    }

    /* Retrieve the notAfter field and print its data */
    R_CERT_not_after_to_binary(cert, 0, NULL, &length);
    data = (unsigned char *)Malloc(length);
    R_CERT_not_after_to_binary(cert, length, data, &length);
    BIO_printf(bio_out, "\nNOT AFTER DATA:\n");
    if ((data != NULL) && (length != 0))
    {
        BIO_dump(bio_out, data, length);
    }
    else
    {
        BIO_printf(bio_out, "\tNot available\n\n");
    }

    if (data != NULL)
    {
        Free(data);
    }

done:

    return(ret);
}

/*
 * An application-specific details verification function that will be set in
 * the resource list.
 *
 * @param state     [In]   The verification state object.
 * @param detail    [In]   The verification details object.
 * @param index     [In]   The index of the detail object in the state object.
 *                         Not used in this sample.
 *
 * @returns  R_ERROR_NONE indicates success.
 *           See @ref R_ERROR_IDS for valid values.
 *
 * @note     The certificate is extracted from the verification details object.
 *           The extension information is extracted from the certificate and
 *           printed. No actual action is taken on the extension information
 *           in this sample.
 */
static int vfy_detail_func(R_VERIFY_STATE *state, R_VERIFY_DETAILS *detail,
    int index)
{
    int ret;
    R_VERIFY_CTX  *vfy_ctx;
    R_CERT        *cert;
    BIO           *bio_out;
    char           ku_str[30];
    char          *str=NULL;
    int            count=0;

    Memset(ku_str, 0, 30);

    /* Access the verification context */
    if ((ret = R_VERIFY_STATE_get_R_VERIFY_CTX(state, &vfy_ctx)) !=
        R_ERROR_NONE)
    {
        goto done;
    }

    /* Extract the BIO for printing */
    if ((ret = R_VERIFY_CTX_get_info(vfy_ctx, R_VERIFY_CTX_INFO_CALLBACK_ARG,
        &bio_out)) != R_ERROR_NONE)
    {
        goto done;
    }

    /* Print something to show that verification time has been reached */
    BIO_printf(bio_out, "\n\t\t-----  REACHED VFY_DETAIL_FUNC  ----\n\n");

    /* Extract the certificate from the details */
    if ((ret = R_VERIFY_DETAILS_cert_to_R_CERT(detail,
        R_VERIFY_DETAIL_FLAG_BY_REFERENCE, &cert)) != R_ERROR_NONE)
    {
        goto done;
    }

    /* Print the header */
    BIO_printf(bio_out, "EXTENSIONS:");

    if (R_CERT_is_info_present(cert, R_CERT_INFO_EXTENDED_KEY_USAGE))
    {
        count++;
        BIO_printf(bio_out, "\n");
        BIO_printf(bio_out, "\tExtended Key Usage\n");
        if (R_CERT_is_info_critical(cert, R_CERT_INFO_EXTENDED_KEY_USAGE))
        {
            BIO_printf(bio_out, "\tExtension is critical\n");
        }
        else
        {
            BIO_printf(bio_out, "\tExtension is not critical\n");
        }

        /* Print more information based on the extension */
        if ((ret = R_CERT_extended_key_usage_to_string(cert, STRING_SEPERATOR,
            sizeof(ku_str), ku_str)) != R_ERROR_NONE)
        {
            BIO_printf(bio_out, "\tUnknown Extended Key Usage Data\n");
        }
        else
        {
            BIO_printf(bio_out, "\t%s Data\n", ku_str);
        }
    }

    if (R_CERT_is_info_present(cert, R_CERT_INFO_KEY_USAGE))
    {
        count++;
        BIO_printf(bio_out, "\n");
        BIO_printf(bio_out, "Key Usage\n");
        if (R_CERT_is_info_critical(cert, R_CERT_INFO_KEY_USAGE))
        {
            BIO_printf(bio_out, "\tExtension is critical\n");
        }
        else
        {
            BIO_printf(bio_out, "\tExtension is not critical\n");
        }

        if ((str = (char *)Malloc(MAX_BUF_LEN)) == NULL)
        {
            goto done;
        }
        Memset(str, 0, MAX_BUF_LEN);

        if ((ret = R_CERT_key_usage_to_string(cert, STRING_SEPERATOR,
            MAX_BUF_LEN, str)) != R_ERROR_NONE)
        {
            goto done;
        }
        if (str[0] == 0)
        {
            BIO_printf(bio_out, "\tNo Key Usage Set\n");
        }
        else
        {
            BIO_printf(bio_out, "\t%s\n", str);
        }
    }

    if (count == 0)
    {
        BIO_printf(bio_out, " None\n");
    }

done:

    if (str != NULL)
    {
        Free(str);
    }
    return(ret);
}


Copyright (c) 1999-2005 RSA Security Inc. All rights reserved. 072-001001-2100-001-000 - 2.1