RSA BSAFE Micro Edition Suite

Streamlined security for mobile and embedded devices

Search  Print

cert.c

/* $Id: cert.c,v 1.74 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.
 *
 *
 */

#include "r_prod.h"

static int display_modulus(BIO *bio_err, BIO *out, R_CERT *cert);
static int display_pkey_text(BIO *bio_err, BIO *out, R_CERT *cert);
static int display_hash(BIO *bio_err, BIO *out, R_CERT *cert);
static int verify_cert(BIO *bio_err, BIO *bio_out, R_CERT *ca_cert,
    R_CERT *cert);
static int display_fingerprint(BIO *bio_err, BIO *out, R_CERT *cert);
static int display_thumbprint(BIO *bio_err, BIO *out, R_CERT *cert,
    R_CR_ALG_ID thumbprint_alg);

/* 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 */
    " -CAfile arg         - The Certification Authority (CA) certificate\n",
#ifdef NO_PEM /* NO_PEM */
    " -CAform arg         - The CA certificate format (BIN only)\n",
#else
    " -CAform arg         - The CA certificate format - one of BIN PEM",
    " (default is PEM)\n",
#endif /* NO_PEM */
#ifndef NO_WTLSCERT
    " -CAtype arg         - The CA certificate type - one of WTLS X509 \n",
    "                       (default is X509)\n",
#else /* NO_WTLSCERT */
    " -CAtype arg         - The CA certificate type - X509 \n",
#endif /* !NO_WTLSCERT */
    " -out arg            - The output file (default stdout)\n",
#ifdef NO_PEM
    " -outform arg        - The output format (BIN only)\n",
#else
    " -outform arg        - The output format - one of BIN PEM",
    " (default is PEM)\n",
#endif /* NO_PEM */
    " -outformarg arg     - The output format for BASE64 - one of 0,1,2 or 3\n",
    "                       0=EOL_NONE, 1=EOL_CR, 2=EOL_LF, 3=EOL_CR|LF\n",
    " -noout              - Indicates no output\n",
    " -text               - The output text format\n",
    " -C                  - Print the certificate in C format for inclusion",
    " in\n",
    "                       other code\n",
#ifndef NO_CFUNC
    " -Cf                 - Print a function in C that will return the\n",
    "                       specified certificate\n",
#endif /* NO_CFUNC */
    " -hex                - Print the certificate in hexadecimal format\n",
    " -codehex            - Print the certificate in code hexadecimal\n",
    "                       certificate\n",
    " -verify             - Verify the certificate.\n",
    "                       Pass in the certificate to verify with -in and \n",
    "                       the CA certificate, used to verify with -CAfile\n",
    " -serial             - Output the serial number value (X509 only)\n",
    " -issuer             - Output the issuer name\n",
    " -notBefore          - Output the time when the certificate becomes\n",
    "                       valid\n",
    " -notAfter           - Output the time when the certificate expires\n",
    " -dates              - Output both valid and expiry date\n",
    " -validity           - Output the validity of the certificate\n",
    " -subject            - Output the subject name\n",
    " -MID_subject        - Output the subject name in Mobile Information\n"
    "                       Device (MID) format\n",
    " -modulus            - Output the RSA key modulus\n",
    " -pkey_text          - Output the public key as text\n",
    " -hash               - Output a hash of the certificate\n",
    " -fingerprint        - Output the fingerprint of a certificate\n",
    " -thumbprint         - Output the thumbprint of a certificate\n",
    " -thumbprint_alg arg - Digest of the thumbprint - one of MD5 SHA1 \n",
    "                       (default is SHA1)\n",
#ifdef NO_SOFTWARE_CRYPTO
    " -no_fips140         - Use non FIPS140 crypto implementations\n",
#endif /* NO_SOFTWARE_CRYPTO */
    " -eg                 - Example Usage\n",
    NULL
};

