RSA BSAFE Micro Edition Suite

Streamlined security for mobile and embedded devices

Search  Print

Extracting Details of Extensions from Certificates

This sample demonstrates how to extract details about extensions from a certificate. The key usage, extended key usage and authority information access extensions' details can be displayed. An extension identified by its OID value can be extracted and the data dumped.

Sample Description:
-------------------
This sample loads a certificate and provides details on
extensions in the certificate. Key usage extended key usage
and authority information access extensions can be displayed
if they exist. An extension identifed by its OID value
can be dumped as well.

Procedure:
----------
 1)  Create the output BIO.
 2)  Read and parse the command line options.
 3)  Create the library context.
 4)  Load the certificate.
 5)  Display the details of extensions as request on command line.
 6)  Clean up.


/* $Id: ext.c,v 1.1.2.3 2005/10/27 01:19:25 sparki 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"

/* Usage statement for this program */
static char *cert_usage[] =
{
    "usage: cert [options]\n",
    "where options are:\n",
    " -in arg             - The input certificate file\n",
#ifdef NO_PEM
    " -inform arg         - The input format (BIN only)\n",
#else
    " -inform arg         - The input format - one of BIN PEM",
    " (default is PEM)\n",
#endif /* NO_PEM */
#ifndef NO_WTLSCERT
    " -intype arg         - The input type - one of WTLS X509 \n",
    "                       (default is X509)\n",
#else /* NO_WTLSCERT */
    " -intype arg         - The input type - X509 \n",
#endif /* !NO_WTLSCERT */
    " -hex                - Print the certificate extensions in hexadecimal "
    "format\n",
    " -validity           - Output the validity of the certificate's "
    "extensions\n",
    " -key_usage          - Output the key usage of the certificate\n",
    " -ext_key_usage      - Output the extended key usage of the "
    "certificate\n",
    " -aia                - Output the authority information access of the "
    "certificate\n",
    " -oid                - Retrieve extension by OID and print value\n",
#ifdef NO_SOFTWARE_CRYPTO
    " -no_fips140         - Use non FIPS140 crypto implementations\n",
#endif /* NO_SOFTWARE_CRYPTO */
    " -eg                 - Example Usage\n",
    NULL
};

/* Example usages statement for this program */
static char *cert_example_usage[] =
{
    "Print the certificate extensions in hexadecimal form\n",
    "ext -in cert.in -hex\n",
    "\n",
    "Print the key usage extension and extended key usage extension\n",
    "ext -in cert.in -key_usage -ext_key_usage\n",
    "\n",
    "Retrieve an extension by OID and print the value\n",
    "ext -int cert.in -oid 6086480186f842010d\n",
    "\n",
    "Validate the certificate's extensions\n",
    "ext -in cert.in -validate\n",
    "\n",
    "where:  cert.in    = The certificate upon which to perform operations\n",
    "\n",
    NULL
};

/*
 * Demonstrates how to use the most common operations performed on
 * certificate extensions.
 *
 * @param   argc   [In]      The number of command line arguments.
 * @param   argv   [In]      An array of command line argument strings.
 *
 * @returns R_ERROR_NONE indicates success.<br>
 *          See @ref R_ERROR_IDS for valid values.
 *
 * @note    If an error occurs, the error value is displayed where possible.
 */
