RSA BSAFE Micro Edition Suite

Streamlined security for mobile and embedded devices

Search  Print

reqgen.c

/* $Id: reqgen.c,v 1.63 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"

/* The callback function called when the public key operation surrenders */
static int kg_surrender(R_SURRENDER * ctx, int p, int n);
/* The function to create a subject name string */
static int get_subject_name_string(BIO *bio_err, unsigned int max_str_len,
    char *str, int no_in);

/* The size of the issuer name string to hold the user input */
#define NAME_STR_LEN                   512
/* The length of the input string for reading in a name entry value */
#define NAME_INPUT_STR_LENGTH   80

/* The number of items in the name to be created from user input */
#define NAME_REQ_NUM            5

/*
 * The mapping of long name version strings of the name item identifier to
 * the default value
 */
static char *name_req[NAME_REQ_NUM*3] =
{
    LN_commonName,              SN_commonName,              "User One",
    LN_organizationName,        SN_organizationName,        "RSA Security",
    LN_localityName,            SN_localityName,            "Brisbane",
    LN_stateOrProvinceName,     SN_stateOrProvinceName,     "Qld",
    LN_countryName,             SN_countryName,             "AU",
};

/* The usage help message */
static char *reqgen_usage[] =
{
    "usage: reqgen [options]\n",
    "where options are:\n",
    " -out arg         - The certificate request file name to write\n",
#ifndef NO_PEM
    " -outform arg     - The output format - one of BIN PEM",
    " (default is PEM)\n",
#else /* !NO_PEM */
    " -outform arg     - The output format (BIN only)\n",
#endif /* !NO_PEM */
    " -signkey arg     - The file name of private key to sign request with\n",
#ifndef NO_PEM
    " -signkeyform arg - The format of key - one of BIN PEM",
    " (default is PEM)\n",
#else /* !NO_PEM */
    " -signkeyform arg - The format of key (BIN only)\n",
#endif /* !NO_PEM */
#ifndef NO_DSA
    " -signkeytype arg - The type of key - one of RSA DSA (default is RSA)\n",
#else /* NO_DSA */
    " -signkeytype arg - The type of key - one of RSA (default is RSA)\n",
#endif /* !NO_DSA */
#ifndef NO_DSA
    " -sign_type arg   - The signature type to use - one of:\n",
    "                    RSA_MD2 RSA_MD5 RSA_SHA1 DSA_SHA1",
    " (default is RSA_SHA1)\n",
#else /* NO_DSA */
    " -sign_type arg   - The signature type to use - one of:\n",
    "                    RSA_MD2 RSA_MD5 RSA_SHA1 (default is RSA_SHA1)\n",
#endif /* !NO_DSA */
    " -inkey arg       - The public key file name to read\n",
    " -outkey arg      - The public key file name to write\n",
#ifndef NO_PEM
    " -keyform arg     - The format of key - one of BIN PEM",
    " (default is PEM)\n",
#else /* !NO_PEM */
    " -keyform arg     - The format of key (BIN only)\n",
#endif /* !NO_PEM */
#ifndef NO_DSA
    " -keytype arg     - The type of key - one of RSA DSA (default is RSA)\n",
#else /* NO_DSA */
    " -keytype arg     - The type of key - one of RSA (default is RSA)\n",
#endif /* !NO_DSA */
    " -keysize arg     - The key length in bits (default is 1024)\n",
    " -numprimes arg   - The number of primes used when generating a key",
    " (default is 2)\n",
    " -cert arg        - The name of certificate file\n",
#ifndef NO_PEM
    " -certform arg    - The format of certificate - one of BIN PEM",
    " (default is PEM)\n",
#else /* !NO_PEM */
    " -certform arg    - The format of certificate (BIN only)\n",
#endif /* !NO_PEM */
    " -certtype arg    - The type of certificate - one of X509",
    " (default is X509)\n",
    " -no_in           - Indicates that no input is required for the",
    " creation of the name\n",
    " -eg              - The example usage\n",
    NULL
};