static char *cert_example_usage[] =
{
    "Print the certificate details in text form\n",
    "cert -in cert.in -text\n",
    "\n",
    "Print before/after dates, current validity and subject\n",
    "cert -in cert.in -validity -subject -dates -noout\n",
    "\n",
#ifndef NO_PEM
    "Convert the certificate between formats (inform defaults to PEM)\n",
    "cert -in cert.in -out certin.bin -outform BIN\n",
    "\n",
#endif
    "Verify the certificate - CA cert has public key needed to verify",
    " signature\n",
    "cert -in cert.in -CAfile ca.cert -verify -noout\n",
    "\n",
    "where:  cert.in    = The certificate to perform operations on\n",
    "        certin.bin = The binary version of cert.in\n",
    "        ca.cert    = The certificate of CA that signed cert.in\n",
    "\n",
    NULL
};

/*
 * Demonstrates how to use the most common operations performed on
 * certificates.
 *
 * @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 */
    BIO *out = NULL;             /* The BIO to write output to */
    BIO *ca = NULL;              /* The BIO from which to read the CA
                                  * certificate */
    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 */
    char *outfile = NULL;        /* The name of file to write to */
    char *cafile = NULL;         /* The name of CA certificate file from
                                  * which to read */
    int cert_type;               /* The type of certificate */
    R_FORMAT cert_form;          /* The format of certificate */
    R_FORMAT out_cert_form;      /* The format of output certificate */
    int outform_arg;             /* Type of output format for the output form*/
    void *format_arg;                /* Pointer to outform_arg */
    int ca_type;                 /* The type of CA certificate */
    R_FORMAT ca_form;            /* The format of the CA certificate */
    int noout = 0;               /* Indicates that no output is generated */
    R_CERT *cert = NULL;         /* The certificate object */
    R_CERT *ca_cert = NULL;      /* The CA certificate object */
    int do_text;                 /* The text version to display */
    int do_c;                    /* The C version to display */
    int do_cf;                   /* The C fields version to display */
    int do_hex;                  /* The hexadecimal version to display */
    int do_codehex;              /* The code version in hexadecimal to
                                  * display */
    int do_serial;               /* Display the serial number */
    int do_issuer;               /* Display the issuer name */
    int do_subject;              /* Display the subject name */
    int do_MID_subject;          /* Display the subject name in MID (JSR 118) format */
    int do_modulus;              /* Display the modulus of the subject
                                  * public key */
    int do_hash;                 /* Display a hash of the subject name */
    int do_not_after;            /* Display the notAfter time */
    int do_not_before;           /* Display the notBefore time */
    int do_validity;             /* Display the time validity of the
                                  * certificate */
    int do_fingerprint;          /* Display a fingerprint of the certificate */
    int do_thumbprint;           /* Display a thumbprint of the certificate */
    int do_verify;               /* Verify the signature */
    int do_pkey_text;            /* Display the public key as text */
    R_CR_ALG_ID thumbprint_alg;  /* The hashing algorithm to use in
                                  * thumbprint */
    char *str;                   /* A character string */
    R_CERT_CTX *cert_ctx = NULL; /* The certificate context */

    /* Initialize to defaults */
    cert_type = R_CERT_TYPE_X509;
    ca_type = R_CERT_TYPE_X509;
#ifndef NO_PEM
    cert_form = R_FORMAT_PEM;
    ca_form = R_FORMAT_PEM;
    out_cert_form = R_FORMAT_PEM;
#else /* !NO_PEM */
    cert_form = R_FORMAT_BINARY;
    ca_form = R_FORMAT_BINARY;
    out_cert_form = R_FORMAT_BINARY;
