RSA BSAFE Micro Edition Suite

Streamlined security for mobile and embedded devices

Search  Print

ext.c

/* $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