static char *reqgen_example_usage[] =
{
    "Generates a certificate request and key pair\n",
    "reqgen -out req.out -signkey signer.key -outkey key.out\n",
    "\n",
    "Generates  a certificate request using an existing key pair and",
    " certificate\n",
    "reqgen -out req.out -signkey signer.key -inkey key.in -cert cert.in\n",
    "\n",
    "Generates a certificate request using internal data for subject",
    " name etc\n",
    "reqgen -out req.out -signkey signer.key -outkey key.out -no_in\n",
    "\n",
    "where req.out    = The certificate request created\n",
    "      signer.key = The private key of the cert. req. signer\n",
    "      key.out    = The generated key pair\n",
    "      key.in     = An existing key pair used for the request\n",
    "      cert.in    = The existing certificate - details are used for",
    " the request\n",
    "\n",
    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)
{
    int ret = R_ERROR_NONE;         /* The return value */
    BIO *bio_err = NULL;            /* The standard error stream */
    BIO *bio_out = NULL;            /* The standard output stream */
    BIO *bio_key = NULL;            /* The public key output stream */
    BIO *bio_req = NULL;            /* The certificate request output stream */
    R_LIB_CTX *lib_ctx = NULL;      /* The library context */
    R_CERT_REQ_CTX *req_ctx = NULL; /* The certificate request context */
    R_CERT_REQ *req = NULL;         /* The certificate request */
    R_CERT_CTX *cert_ctx = NULL;    /* The certificate context */
    R_CERT *cert = NULL;            /* The certificate */
    R_CERT_NAME *name = NULL;       /* The certificate name */
    R_PKEY_CTX *pkey_ctx = NULL;    /* The public key context */
    R_PKEY *pkey = NULL;            /* The public key */
    R_PKEY *sign_key = NULL;        /* The signing key - public key */
    R_PKEY *s_pkey = NULL;          /* The public key used */
    R_SURRENDER *surr = NULL;       /* The surrender function when generating
                                     * key */
    unsigned char *buf = NULL;      /* The data buffer */
    R_FORMAT req_form;              /* The format of the certificate request */
    int key_bits;                   /* The number of bits in the new key */
    int key_mod;                    /* The modifying parameter in the new
                                     * key */
    int key_type;                   /* The type of public key */
    R_FORMAT key_form;              /* The format of public key */
    int sign_key_type;              /* The type of signing key */
    R_FORMAT sign_key_form;         /* The format of the  signing key */
    int sign_type;                  /* The signature type */
    int cert_type;                  /* The type of certificate */
    R_FORMAT cert_form;             /* The format of the certificate */
    char *inpkeyfile = NULL;        /* The input public key file name */
    char *signpkeyfile = NULL;      /* The signing public key file name */
    char *outpkeyfile = NULL;       /* The output file name of public key */
    char *certfile = NULL;          /* The certificate file name */
    char *reqfile = NULL;           /* The certificate request file name */
    int no_in = 0;                  /* Indicates that no input from the user
                                     * required */
    int version = 1;                /* The version of the certificate
                                     * request */
    char name_str[NAME_STR_LEN];    /* The certificate name as a string */
    int badop = 0;                  /* Indicates a bad command line option */
    char *str;                      /* The character string */
    int key_usage = R_CERT_KEY_USAGE_DIGITAL_SIGNATURE |
                    R_CERT_KEY_USAGE_NON_REPUDIATION |
                    R_CERT_KEY_USAGE_KEY_ENCIPHERMENT |
                    R_CERT_KEY_USAGE_DATA_ENCIPHERMENT |
                    R_CERT_KEY_USAGE_KEY_AGREEMENT |
                    R_CERT_KEY_USAGE_KEY_CERT_SIGN |
                    R_CERT_KEY_USAGE_CRL_SIGN |
                    R_CERT_KEY_USAGE_ENCIPHER_ONLY |
                    R_CERT_KEY_USAGE_DECIPHER_ONLY;

    /* Set the defaults */
#ifndef NO_PEM
    req_form = R_FORMAT_PEM;
#else /* NO_PEM */
    req_form = R_FORMAT_BINARY;
#endif /* !NO_PEM */
    key_bits = 1024;
    key_mod = 2;
    key_type = R_PKEY_TYPE_RSA;
    sign_key_type = R_PKEY_TYPE_RSA;
#ifndef NO_PEM
    key_form = R_FORMAT_PEM;
    sign_key_form = R_FORMAT_PEM;
#else /* NO_PEM */
    key_form = R_FORMAT_BINARY;
    sign_key_form = R_FORMAT_BINARY;
#endif /* !NO_PEM */
    sign_type = R_CR_ID_SHA1_RSA;
    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 */

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

    /* Parse the command line parameters */

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

    /* Process all command line options */
    while (argc >= 1)
    {
        if (Strcmp(*argv, "-out") == 0)
        {
            if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0))
            {
                goto bad;
            }
            reqfile = *argv;
        }
        else if (Strcmp(*argv, "-outform") == 0)
        {
            if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0))
            {
                goto bad;
            }
            str = *argv;
            if ((ret = R_FORMAT_from_string(str, &req_form)) != R_ERROR_NONE)
            {
                BIO_printf(bio_err, "Unknown request format: %s\n", str);
                goto bad;
            }
        }
        else if (Strcmp(*argv, "-sign_type") == 0)
        {
            if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0))
            {
                goto bad;
            }
            str = *argv;
            if (Strcmp(str, "RSA_MD2") == 0)
            {
                sign_type = R_CR_ID_MD2_RSA;
            }
            else if (Strcmp(str, "RSA_MD5") == 0)
            {
                sign_type = R_CR_ID_MD5_RSA;
            }
            else if (Strcmp(str, "RSA_SHA1") == 0)
            {
                sign_type = R_CR_ID_SHA1_RSA;
            }