#endif /* !NO_PEM */
    do_text = 0;
    do_c = 0;
    do_cf = 0;
    do_hex = 0;
    do_codehex = 0;
    do_verify = 0;
    do_serial = 0;
    do_issuer = 0;
    do_not_after = 0;
    do_not_before = 0;
    do_validity = 0;
    do_subject = 0;
    do_MID_subject = 0;
    do_modulus = 0;
    do_hash = 0;
    do_fingerprint = 0;
    do_thumbprint = 0;
    do_pkey_text = 0;
    thumbprint_alg = R_CR_ID_SHA1;
    format_arg = 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)
        {
            /*
             * 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 name of the Certification Authority (CA) certificate file
         * to read
         */
        else if (Strcmp(*argv, "-CAfile") == 0)
        {
            if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0))
            {
                goto bad;
            }
            cafile = *argv;
        }
        /* The type of the CA certificate to read */
        else if (Strcmp(*argv, "-CAtype") == 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, &ca_type)) != R_ERROR_NONE)
            {
                BIO_printf(bio_err, "Unknown certificate type: %s\n", str);
                goto bad;
            }
        }
        /* The format of the CA certificate to read */
        else if (Strcmp(*argv, "-CAform") == 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, &ca_form)) != R_ERROR_NONE)
            {
                BIO_printf(bio_err, "Unknown certificate format: %s\n", str);
                goto bad;
            }
        }
        /* The format of the certificate to write */
        else if ( (Strcmp(*argv, "-outform") == 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, &out_cert_form)) !=
                R_ERROR_NONE)
            {
                BIO_printf(bio_err, "Unknown certificate format: %s\n", str);
                goto bad;
            }
        }
        /* The format argument of the certificate to write */
        else if ( (Strcmp(*argv, "-outformarg") == 0) )
        {
            if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0))
            {
                goto bad;
            }
            outform_arg = atoi(*argv);
            format_arg = &outform_arg;
        }
        /* The name of the output file */
        else if (Strcmp(*argv, "-out") == 0)
        {
            if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0))
            {
                goto bad;
            }
            outfile = *argv;
        }
        /* The text version to display */
        else if (Strcmp(*argv, "-text") == 0)
        {
            do_text = 1;
        }
        /* The C code version to display */
        else if (Strcmp(*argv, "-C") == 0)
        {
            do_c = 1;
        }
#ifndef NO_CFUNC
        /* The C code version in fields to display */
        else if (Strcmp(*argv, "-Cf") == 0)
        {
            do_cf = 1;
        }