int main(int argc, char **argv)
{
    int ret = R_ERROR_NONE;      /* The return value */
    BIO *bio_out = NULL;         /* The BIO that represents stdout */
    BIO *bio_err;                /* The BIO that represents stderr */
    BIO *in = NULL;              /* The BIO to read from for input */
    R_RES_LIST *res_list;        /* The resource list */
    R_LIB_CTX *lib_ctx = NULL;   /* The library context */
    int badop = 0;               /* Indicates a bad option on the command
                                  * line */
    char *infile = NULL;         /* The name of the file from which to read */
    int cert_type;               /* The type of certificate */
    R_FORMAT cert_form;          /* The format of certificate */
    R_CERT *cert = NULL;         /* The certificate object */
    int do_hex;                  /* The hexadecimal version to display */
    int do_validity;             /* Display the validity of the certificate
                                  * extensions */
    int do_key_usage;            /* Display the key usage of the certificate */
    int do_ext_key_usage;        /* Display the extended key usage of the
                                  * certificate */
    int do_aia;                  /* Display the authority information access of
                                  * the certificate */
    int do_oid;                  /* Retrieve an extension by OID and display
                                  * the value */
    R_ITEM oid;                  /* OID data and length */
    char *str;                   /* A character string */
    R_CERT_CTX *cert_ctx = NULL; /* The certificate context */
    R_TITEM titem;               /* An item of data with a type */
    R_ITEM item;                 /* An item of data with length */
    R_EXT *ext = NULL;           /* An extension object */

    /* Initialize to defaults */
    cert_type = R_CERT_TYPE_X509;
#ifndef NO_PEM
    cert_form = R_FORMAT_PEM;
#else /* !NO_PEM */
    cert_form = R_FORMAT_BINARY;
#endif /* !NO_PEM */
    do_hex = 0;
    do_validity = 0;
    do_key_usage = 0;
    do_ext_key_usage = 0;
    do_aia = 0;
    do_oid = 0;
    oid.data = NULL;

    res_list = PRODUCT_DEFAULT_RESOURCE_LIST();

    /*
     * Create BIOs to stderr and stdout. 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)
    {
        ret = R_ERROR_ALLOC_FAILURE;
        goto end;
    }
    if ((bio_out = BIO_new_fp(stdout, BIO_NOCLOSE)) == NULL)
    {
        ret = R_ERROR_ALLOC_FAILURE;
        goto end;
    }

    /* Parse the command line parameters */

    /* Skip over the program name command line argument */
    argc--;
    argv++;

    /* Check to ensure there are command line arguments supplied */
    if (argc < 1)
    {
        goto bad;
    }

    /* Process the command line arguments */
    while (argc >= 1)
    {
        /* The name of the input file */
        if ((Strcmp(*argv, "-in") == 0) ||
            (Strcmp(*argv, "-cert") == 0))
        {
            /*
             * Obtain the next argument if it does not start with a dash.
             * A dash is probably another option.
             */
            if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0))
            {
                goto bad;
            }
            infile = *argv;
        }
        /* The type of certificate that will be read in */
        else if ((Strcmp(*argv, "-certtype") == 0)  ||
                 (Strcmp(*argv, "-intype") == 0))
        {
            if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0))
            {
                goto bad;
            }
            str = *argv;

            /*
             * Convert the string to a value. If the string is not recognized
             * (UNKNOWN) then report an error.
             */
            if ((ret = R_CERT_TYPE_from_string(str,
                &cert_type)) != R_ERROR_NONE)
            {
                BIO_printf(bio_err, "Unknown certificate type: %s\n", str);
                goto bad;
            }
        }
        /* The format of the certificate that will be read in */
        else if ((Strcmp(*argv, "-certform") == 0)  ||
                 (Strcmp(*argv, "-inform") == 0) )
        {
            if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0))
            {
                goto bad;
            }
            str = *argv;

            /*
             * Convert the string to a value. If the string is not recognized
             * (UNKNOWN) then report an error.
             */
            if ((ret = R_FORMAT_from_string(str, &cert_form)) != R_ERROR_NONE)
            {
                BIO_printf(bio_err, "Unknown certificate format: %s\n", str);
                goto bad;
            }
        }
        /* The hexadecimal version to display */
        else if (Strcmp(*argv, "-hex") == 0)
        {
            do_hex = 1;
        }
        /* The validity of the certificate's extensions to display */
        else if (Strcmp(*argv, "-validity") == 0)
        {
            do_validity = 1;
        }
        /* The key usage to display */
        else if (Strcmp(*argv, "-key_usage") == 0)
        {
            do_key_usage = 1;
        }
        /* The extended key usage to display */
        else if (Strcmp(*argv, "-ext_key_usage") == 0)
        {
            do_ext_key_usage = 1;
        }
        /* The authority information access to display */
        else if (Strcmp(*argv, "-aia") == 0)
        {
            do_aia = 1;
        }
        /* The OID to look up an extension with */
        else if (Strcmp(*argv, "-oid") == 0)
        {
            if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0))
            {
                goto bad;
            }
            str = *argv;

            /* Ensure there an even number of digits in the OID */
            if ((Strlen(str) & 1) != 0)
            {
                BIO_printf(bio_err, "Bad OID data: %s", str);
                goto bad;
            }
            /* Calculate the length of the OID and allocate space for it */
            oid.len = Strlen(str) / 2;
            oid.data = (unsigned char *)Malloc(oid.len);
            if (oid.data == NULL)
            {
                ret = R_ERROR_ALLOC_FAILURE;
                BIO_printf(bio_err, "Unable to allocate memory: %d\n", oid.len);
                goto end;
            }
            ret = R_hexstr_to_bin(str, Strlen(str), oid.data);
            if (ret != R_ERROR_NONE)
            {
                BIO_printf(bio_err, "Bad OID data: %s", str);
                goto bad;
            }
            do_oid = 1;
        }