#ifndef NO_DSA
            else if (Strcmp(str, "DSA_SHA1") == 0)
            {
                sign_type = R_CR_ID_SHA1_DSA;
            }
#endif /* NO_DSA */
            else
            {
                BIO_printf(bio_err, "Unknown signature type type\n");
                goto bad;
            }
        }
        else if (Strcmp(*argv, "-inkey") == 0)
        {
            if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0))
            {
                goto bad;
            }
            inpkeyfile = *argv;
        }
        else if (Strcmp(*argv, "-signkey") == 0)
        {
            if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0))
            {
                goto bad;
            }
            signpkeyfile = *argv;
        }
        else if (Strcmp(*argv, "-signkeyform") == 0)
        {
            if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0))
            {
                goto bad;
            }
            str = *argv;
            if (R_FORMAT_from_string(str, &sign_key_form) != R_ERROR_NONE)
            {
                BIO_printf(bio_err, "Unknown pkey format: %s\n", str);
                goto bad;
            }
        }
        else if (Strcmp(*argv, "-signkeytype") == 0)
        {
            if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0))
            {
                goto bad;
            }
            str = *argv;
            if (R_PKEY_TYPE_from_string(&sign_key_type, str) != R_ERROR_NONE)
            {
                goto bad;
            }
            if (key_type == R_PKEY_TYPE_UNKNOWN)
            {
                BIO_printf(bio_err, "Unknown pkey type: %s\n", str);
                goto bad;
            }
        }
        else if (Strcmp(*argv, "-outkey") == 0)
        {
            if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0))
            {
                goto bad;
            }
            outpkeyfile = *argv;
        }
        else if (Strcmp(*argv, "-keyform") == 0)
        {
            if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0))
            {
                goto bad;
            }
            str = *argv;
            if (R_FORMAT_from_string(str, &key_form) != R_ERROR_NONE)
            {
                BIO_printf(bio_err, "Unknown pkey format: %s\n", str);
                goto bad;
            }
        }
        else if (Strcmp(*argv, "-keytype") == 0)
        {
            if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0))
            {
                goto bad;
            }
            str = *argv;
            if (R_PKEY_TYPE_from_string(&key_type, str) != R_ERROR_NONE)
            {
                goto bad;
            }
            if (key_type == R_PKEY_TYPE_UNKNOWN)
            {
                BIO_printf(bio_err, "Unknown pkey type: %s\n", str);
                goto bad;
            }
        }
        else if (Strcmp(*argv, "-keysize") == 0)
        {
            if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0))
            {
                goto bad;
            }
            key_bits = atoi(*argv);
        }
        else if (Strcmp(*argv, "-numprimes") == 0)
        {
            if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0))
            {
                goto bad;
            }
            key_mod = atoi(*argv);
        }
        else if (Strcmp(*argv, "-cert") == 0)
        {
            if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0))
            {
                goto bad;
            }
            certfile = *argv;
        }
        else if (Strcmp(*argv, "-certform") == 0)
        {
            if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0))
            {
                goto bad;
            }
            str = *argv;
            if ((ret = R_FORMAT_from_string(str, &cert_form)) != R_ERROR_NONE)
            {
                BIO_printf(bio_err, "Unknown certificate format: %s\n", str);
                goto bad;
            }
        }
        else if (Strcmp(*argv, "-certtype") == 0)
        {
            if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0))
            {
                goto bad;
            }
            str = *argv;
            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;
            }
        }
        else if (Strcmp(*argv, "-no_in") == 0)
        {
            no_in = 1;
        }
        else if (Strcmp(*argv,"-eg") == 0)
        {
            char **egp;
            for (egp = reqgen_example_usage; (*egp) != NULL; egp++)
            {
                BIO_printf(bio_out, *egp);
            }
            goto done;
        }
        else
        {
            BIO_printf(bio_err, "Unknown option %s\n", *argv);
            badop = 1;
            break;
        }
        argc--;
        argv++;
    }

    /* Display the help menu if an invalid command line option was entered */
    if (badop)
    {
        char **pp;

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

    /* Set up the surrender callback structure */
    surr = (R_SURRENDER *)Malloc(sizeof(*surr));
    if (surr == NULL)
    {
        BIO_printf(bio_err, "Failed to allocate the memory for surr\n");
        ret = R_ERROR_ALLOC_FAILURE;
        goto done;
    }
    surr->callback = kg_surrender;
    surr->arg = (char *) bio_err;

    /*
     * Create the library context. Retrieve the default resource list and
     * create a library context to provide access to all configurable aspects
     * of the library.
     */
    if (PRODUCT_LIBRARY_NEW(PRODUCT_DEFAULT_RESOURCE_LIST(), 0,
        &lib_ctx) != R_ERROR_NONE)
    {
        BIO_printf(bio_err, "Unable to create the library context\n");
        ret = R_ERROR_ALLOC_FAILURE;
        goto done;
    }

    /*
     * Create a certificate request context and public key context. These
     * contexts are required if any R_CERT_REQ_* and R_PKEY_* routines
     * are used.
     */
    ret = R_CERT_REQ_CTX_new(lib_ctx, R_RES_FLAG_DEF, R_CERT_REQ_TYPE_PKCS10,
              &req_ctx);

    if (ret != R_ERROR_NONE)
    {
        BIO_printf(bio_err, "Unable to create an R_CERT_REQ_CTX\n");
        goto done;
    }

    ret = R_PKEY_CTX_new(lib_ctx, R_RES_FLAG_DEF, key_type, &pkey_ctx);
    if (ret != R_ERROR_NONE)
    {
        BIO_printf(bio_err, "Unable to create an R_PKEY_CTX\n");
        ret = R_ERROR_ALLOC_FAILURE;
        goto done;
    }

    /* Load the PKEY from file */

    /*
     * Obtain the PKEY. This is the key for the client certificate. If a PKEY
     * is provided then read it into a R_PKEY object.Otherwise generate the
     * key.
     */
    if (inpkeyfile != NULL)
    {
        ret = R_PKEY_from_file(pkey_ctx, &pkey, inpkeyfile, key_type, key_form);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err, "Failed to open the key file: %s\n", inpkeyfile);
            goto done;
        }
    }
    else if (inpkeyfile == NULL)
    {
        ret = R_PKEY_generate_simple(pkey_ctx, &pkey, key_type, key_bits,
            key_mod, R_PKEY_FL_DEFAULT, surr);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err, "Failed to generate the key!\n");
            goto done;
        }
    }

    /*
     * Obtain the signer PKEY. This is the Certification Authority (CA)
     * certificate's key. The CA key is used to sign the request. If no CA key
     * is provided use the client key.
     */
    if (signpkeyfile != NULL)
    {
        ret = R_PKEY_from_file(pkey_ctx, &sign_key, signpkeyfile, sign_key_type,
            sign_key_form);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err, "Failed to open the key file: %s\n",
                                 signpkeyfile);
            goto done;
        }

        s_pkey = sign_key;
    }
    else
    {
        s_pkey = pkey;
    }

    /*
     * Create a certificate request. This involves:
     *    -  Creating a certificate request object (R_CERT_REQ).
     *    -  Gathering the certificate request details and setting them against
     *       the object.
     *    -  Signing the certificate request.
     * There are two options available at this point (outlined below).
     */

    if (certfile == NULL)
    {
        /*
         * Generate the certificate request. No pre-existing certificate on
         * which to base the request exists. The information in the various
         * fields of the certificate request is set against the certificate
         * request object.
         */

        /* Create an empty certificate request */
        ret = R_CERT_REQ_new(req_ctx, R_CERT_REQ_TYPE_PKCS10, &req);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err, "Failed to create the request\n");
            goto done;
        }

        /* Enter the version of the certificate request structure */
        ret = R_CERT_REQ_set_info(req, R_CERT_REQ_INFO_VERSION, &version);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err, "Failed to set the version\n");
            goto done;
        }

        /* Retrieve the subject name as a string */
        ret = get_subject_name_string(bio_err, NAME_STR_LEN, name_str, no_in);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err,
                       "Failed to retrieve the subject name from user\n");
            goto done;
        }

        /* Convert the string into an R_CERT_NAME structure */
        ret = R_CERT_NAME_from_string(req_ctx, name_str, &name);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err, "Failed to create the name from string\n");
            goto done;
        }

        /* Store the subject name */
        ret = R_CERT_REQ_set_info(req, R_CERT_REQ_INFO_SUBJECT_R_CERT_NAME,
            name);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err, "Failed to set the subject name\n");
            goto done;
        }

        /* Enter the public key for the certificate request */
        ret = R_CERT_REQ_set_info(req, R_CERT_REQ_INFO_R_PKEY, pkey);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err, "Failed to set the public key\n");
            goto done;
        }

        ret = R_CERT_REQ_set_info(req, R_CERT_REQ_INFO_KEY_USAGE_INT, 
                                        &key_usage);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err, "Failed to set key usage values\n");
            goto done;
        }

        /* Sign the certificate request */
        ret = R_CERT_REQ_sign(req, s_pkey, sign_type);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err, "Failed to sign the request\n");
            goto done;
        }
    }
    else
    {
        /*
         * Create a certificate request from an existing certificate. Obtain
         * the client certificate information from an existing certificate.
         * The existing certificate is loaded into the application and
         * converted to a request. The information in the various fields of
         * the certificate request is set against the certificate request
         * object.
         */

        /* Create a certificate context from which to base the certificate */
        ret = R_CERT_CTX_new(lib_ctx, R_RES_FLAG_DEF, cert_type, &cert_ctx);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err, "Failed to create an R_CERT_CTX\n");
            goto done;
        }

        /* Create a certificate from the data in the file */
        ret = R_CERT_read_file(cert_ctx, certfile, cert_type, cert_form, &cert);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err, "Unable to load the certificate file: %s\n",
                certfile);
            goto done;
        }

        /* Create a certificate request from a certificate */
        ret = R_CERT_to_R_CERT_REQ(cert, req_ctx, R_CERT_REQ_TYPE_PKCS10, &req);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err,
                       "Failed to generate the request from a certfificate\n");
            goto done;
        }

        /*
         * In the previous step the PKEY from the existing certificate was
         * stored in the new certificate request. However, if a new key was
         * generated earlier (specifically for this certificate request) then
         * store the key in the request.
         */
        if ((inpkeyfile == NULL) ||
            (!R_CERT_is_matching_private_key(cert, pkey)))
        {
            /* Enter the public key for the certificate request */
            ret = R_CERT_REQ_set_info(req, R_CERT_REQ_INFO_R_PKEY, pkey);
            if (ret != R_ERROR_NONE)
            {
                BIO_printf(bio_err, "Failed to set the public key\n");
                goto done;
            }
        }

        /* Sign the certificate request */
        ret = R_CERT_REQ_sign(req, s_pkey, sign_type);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err, "Failed to sign the request\n");
            goto done;
        }
    }

    /* Output the key if requested */

    if (outpkeyfile != NULL)
    {
        /* Create an output stream to write the key to */
        bio_key = BIO_new_file(outpkeyfile, "wb");
        if (bio_key == NULL)
        {
            BIO_printf(bio_err, "Unable to open the file: %s\n", outpkeyfile);
            ret = R_ERROR_ALLOC_FAILURE;
            goto done;
        }

        /* Write the public key to the output stream */
        ret = R_PKEY_to_bio(bio_key, pkey, key_form, NULL);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err, "Failed to write the key\n");
            goto done;
        }
    }

    /*
     * Write the certificate request to file. Open the output stream and print
     * the request into the stream.
     */

    /* Open the certificate request BIO */
    if (reqfile != NULL)
    {
        bio_req = BIO_new_file(reqfile, "wb");
        if (bio_req == NULL)
        {
            BIO_printf(bio_err, "Unable to open the file: %s\n", reqfile);
            ret = R_ERROR_ALLOC_FAILURE;
            goto done;
        }
    }
    else
    {
        bio_req = bio_out;
        bio_out = NULL;
    }

    /* Print the PEM format only to stdout */
    if (!((req_form == R_FORMAT_BINARY) && (reqfile == NULL)))
    {
        ret = R_CERT_REQ_write(req, bio_req, req_form, NULL);
        if (ret != R_ERROR_NONE)
        {
            BIO_printf(bio_err, "Failed to write the request\n");
        }
    }

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

    /* Clean up */
    if (surr != NULL)
    {
        Free(surr);
    }
    if (sign_key != NULL)
    {
        R_PKEY_free(sign_key);
    }
    if (pkey != NULL)
    {
        R_PKEY_free(pkey);
    }
    if (cert != NULL)
    {
        R_CERT_free(cert);
    }
    if (buf != NULL)
    {
        Free(buf);
    }
    if (name != NULL)
    {
        R_CERT_NAME_free(name);
    }
    if (req != NULL)
    {
        R_CERT_REQ_free(req);
    }
    if (cert_ctx != NULL)
    {
        R_CERT_CTX_free(cert_ctx);
    }
    if (pkey_ctx != NULL)
    {
        R_PKEY_CTX_free(pkey_ctx);
    }
    if (req_ctx != NULL)
    {
        R_CERT_REQ_CTX_free(req_ctx);
    }

    if (bio_req != NULL)
    {
        BIO_free(bio_req);
    }
    if (bio_key != NULL)
    {
        BIO_free(bio_key);
    }

    if (lib_ctx != NULL)
    {
        R_LIB_CTX_free(lib_ctx);
    }

    if (bio_out != NULL)
    {
        BIO_free(bio_out);
    }
    if (bio_err != NULL)
    {
        BIO_free(bio_err);
    }

    return(R_ERROR_EXIT_CODE(ret));
}