#endif /* !NO_CFUNC */
        /* The hexadecimal version to display */
        else if (Strcmp(*argv, "-hex") == 0)
        {
            do_hex = 1;
        }
        /* The C code version in hexadecimal to display */
        else if (Strcmp(*argv, "-codehex") == 0)
        {
            do_codehex = 1;
        }
        /* The verification signature */
        else if (Strcmp(*argv, "-verify") == 0)
        {
            do_verify = 1;
        }
        /* The serial number to display */
        else if (Strcmp(*argv, "-serial") == 0)
        {
            do_serial = 1;
        }
        /* The issuer name to display */
        else if (Strcmp(*argv, "-issuer") == 0)
        {
            do_issuer = 1;
        }
        /* The notBefore time to display */
        else if ((Strcmp(*argv, "-notBefore") == 0)  ||
                 ((Strcmp(*argv, "-notbefore") == 0)))
        {
            do_not_before = 1;
        }
        /* The notAfter time to display */
        else if ((Strcmp(*argv, "-notAfter") == 0)  ||
                 ((Strcmp(*argv, "-notafter") == 0)))
        {
            do_not_after = 1;
        }
        /* The notBefore and notAfter dates to display */
        else if (Strcmp(*argv, "-dates") == 0)
        {
            do_not_before = 1;
            do_not_after = 1;
        }
        /* The statement of time validity to display */
        else if (Strcmp(*argv, "-validity") == 0)
        {
            do_validity = 1;
        }
        /* The subject name to display */
        else if (Strcmp(*argv, "-subject") == 0)
        {
            do_subject = 1;
        }
        /* The subject name to display in MID format */
        else if (Strcmp(*argv, "-MID_subject") == 0)
        {
            do_MID_subject = 1;
        }
        /* The modulus of the subject public key to display */
        else if (Strcmp(*argv, "-modulus") == 0)
        {
            do_modulus = 1;
        }
        /* The subject public key to display as text */
        else if (Strcmp(*argv, "-pkey_text") == 0)
        {
            do_pkey_text = 1;
        }
        /* The hash of the subject name to display */
        else if (Strcmp(*argv, "-hash") == 0)
        {
            do_hash = 1;
        }
        /* The fingerprint of the certificate (MD5 hash) to display */
        else if (Strcmp(*argv, "-fingerprint") == 0)
        {
            do_fingerprint = 1;
        }
        /* The thumbprint of the certificate (default: SHA1 hash) to display */
        else if (Strcmp(*argv, "-thumbprint") == 0)
        {
            do_thumbprint = 1;
        }
        /* The hashing algorithm used when generating the thumbprint */
        else if (Strcmp(*argv, "-thumbprint_alg") == 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_NID_DIGEST_from_string(str,
                &thumbprint_alg)) != R_ERROR_NONE)
            {
                BIO_printf(bio_err, "Unknown digest: %s\n", str);
                goto bad;
            }
        }
        /* Do not display the certificate on output BIO */
        else if (Strcmp(*argv, "-noout") == 0)
        {
            noout = 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");
    }

    /* Ensure verification is available, if applicable */
    if ((do_verify == 1) && (cafile == NULL))
    {
        badop = 1;
        BIO_printf(bio_err, "No CA file specified for verify\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;
    }

    /* Open the output file (or stdout if none) */
    if (outfile != NULL)
    {
        out = BIO_new_file(outfile, "wb");
        if (out == NULL)
        {
            ret = R_ERROR_ALLOC_FAILURE;
            BIO_printf(bio_err, "Unable to create the output file %s\n", outfile);
            goto end;
        }
    }
    else
    {
        out = bio_out;
    }

    /*
     * 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;
    }

    /*
     * Read the CA certificate into a new certificate object. The CA
     * certificate is optional. It is used to verify the signature
     * of the input certificate.
     */
    if (cafile != NULL)
    {
        /* Open the file */
        ca = BIO_new_file(cafile, "rb");
        if (ca == NULL)
        {
            ret = R_ERROR_NOT_FOUND;
            BIO_printf(bio_err, "Unable to open the CA file %s\n", cafile);
            goto end;
        }

        /* Read the certificate from the stream */
        ret = R_CERT_read(cert_ctx, ca, ca_type, ca_form, &ca_cert);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err, "Unable to load the CA certificate\n");
            goto end;
        }
    }

    /*
     * Find and display the requested certificate information. If printing a
     * WTLS certificate, do not include the steps that retrieve the serial
     * number. Command line options indicate the various certificate fields to
     * extract or calculate, and display. This is commented for each subsection
     * below.
     */

    /* Display the serial number */
    if (do_serial)
    {
        R_ITEM item;

        ret = R_CERT_get_info(cert, R_CERT_INFO_SERIAL_NUMBER, &item);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err,
                "Unable to extract the serial number from the certificate\n");
            goto end;
        }

        BIO_printf(out, "serial=");
        BIO_dump_format(out, item.data, item.len, BIO_DUMP_FORMAT_HEX,
            '\0', 0, 0);
    }

    /* Display the issuer name as a string */
    if (do_issuer)
    {
        static char str[256];   /* The character string */

        ret = R_CERT_issuer_name_to_string(cert, sizeof(str), str);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err,
                "Unable to extract the issuer name from the certificate\n");
            goto end;
        }

        BIO_printf(out, "issuer=%s\n", str);
    }

    /* Display the notBefore time as a string */
    if (do_not_before)
    {
        static char buf[R_CERT_TIME_STRING_LENGTH];  /* The time as a string */

        ret = R_CERT_not_before_to_string(cert, R_CERT_TIME_STRING_LENGTH, buf);

        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err,
                "Unable to extract notBefore time from the certificate\n");
            goto end;
        }
        BIO_printf(out, "notBefore: %s\n", buf);
    }

    /* Display the notAfter time as a string */
    if (do_not_after)
    {
        static char buf[R_CERT_TIME_STRING_LENGTH];  /* The time as a string */

        ret = R_CERT_not_after_to_string(cert, R_CERT_TIME_STRING_LENGTH, buf);

        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err,
                "Unable to extract the notAfter time from the certificate\n ");
            goto end;
        }
        BIO_printf(out, "Not After : %s\n", buf);
    }

    /* Display a statement of time validity */
    if (do_validity)
    {
        int validity; /* The time validity indicator */
        char *str;    /* The character string */

        ret = R_CERT_time_validity(cert, &validity);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err,
                "Unable to determine the time validity of the certificate\n");
            goto end;
        }

        if (validity == R_CERT_TIME_CURRENT)
        {
            str = "Current";
        }
        else if (validity == R_CERT_TIME_NOT_YET_CURRENT)
        {
            str = "Not yet current";
        }
        else
        {
            str = "Expired";
        }

        BIO_printf(out, "Certificate is %s\n", str);
    }

    /* Display the subject name as a string */
    if (do_subject)
    {
        static char str[256];   /* The character string */

        ret = R_CERT_subject_name_to_string(cert, sizeof(str), str);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err,
                "Unable to extract the subject name from the certificate\n");
            goto end;
        }

        BIO_printf(out, "subject=%s\n", str);
    }

    /* Display the subject name as a string in MID format */
    if (do_MID_subject)
    {
        static char str[256];   /* The character string */
        R_CERT_NAME *subject_name;

        /* Ensure that the certificate type is X.509 */
        if (cert_type != R_CERT_TYPE_X509)
        {
            BIO_printf(bio_err,
                "MID subject name format is only available for X.509 certificates\n");
            goto end;
        }

        ret = R_CERT_subject_name_to_R_CERT_NAME(cert, R_FLAG_SHARE_DATA,
                                                 &subject_name);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err,
                "Unable to extract the subject name from the certificate\n");
            goto end;
        }

        ret = R_CERT_NAME_to_MID_string(subject_name, sizeof(str), str);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err,
                "Unable to output the subject name in MID format\n");
            R_CERT_NAME_free(subject_name);
            goto end;
        }

        BIO_printf(out, "MID subject=%s\n", str);
        R_CERT_NAME_free(subject_name);
    }

    /* Display the modulus of the subject public key */
    if (do_modulus)
    {
        if ((ret = display_modulus(bio_err, out, cert)) != R_ERROR_NONE)
        {
            goto end;
        }
    }

    /* Display the subject public key as text */
    if (do_pkey_text)
    {
        if ((ret = display_pkey_text(bio_err, out, cert)) != R_ERROR_NONE)
        {
            goto end;
        }
    }

    /* Display the unique hash value of the subject name */
    if (do_hash)
    {
        if ((ret = display_hash(bio_err, out, cert)) != R_ERROR_NONE)
        {
            goto end;
        }
    }

    /* Verify the signature of the certificate using the CA certificate */
    if (do_verify)
    {
        if ((ret = verify_cert(bio_err, bio_out, ca_cert,
            cert)) != R_ERROR_NONE)
        {
            goto end;
        }
    }

    /* Display the certificate in text format */
    if (do_text)
    {
        ret = R_CERT_write(cert, out, R_FORMAT_TEXT, NULL);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err,
                "Unable to print the text format of the certificate\n");
            goto end;
        }
    }

    /* Display the certificate in C code format */
    if (do_c)
    {
        ret = R_CERT_write(cert, out, R_FORMAT_CODE_FIELDS, NULL);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err,
                "Unable to print the code format of the certificate\n");
            goto end;
        }
    }