#ifdef NO_SOFTWARE_CRYPTO
        else if (Strcmp(*argv, "-no_fips140") == 0)
        {
            res_list = PRODUCT_NON_FIPS_140_MODE_RESOURCE_LIST();
        }
#endif /* NO_SOFTWARE_CRYPTO */
        /* The usage information to display */
        else if (Strcmp(*argv, "-help") == 0)
        {
            goto bad;
        }
        else if (Strcmp(*argv,"-eg") == 0)
        {
            char **egp;
            for (egp = cert_example_usage; (*egp) != NULL; egp++)
            {
                BIO_printf(bio_out, *egp);
            }
            goto end;
        }
        /* The option on the command line was not recognized */
        else
        {
            BIO_printf(bio_err, "unknown option %s\n", *argv);
            badop = 1;
            break;
        }

        /* Move onto the next command line argument */
        argc--;
        argv++;
    }

    /* Ensure a certificate is available for processing */
    if (infile == NULL)
    {
        badop = 1;
        BIO_printf(bio_err, "No certificate supplied (-in option)\n");
    }

    /* Enter the usage if there was a bad option */
    if (badop)
    {
        char **pp;

bad: ;
        for (pp = cert_usage; (*pp != NULL); pp++)
        {
            BIO_printf(bio_err, *pp);
        }
        goto end;
    }


    /*
     * Create the library context to provide access to all configurable aspects
     * of the library.
     */
    if ((ret = PRODUCT_LIBRARY_NEW(res_list, 0, &lib_ctx)) != R_ERROR_NONE)
    {
        BIO_printf(bio_err, "Unable to create the library context\n");
        goto end;
    }

    /*
     * 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, cert_type, &cert_ctx);
    if (ret != R_ERROR_NONE)
    {
        BIO_printf(bio_err, "The new certificate context failed\n");
        goto end;
    }

    /*
     * Read the certificate into a new certificate object that stores all the
     * certificate information.
     */
    /* Open the input file - this is the certificate file */
    if ((in = BIO_new_file(infile, "rb")) == NULL)
    {
        ret = R_ERROR_NOT_FOUND;
        BIO_printf(bio_err, "Unable to open the input file %s\n", infile);
        goto end;
    }

    /* Read the certificate into a certificate object */
    ret = R_CERT_read(cert_ctx, in, cert_type, cert_form, &cert);
    if (ret != R_ERROR_NONE)
    {
        BIO_printf(bio_err, "Unable to load the certificate\n");
        goto end;
    }

    /* Display the validity of the certificate's extensions */
    if (do_validity)
    {
        /* Check that all critical extensions are recognized */
        ret = R_CERT_check(cert, R_CERT_CHECK_FLAG_EXTENSIONS);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_out, "Certificate's extensions are not valid\n");
        }
        else
        {
            BIO_printf(bio_out, "Certificate's extensions are valid\n");
        }
    }

    /* Display the key usage as a string */
    if (do_key_usage)
    {
        static char str[256];   /* The character string */

        /* Get a string representing the key usage */
        ret = R_CERT_key_usage_to_string(cert, NULL, sizeof(str), str);
        if (ret == R_ERROR_NOT_FOUND)
        {
            BIO_printf(bio_out, "No Key Usage extension in certificate\n");
            ret = R_ERROR_NONE;
        }
        else if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err,
                "Unable to extract the key usage from the certificate\n");
            goto end;
        }
        else
        {
            BIO_printf(bio_out, "Key Usage = %s\n", str);
        }
    }

    /* Display the extended key usage as a string */
    if (do_ext_key_usage)
    {
        static char str[256];   /* The character string */

        /* Get a string representing the extended key usage */
        ret = R_CERT_extended_key_usage_to_string(cert, NULL, sizeof(str), str);
        if (ret == R_ERROR_NOT_FOUND)
        {
            BIO_printf(bio_out, "No Extended Key Usage extension in "
                "certificate\n");
            ret = R_ERROR_NONE;
        }
        else if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err,
                "Unable to extract the key usage from the certificate\n");
            goto end;
        }
        else
        {
            BIO_printf(bio_out, "Extended Key Usage = %s\n", str);
        }
    }

    /* Display the extended key usage as a string */
    if (do_aia)
    {
        static char str[256];   /* The character string */

        /* Get a string representing the authority information access */
        ret = R_CERT_authority_info_access_to_string(cert, "\n    ",
            sizeof(str), str);
        if (ret == R_ERROR_NOT_FOUND)
        {
            BIO_printf(bio_out, "No Authority Info Access extension in "
                "certificate\n");
            ret = R_ERROR_NONE;
        }
        else if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err,
                "Unable to extract the authority information access from the "
                "certificate\n");
            goto end;
        }
        else
        {
            BIO_printf(bio_out, "Authority Info Access:\n    %s\n", str);
        }
    }

    /* Retrieve an extension by OID and print the value */
    if (do_oid)
    {
        /* Display the OID that will be used */
        BIO_printf(bio_out, "OID: ");
        BIO_dump_format(bio_out, oid.data, oid.len, BIO_DUMP_FORMAT_HEX,
            ':', 0, 16);

        /* Create a new extension object */
        ret = R_EXT_new(lib_ctx, R_RES_FLAG_DEF, &ext);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err, "Unable to create a new extension object\n");
            goto end;
        }

        /* Set the OID data into the extension */
        ret = R_EXT_set_info(ext, R_EXT_INFO_OID, &oid);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err, "Unable to set OID data into extension\n");
            goto end;
        }

        /* Search for an extension with the OID that has been set */
        ret = R_CERT_get_info(cert, R_CERT_INFO_EXTENSION_BY_OID, ext);
        if (ret == R_ERROR_NOT_FOUND)
        {
            BIO_printf(bio_out, "Unable to find extension in certificate\n");
            ret = R_ERROR_NONE;
        }
        else if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err, "Unable to get extension by OID\n");
            goto end;
        }

        /* Get the data for the extenstion */
        ret = R_EXT_get_info(ext, R_EXT_INFO_DATA, &item);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err, "Unable to get OID data from extension\n");
            goto end;
        }

        /* Dump out the extension data as hexadecimal bytes. */
        BIO_dump_format(bio_out, item.data, item.len, BIO_DUMP_FORMAT_HEX,
            ':', 4, 16);
    }

    /* Display the certificate extensions in plain hexadecimal Bytes format */
    if (do_hex)
    {
        /* Get the raw extension bytes */
        ret = R_CERT_get_info(cert, R_CERT_INFO_EXTENSIONS, &titem);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err, "Unable to display the hexadecimal format"
                " of the certificate extensions\n");
            goto end;
        }

        /* Dump out the extension data in hexadecimal format */
        BIO_printf(bio_out, "Extensions in hexadecimal format:\n");
        BIO_dump_format(bio_out, titem.data, titem.len, BIO_DUMP_FORMAT_HEX,
            ':', 4, 16);
    }

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_err != NULL))
    {
        if (lib_ctx != NULL)
        {
            BIO_printf(bio_err, "Error: (%d) %s\n", ret,
                R_LIB_CTX_get_error_string(lib_ctx, R_RES_MOD_ID_LIBRARY, ret));
        }
        else
        {
            BIO_printf(bio_err, "Error: %d\n", ret);
        }
    }

    if (ext != NULL)
    {
        R_EXT_free(ext);
    }
    if (cert != NULL)
    {
        R_CERT_free(cert);
    }
    if (cert_ctx != NULL)
    {
        R_CERT_CTX_free(cert_ctx);
    }
    if (in != NULL)
    {
        BIO_free(in);
    }
    if (lib_ctx != NULL)
    {
        PRODUCT_LIBRARY_FREE(lib_ctx);
    }
    if (oid.data != NULL)
    {
        Free(oid.data);
    }
    if (bio_err != NULL)
    {
        BIO_free(bio_err);
    }
    if (bio_out != NULL)
    {
        BIO_free(bio_out);
    }

    return(R_ERROR_EXIT_CODE(ret));
}


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