/*
 * Indicates the public key pair generation surrender callback function.
 *
 * @param  surr [In]  The surrender structure.
 * @param  p    [In]  The phase.
 * @param  n    [In]  The number.
 *
 * @returns  0 indicates success.
 */
static int kg_surrender(R_SURRENDER * surr, int p, int n)
{
    char c = '*';   /* Status character to write out  */

    /* Use a different character for each status */
    if (p == 0)
    {
        c = '.';
    }
    if (p == 1)
    {
        c = '+';
    }
    if (p == 2)
    {
        c = '*';
    }
    if (p == 3)
    {
        c = '\n';
    }

    /*
     * Write out the character and flush to ensure it appears
     * as soon as possible
     */
    BIO_write((BIO *) surr->arg, &c, 1);
    BIO_flush((BIO *) surr->arg);

    /* Continue calculation */
    return (0);
}

/*
 * Obtains the details of the subject name from the user and places it in a
 * string.
 *
 * @param  bio_err     [In]  The BIO for error messages.
 * @param  max_str_len [In]  The amount of memory allocated to string.
 * @param  str         [In]  The subject name.
 * @param  no_in       [In]  The default value.
 *
 * @returns  R_ERROR_NONE indicates success.<br>
 *           See @ref R_ERROR_IDS for valid values.
 */