#ifndef NO_CFUNC
    /* Display the certificate in C code fields format */
    if (do_cf)
    {
        ret = R_CERT_write(cert, out, R_FORMAT_CODE_BINARY, NULL);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err,
                "Unable to print the code fields format of the certificate\n");
            goto end;
        }
    }
#endif /* !NO_CFUNC */

    /* Display the certificate in plain hexadecimal Bytes format */
    if (do_hex)
    {
        ret = R_CERT_write(cert, out, R_FORMAT_HEX, NULL);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err, "Unable to display the hexadecimal format"
                " of the certificate\n");
            goto end;
        }
    }

    /* Display the certificate in a C code data format */
    if (do_codehex)
    {
        ret = R_CERT_write(cert, out, R_FORMAT_CODE_HEX, NULL);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err,
                "Unable to print the hexadecimal format of the certificate\n");
            goto end;
        }
    }

    /* Calculate and display the fingerprint of the certificate */
    if (do_fingerprint)
    {
        if ((ret = display_fingerprint(bio_err, out, cert)) != R_ERROR_NONE)
        {
            goto end;
        }
    }

    /* Calculate and display the thumbprint of the certificate */
    if (do_thumbprint)
    {
        if ((ret = display_thumbprint(bio_err, out, cert,
            thumbprint_alg)) != R_ERROR_NONE)
        {
            goto end;
        }
    }


    /* Output the certificate unless explicitly told otherwise and if not in
     * binary format */
    if ((noout == 0) && (out_cert_form != R_FORMAT_BINARY))
    {
        ret = R_CERT_write(cert, out, out_cert_form, format_arg);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err,
                "Unable to write out the certificate\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_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));
    }

    if (cert != NULL)
    {
        R_CERT_free(cert);
    }
    if (ca_cert != NULL)
    {
        R_CERT_free(ca_cert);
    }
    if (cert_ctx != NULL)
    {
        R_CERT_CTX_free(cert_ctx);
    }
    if (in != NULL)
    {
        BIO_free(in);
    }
    if ((out != NULL) && (out!=bio_out))
    {
        BIO_free(out);
    }
    if (ca != NULL)
    {
        BIO_free(ca);
    }
    if (lib_ctx != NULL)
    {
        PRODUCT_LIBRARY_FREE(lib_ctx);
    }
    if (bio_err != NULL)
    {
        BIO_free(bio_err);
    }
    if (bio_out != NULL)
    {
        BIO_free(bio_out);
    }

    return(R_ERROR_EXIT_CODE(ret));
}

/*
 * Displays the public modulus of the RSA key from a supplied certificate.
 *
 * @param bio_err [In] The BIO for the error messages.
 * @param out     [In] The output stream for the modulus data.
 * @param cert    [In] The certificate containing the modulus to display.
 *
 * @returns R_ERROR_NONE indicates success.
 *          See @ref R_ERROR_IDS for valid values.
 */
static int display_modulus(BIO *bio_err, BIO *out, R_CERT *cert)
{
    int ret = R_ERROR_NONE;
    R_PKEY *pkey = NULL;    /* The public key object */
    R_ITEM item;            /* An item of data */
    unsigned char *p;       /* A pointer into the item data */
    int len;                /* The length of the modulus data */


    ret = R_CERT_public_key_to_R_PKEY(cert, R_FLAG_SHARE_DATA, &pkey);
    if (ret != R_ERROR_NONE)
    {
        BIO_printf(bio_err,
            "Unable to obtain the public key object from the certificate\n");
        goto end;
    }

    ret = R_PKEY_get_info(pkey, R_PKEY_INFO_ID_RSA_MOD, (void *)&item);
    if (ret != R_ERROR_NONE)
    {
        BIO_printf(bio_err,
            "Unable to obtain public key object from the certificate\n");
        goto end;
    }

    /* Remove the leading zeros */
    p = item.data;
    len = item.len;
    while ((*p) == 0)
    {
        p++;
        len--;
    }

    BIO_printf(out, "Modulus=");
    BIO_dump_format(out, p, len, BIO_DUMP_FORMAT_HEX, '\0', 0, 0);

end:
    if (pkey != NULL)
    {
        R_PKEY_free(pkey);
    }

    return(ret);
}

/*
 * Displays the public key information from a supplied certificate.
 *
 * @param bio_err [In] The BIO for the error messages.
 * @param out     [In] The output stream for the public key data.
 * @param cert    [In] The certificate containing the public key to display.
 *
 * @returns R_ERROR_NONE indicates success.
 *          See @ref R_ERROR_IDS for valid values.
 */