static int get_subject_name_string(BIO *bio_err, unsigned int max_str_len,
    char *str, int no_in)
{
    int ret = R_ERROR_NONE;                         /* The return value */
    BIO *bio_in = NULL;                             /* The standard input
                                                     * stream */
    MS_STATIC char in_str[NAME_INPUT_STR_LENGTH];   /* The input string */
    int i;                                          /* The iterator over
                                                     * string */
    char *p;                                        /* A pointer into string */

    if ((bio_in = BIO_new_fp(stdin, BIO_NOCLOSE)) == NULL)
    {
        ret = R_ERROR_ALLOC_FAILURE;
        BIO_printf(bio_err, "Failed to open the standard input stream\n");
    }
    else
    {
        /* Ensure the subject name string is empty */
        str[0] = '\0';

        /* Create a subject name string with each of the entries completed */
        for (i=0;i<NAME_REQ_NUM;i++)
        {
            /* Enter the separator between successive entries */
            if (i != 0)
            {
                Strcat(str, ", ");
            }

            /* Enter the long name of the entry type */
            Strcat(str, name_req[i*3+1]);
            Strcat(str, "=");

            p=name_req[i*3+2];
            if (no_in == 0)
            {
                /* Print the prompt */
                BIO_printf(bio_err, "Enter %s [default %s]: ",
                    name_req[i*3], p);

                /* Empty the string and retrieve the user's input */
                in_str[0]=0;
                BIO_gets(bio_in, in_str, sizeof(in_str));

                /* Remove the trailing carriage return(s)/line feed(s) */
                while (in_str[Strlen(in_str)-1] == '\n' ||
                       in_str[Strlen(in_str)-1] == '\r')
                {
                    in_str[Strlen(in_str)-1] = '\0';
                }

                /* Use the entered string if applicable */
                if (in_str[0] != '\0')
                {
                    p=in_str;
                }
            }

            /* Enter the entry value */
            Strcat(str, p);
        }
    }

    if (bio_in != NULL)
    {
        BIO_free(bio_in);
    }

    /* The return error value */
    return(ret);
}



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