static int display_pkey_text(BIO *bio_err, BIO *out, R_CERT *cert)
{
    int ret = R_ERROR_NONE;
    R_PKEY *pkey = NULL;    /* The public key object */

    ret = R_CERT_public_key_to_R_PKEY(cert, R_FLAG_SHARE_DATA, &pkey);
    if (ret != R_ERROR_NONE)
    {
        BIO_printf(bio_err,
            "Unable to obtain the public key object from the certificate\n");
        goto end;
    }

    ret = R_PKEY_print(out, pkey, R_FORMAT_TEXT, NULL);
    if (ret != R_ERROR_NONE)
    {
        BIO_printf(bio_err,
            "Unable to print public key object from the certificate\n");
        goto end;
    }

end:
    if (pkey != NULL)
    {
        R_PKEY_free(pkey);
    }

    return(ret);
}

/*
 * Displays the hash information from a supplied certificate.
 *
 * @param bio_err [In] The BIO for the error messages.
 * @param out     [In] The output stream for the hash data.
 * @param cert    [In] The certificate containing the hash to display.
 *
 * @returns R_ERROR_NONE indicates success.
 *          See @ref R_ERROR_IDS for valid values.
 */
static int display_hash(BIO *bio_err, BIO *out, R_CERT *cert)
{
    int ret = R_ERROR_NONE;
    R_CERT_NAME *subject = NULL;    /* The subject name object */
    unsigned long hash;             /* The hash value */

    ret = R_CERT_subject_name_to_R_CERT_NAME(cert,
        R_FLAG_SHARE_DATA, &subject);
    if (ret != R_ERROR_NONE)
    {
        BIO_printf(bio_err,
            "Unable to obtain subject name object from certificate\n");
        goto end;
    }

    ret = R_CERT_NAME_get_info(subject, R_CERT_NAME_INFO_HASH, &hash);
    if (ret != R_ERROR_NONE)
    {
        BIO_printf(bio_err, "Unable to hash subject name object\n");
        goto end;
    }

    BIO_printf(out, "%08lx\n", hash);

end:
    if (subject != NULL)
    {
        /* The R_CERT_NAME data is referenced. Free the structure. */
        R_CERT_NAME_free(subject);
    }

    return(ret);
}

/*
 * Verifies a certificate.
 *
 * @param bio_err [In] The BIO for the error messages.
 * @param out     [In] The BIO for the information messages.
 * @param ca_cert [In] The CA certificate that issued the certificate
 *                     being verified.
 * @param cert    [In] The certificate to verify.
 *
 * @returns R_ERROR_NONE indicates success.
 *          See @ref R_ERROR_IDS for valid values.
 */
static int verify_cert(BIO *bio_err, BIO *bio_out, R_CERT *ca_cert,
    R_CERT *cert)
{
    int ret = R_ERROR_NONE;
    int verified;           /* The signature verification status */
    R_PKEY *pkey = NULL;    /* The public key object */

    ret = R_CERT_public_key_to_R_PKEY(ca_cert, R_FLAG_SHARE_DATA, &pkey);
    if (ret != R_ERROR_NONE)
    {
        BIO_printf(bio_err,
            "Unable to extract public key from the CA certificate\n");
        goto end;
    }

    if ((ret = R_CERT_verify(cert, pkey, &verified)) != R_ERROR_NONE)
    {
        BIO_printf(bio_err, "R_CERT_verify failure\n");
        goto end;
    }

    if (!verified)
    {
        ret = R_ERROR_FAILED;
        BIO_printf(bio_out, "The certificate verification failed\n");
    }
    else
    {
        BIO_printf(bio_out, "The certificate verification was successful\n");
    }

end:
    if (pkey != NULL)
    {
        R_PKEY_free(pkey);
    }

    return(ret);
}

/*
 * Displays the fingerprint information from a supplied certificate.
 *
 * @param bio_err [In] The BIO for the error messages.
 * @param out     [In] The output stream for the fingerprint data.
 * @param cert    [In] The certificate containing the fingerprint to display.
 *
 * @returns R_ERROR_NONE indicates success.
 *          See @ref R_ERROR_IDS for valid values.
 */
static int display_fingerprint(BIO *bio_err, BIO *out, R_CERT *cert)
{
    int ret = R_ERROR_NONE;
    unsigned char *buf = NULL;   /* The data buffer */
    unsigned int blen;           /* The length of the data buffer */
    int i;                       /* The iterator over Bytes in the data
                                  * buffer */

    R_CERT_fingerprint(cert, R_CR_ID_MD5, 0, NULL, &blen);
    if (ret != R_ERROR_NONE)
    {
        BIO_printf(bio_err,
            "Unable to calculate length of the fingerprint of the"
            " certificate\n");
        goto end;
    }

    if ((buf = (unsigned char *)Malloc(blen)) == NULL)
    {
        BIO_printf(bio_err,
            "Unable to allocate memory for the fingerprint result\n");
        ret = R_ERROR_ALLOC_FAILURE;
        goto end;
    }

    ret = R_CERT_fingerprint(cert, R_CR_ID_MD5, blen, buf, &blen);
    if (ret != R_ERROR_NONE)
    {
        BIO_printf(bio_err,
            "Unable to calculate the fingerprint of the certificate\n");
        goto end;
    }

    BIO_printf(out, "MD5 fingerprint=");
    for (i = 0; i < (int)(blen); i++)
    {
        BIO_printf(out, "%02X%c", buf[i],
            (i+1 == (int)(blen))?('\n'):(':'));
    }

end:
    if (buf != NULL)
    {
        Free(buf);
    }

    return(ret);
}

/*
 * Calculates the thumbprint information from a supplied certificate.
 *
 * @param bio_err        [In] The BIO for the error messages.
 * @param out            [In] The output stream for the thumbprint data.
 * @param cert           [In] The certificate containing the thumbprint
 *                            to display.
 * @param thumbprint_alg [In] The thumbprint algorithm to use.
 *
 * @returns R_ERROR_NONE indicates success.
 *          See @ref R_ERROR_IDS for valid values.
 */
static int display_thumbprint(BIO *bio_err, BIO *out, R_CERT *cert,
    R_CR_ALG_ID thumbprint_alg)
{
    int ret = R_ERROR_NONE;
    unsigned char *buf = NULL;   /* The data buffer */
    unsigned int blen;           /* The length of the data buffer */
    int i;                       /* The iterator over Bytes in the data
                                  * buffer */
    char *s[10];

    ret = R_CERT_fingerprint(cert, thumbprint_alg, 0, NULL, &blen);
    if (ret != R_ERROR_NONE)
    {
        BIO_printf(bio_err,
            "Unable to calculate the length of the thumbprint of the"
            " certificate\n");
        goto end;
    }

    if ((buf = (unsigned char *)Malloc(blen)) == NULL)
    {
        BIO_printf(bio_err,
            "Unable to allocate memory for the fingerprint result\n");
        ret = R_ERROR_ALLOC_FAILURE;
        goto end;
    }

    ret = R_CERT_fingerprint(cert, thumbprint_alg, blen, buf, &blen);
    if (ret != R_ERROR_NONE)
    {
        BIO_printf(bio_err,
            "Unable to calculate the thumbprint of the certificate\n");
        goto end;
    }

    if ((ret = R_NID_DIGEST_to_string(thumbprint_alg, sizeof(s),
        (char *)s)) != R_ERROR_NONE)
    {
        goto end;
    }

    BIO_printf(out, "Thumbprint Algorithm=%s", s);
    BIO_printf(out, "\nThumbprint=");

    for (i = 0; i < (int)(blen); i += 2)
    {
        BIO_printf(out, "%02X%02X%c", buf[i], buf[i+1],
            (i+2 == (int)(blen))?('\n'):(' '));
    }

end:

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

    return(ret);
}

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