| RSA BSAFE Micro Edition Suite |
Streamlined security for mobile and embedded devices |
 
![]() |
/* $Id: req.c,v 1.67 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 function to create an issuer name string */ static int get_issuer_name_string(unsigned int max_str_len, char *str, int no_in); /* The function to create a serial number */ static int get_serial_number(unsigned int max_buf_len, unsigned char *buf, unsigned int *out_len, int no_in); /* The size of the issuer name string to hold user input */ #define NAME_STR_LEN 512 /* The size of the user input for each item of the issuer name */ #define NAME_ITEM_STR_LEN 80 /* The size of the serial number buffer */ #define SERIAL_BUF_LEN 32 /* The size of the input buffer for serial number */ #define SERIAL_INPUT_LEN SERIAL_BUF_LEN * 2 + 1 /* The number of items in the name that is to be created from user input */ #define CERT_NAME_NUM_ITEMS 5 /* * The mapping of long name version strings of the name entry identifier * to default value */ static char *cert_name_items[CERT_NAME_NUM_ITEMS*3] = { LN_commonName, SN_commonName, "Root Cert", LN_organizationName, SN_organizationName, "RSA Security", LN_localityName, SN_localityName, "Brisbane", LN_stateOrProvinceName, SN_stateOrProvinceName, "Qld", LN_countryName, SN_countryName, "AU", }; /* Usage help message */ static char *req_usage[] = { "usage: req [options]\n", "where options are:\n", " -in arg - The certificate request filename to read\n", " -intype arg - The input type - one of PKCS10", " (default is PKCS10)\n", #ifndef NO_PEM " -inform arg - The input format - one of BIN PEM", " (default is PEM)\n", #else /* NO_PEM */ " -inform arg - The input format (BIN only)\n", #endif /* !NO_PEM */ " -out arg - The 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 */ " -text - Prints out text form of request\n", " -C - Prints the request in C format for inclusion in\n", " other code\n", #ifndef NO_CFUNC " -Cf - Prints a function in C that will return the\n", " specified certificate request\n", #endif /* NO_CFUNC */ " -hex - Prints the request in hex format\n", " -codehex - Prints the request in code hex format request\n", " -verify - Verifies signature on request\n", " -key arg - The public key file name to read\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 */ " -keytype arg - The type of key - one of RSA DSA", " (default is RSA)\n", " -CA arg - The name of the Certification Authority (CA)", " certificate file\n", #ifndef NO_PEM " -CAform arg - The format of CA certificate - one of BIN PEM", " (default is PEM)\n", #else /* NO_PEM */ " -CAform arg - The format of CA certificate (BIN only)\n", #endif /* !NO_PEM */ " -CAtype arg - The type of CA certificate - one of X509", " (default is X509)\n", #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 */ " -x509 - Outputs an X.509 certificate instead of a", " certificate request\n", " -days arg - The number of days the certificate is valid for\n", " -utc_notbefore arg - The time at which the certificate becomes valid\n", " -utc_notafter arg - The time at which the certificate expires\n", " -no_in - Indicates that no input is required for the", " creation of the name\n", " -eg - The example usage\n", NULL }; static char *req_example_usage[] = { "Prints out the request in text form\n", "req -in req.in -text\n", "\n", "Verifies the signature of the request\n", "req -in req.in -key signer.key -verify\n", "\n", #ifndef NO_PEM "Converts requests between formats (PEM to BIN)\n", "req -in req.in -inform PEM -out req.bin -outform BIN\n", "\n", #endif /* NO_PEM */ "Creates a certificate from an existing request\n", "req -in req.in -out cert.out -key ca.key -CA ca.cert -x509 -days 200\n", "\n", "where: req.in = existing request\n", " signer.key = key used to sign the request (see reqgen command)\n", " req.bin = same as req.in but in binary format\n", " cert.out = the certificate generated from the request req.in\n", " ca.key = CA's private key - used to sign the created", " certificate\n", " ca.cert = CA's cert - used to retrieve the issuer name etc\n", "\n", NULL }; /* Global variables */ /* Standard error output stream */ BIO *bio_err; /* Standard input stream */ BIO *bio_in; /* * 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_out = NULL; /* The standard output stream */ BIO *bio_req_in = NULL; /* The request data input stream */ BIO *bio_req_out = NULL; /* The request file 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 *ca = NULL; /* The Certification Authority (CA) * certificate */ R_CERT_NAME *name=NULL; /* The issuer name of new certificate */ R_PKEY_CTX *pkey_ctx = NULL; /* The public key context */ R_PKEY *pkey = NULL; /* The public key */ R_TIME_CTX *time_ctx = NULL; /* The time module context */ R_TIME *na_time = NULL; /* The notAfter time */ R_TIME *nb_time = NULL; /* The notBefore time */ int req_type; /* The type of certificate request */ R_FORMAT req_form; /* The format of the certificate request */ R_FORMAT out_form; /* The output format of the certificate * request */ int key_type; /* The type of public key */ R_FORMAT key_form; /* The format of the public key */ int sign_type; /* The signature type with which to sign * the new certificate */ int ca_type; /* The type of CA certificate */ R_FORMAT ca_form; /* The format of the CA certificate */ char *pkeyfile = NULL; /* The public key file name */ char *cafile = NULL; /* The CA certificate file name */ char *reqfile = NULL; /* The certificate request file name */ char *outfile = NULL; /* The output file name */ int text; /* Display the text output of the * request */ int do_c; /* Display the C version */ #ifndef NO_CFUNC int do_cf; /* Display the C code version of the * request */ #endif int do_hex; /* Display the hexadecimal version */ int do_codehex; /* Display the Code version in hexadecimal * format */ int verify; /* Verify the certificate request */ int x509; /* Create an X.509 certificate from the * request */ long days; /* The number of days for which the * certificate will be valid */ int no_in = 0; /* Indicates to not retrieve input * - use defaults */ char *not_after = NULL; /* The notAfter time as a string */ char *not_before = NULL; /* The notBefore time as a string */ unsigned char serial_number[SERIAL_BUF_LEN]; /* The serial number */ char name_str[NAME_STR_LEN]; /* The certificate name as a string */ R_ITEM item; /* The item of data */ int verified; /* The request was verified */ int badop = 0; /* A bad command line option */ char *str; /* A pointer to the character string */ /* Initialize the global variables */ bio_err = NULL; bio_in = NULL; /* Set the defaults */ req_type = R_CERT_REQ_TYPE_PKCS10; #ifndef NO_PEM req_form = R_FORMAT_PEM; out_form = R_FORMAT_PEM; key_form = R_FORMAT_PEM; ca_form = R_FORMAT_PEM; #else /* NO_PEM */ req_form = R_FORMAT_BINARY; out_form = R_FORMAT_BINARY; key_form = R_FORMAT_BINARY; ca_form = R_FORMAT_BINARY; #endif /* !NO_PEM */ key_type = R_PKEY_TYPE_RSA; sign_type = R_CR_ID_SHA1_RSA; ca_type = R_CERT_TYPE_X509; text = 0; do_c = 0; #ifndef NO_CFUNC do_cf = 0; #endif do_hex = 0; do_codehex = 0; verify = 0; x509 = 0; days = 30; /* * 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; } /* Create the input channel */ bio_in = BIO_new_fp(stdin, BIO_NOCLOSE); if (bio_in == 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, "-in") == 0) { if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0)) { goto bad; } reqfile = *argv; } else if (Strcmp(*argv, "-intype") == 0) { if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0)) { goto bad; } str = *argv; if ((ret = R_CERT_REQ_TYPE_from_string(str, &req_type)) != R_ERROR_NONE) { BIO_printf(bio_err, "Unknown request type %s\n", str); goto bad; } } else if (Strcmp(*argv, "-inform") == 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, "-out") == 0) { if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0)) { goto bad; } outfile = *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, &out_form)) != R_ERROR_NONE) { BIO_printf(bio_err, "Unknown output format %s\n", str); goto bad; } } else if (Strcmp(*argv, "-text") == 0) { text = 1; } /* C code version to display */ else if (Strcmp(*argv, "-C") == 0) { do_c = 1; } #ifndef NO_CFUNC /* 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; } /* C code version in hexadecimal to display */ else if (Strcmp(*argv, "-codehex") == 0) { do_codehex = 1; } else if (Strcmp(*argv, "-verify") == 0) { verify = 1; } else if (Strcmp(*argv, "-key") == 0) { if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0)) { goto bad; } pkeyfile = *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); ret = R_ERROR_FAILED; goto done; } } 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, "-CA") == 0) { if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0)) { goto bad; } cafile = *argv; } else if (Strcmp(*argv, "-CAform") == 0) { if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0)) { goto bad; } str = *argv; if ((ret = R_FORMAT_from_string(str, &ca_form)) != R_ERROR_NONE) { BIO_printf(bio_err, "Unknown cert format %s\n", str); goto bad; } } else if (Strcmp(*argv, "-CAtype") == 0) { if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0)) { goto bad; } str = *argv; if ((ret = R_CERT_TYPE_from_string(str, &ca_type)) != R_ERROR_NONE) { BIO_printf(bio_err, "Unknown cert type %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 else { BIO_printf(bio_err, "Unknown signature type %s\n", str); goto bad; } } else if (Strcmp(*argv, "-x509") == 0) { x509 = 1; } else if (Strcmp(*argv, "-days") == 0) { if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0)) { goto bad; } str = *argv; days = atoi(str); if (days < 0) { BIO_printf(bio_err, "Days cannot be negative: %d\n", days); goto bad; } } else if (Strcmp(*argv, "-utc_notafter") == 0) { if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0)) { goto bad; } not_after = *argv; } else if (Strcmp(*argv, "-utc_notBefore") == 0) { if ((--argc < 1) || (Strncmp(*(++argv), "-", 1) == 0)) { goto bad; } not_before = *argv; } else if (Strcmp(*argv, "-no_in") == 0) { no_in = 1; } else if (Strcmp(*argv,"-eg") == 0) { char **egp; for (egp = req_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++; } /* Perform simple checks */ if ((x509 == 1) && (pkeyfile == NULL)) { BIO_printf(bio_err, "When issuing a certificate a signing key is required\n"); badop = 1; } /* Display help menu if an invalid command line option was entered */ if (badop) { char **pp; bad: ; for (pp = req_usage; (*pp != NULL); pp++) { BIO_printf(bio_err, *pp); } goto done; } /* * 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 ((ret = PRODUCT_LIBRARY_NEW(PRODUCT_DEFAULT_RESOURCE_LIST(), 0, &lib_ctx)) != R_ERROR_NONE) { BIO_printf(bio_err, "Unable to create the library context\n"); goto done; } /* * Create a certificate request context. The context is required if any * R_CERT_REQ_* 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; } /* Open the input file */ if (reqfile == NULL) { /* No certificate request file specified */ BIO_printf(bio_err, "No input file specified\n"); goto done; } else { /* Open the request file */ bio_req_in = BIO_new_file(reqfile, "rb"); } if (bio_req_in == NULL) { ret = R_ERROR_NOT_FOUND; BIO_printf(bio_err, "Unable to open the input file %s\n", reqfile); goto done; } /* * Read the certificate request from the input file into a new certificate * object. The certificate request object (R_CERT_REQ) stores all the * certificate request information. */ ret = R_CERT_REQ_read(req_ctx, bio_req_in, req_type, req_form, &req); if (ret != R_ERROR_NONE) { BIO_printf(bio_err, "Failed to read the request\n"); goto done; } /* * Read the signer's PKEY from file. The signer's key is used to sign the * certificate request. If a certificate request is not being generated * then no key is supplied. */ if (pkeyfile != NULL) { /* Create a public key context in order to create the public key */ 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"); goto done; } /* Create a public key from the data in the file */ ret = R_PKEY_from_file(pkey_ctx, &pkey, pkeyfile, key_type, key_form); if (ret != R_ERROR_NONE) { BIO_printf(bio_err, "Failed to open the key file: %s\n", pkeyfile); goto done; } } /* * Create a certificate context and load the Certification Authority (CA) * certificate (in the case of generating a certificate) */ if ((cafile != NULL) || (x509 == 1)) { ret = R_CERT_CTX_new(lib_ctx, R_RES_FLAG_DEF, ca_type, &cert_ctx); if (ret != R_ERROR_NONE) { BIO_printf(bio_err, "Unable to create an R_CERT_CTX\n"); goto done; } } /* Read the CA certificate from file */ if (cafile != NULL) { ret = R_CERT_read_file(cert_ctx, cafile, ca_type, ca_form, &ca); if (ret != R_ERROR_NONE) { BIO_printf(bio_err, "Unable to read the CA certificate file: %s\n", cafile); goto done; } } /* * Verify the certificate request signature, if requested. The signer's key * is required to verify the signature. This key is either provided as a * command line argument or in the case of a self-signed request the key is * obtained from the request itself. */ if (verify == 1) { /* * Retrieve the key from the certificate request if none are loaded. * This is the self signed case . */ if (pkey == NULL) { ret = R_CERT_REQ_public_key_to_R_PKEY(req, R_FLAG_SHARE_DATA, &pkey); if (ret != R_ERROR_NONE) { BIO_printf(bio_err, "Unable to extract the key from the request\n"); goto done; } } /* * Perform the verification. The return value will be an error code on * failure. */ ret = R_CERT_REQ_verify(req, pkey, &verified); if (ret != R_ERROR_NONE) { BIO_printf(bio_err, "R_CERT_REQ_verify failure\n"); goto done; } else if (verified == 1) { BIO_printf(bio_err, "verify OK\n"); } else { BIO_printf(bio_err, "The certificate request verification" " failed\n"); goto done; } } /* * Issue a certificate from the request if requested. This requires the * following steps: * - Obtain all the time information. * - Create the certificate object based on an original request. This * provides some of the information for the certificate. * - Obtain the remaining information and set it against the * certificate object. * - Sign the certificate. * If generating a WTLS certificate, do not include the steps that set * the serial number. */ if (x509 == 1) { /* Create the time context */ ret = R_TIME_CTX_new(lib_ctx, R_RES_FLAG_DEF, &time_ctx); if (ret != R_ERROR_NONE) { BIO_printf(bio_err, "Unable to create an R_TIME_CTX\n"); goto done; } /* Create the notBefore time object */ ret = R_TIME_new(time_ctx, &nb_time); if (ret != R_ERROR_NONE) { BIO_printf(bio_err, "Unable to create the time object\n"); goto done; } if (not_before == NULL) { /* Retrieve the current time */ ret = R_TIME_time(nb_time); if (ret != R_ERROR_NONE) { BIO_printf(bio_err, "Unable to retrieve the current time\n"); goto done; } } else { /* Import the Universal Time, Coordinated (UTC) notBefore time */ ret = R_TIME_import(nb_time, R_TIME_EXTERNAL_FORMAT_UTC, (unsigned char *)not_before, Strlen(not_before)); if (ret != R_ERROR_NONE) { BIO_printf(bio_err, "Unable to import the notBefore time\n"); goto done; } } /* Copy the notBefore time */ ret = R_TIME_dup(nb_time, &na_time); if (ret != R_ERROR_NONE) { BIO_printf(bio_err, "Unable to create the time object\n"); goto done; } if (not_after == NULL) { /* Adjust the notAfter time by the number of days */ ret = R_TIME_offset(na_time, na_time, 60*60*24*days); if (ret != R_ERROR_NONE) { BIO_printf(bio_err, "Unable to offset the time\n"); goto done; } } else { /* Import the Universal Time, Coordinated (UTC) notAFter time */ ret = R_TIME_import(na_time, R_TIME_EXTERNAL_FORMAT_UTC, (unsigned char *) not_after, Strlen(not_after)); if (ret != R_ERROR_NONE) { BIO_printf(bio_err, "Unable to import the notAfter time\n"); goto done; } } /* * Issue a new certificate. The certificate request contains the * subject name and public key. This information can be entered * directly into the certificate. Before signing, the serial number, * issuer name and validity times are added to complete the * certificate. */ /* Create a certificate based on the information in the request */ ret = R_CERT_REQ_to_R_CERT(req, cert_ctx, ca_type, &cert); if (ret != R_ERROR_NONE) { BIO_printf(bio_err, "Failed to create the certificate from the request\n"); goto done; } /* Retrieve the serial number from use */ ret = get_serial_number(SERIAL_BUF_LEN, serial_number, &item.len, no_in); if (ret != R_ERROR_NONE) { BIO_printf(bio_err, "Failed to retrieve the serial number\n"); goto done; } item.data = serial_number; /* Store the serial number in the certificate */ ret = R_CERT_set_info(cert, R_CERT_INFO_SERIAL_NUMBER, &item); if (ret != R_ERROR_NONE) { BIO_printf(bio_err, "Failed to set the certificate" " serial number\n"); goto done; } /* Use the subject name from a CA certificate as the issuer */ if (cafile != NULL) { ret = R_CERT_subject_name_to_R_CERT_NAME(ca, R_FLAG_SHARE_DATA, &name); if (ret != R_ERROR_NONE) { BIO_printf(bio_err, "Failed to retrieve the subject name from a CA cert\n"); goto done; } } /* Retrieve the issuer name from the user */ else { /* Retrieve the issuer name as a string */ ret = get_issuer_name_string(NAME_STR_LEN, name_str, no_in); if (ret != R_ERROR_NONE) { BIO_printf(bio_err, "Failed to obtain issuer name from" " user\n"); goto done; } /* Convert the string into an R_CERT_NAME structure */ ret = R_CERT_NAME_from_string(cert_ctx, name_str, &name); if (ret != R_ERROR_NONE) { BIO_printf(bio_err, "Failed to convert the string to a" " name\n"); goto done; } } /* Store the issuer name */ ret = R_CERT_set_info(cert, R_CERT_INFO_ISSUER_R_CERT_NAME, name); if (ret != R_ERROR_NONE) { BIO_printf(bio_err, "Failed to set the issuer name to the" " certificate\n"); goto done; } /* Store the notBefore validity time as a UTC string */ ret = R_CERT_not_before_from_R_TIME(cert, nb_time); if (ret != R_ERROR_NONE) { BIO_printf(bio_err, "Failed to set the notBefore time to the certificate\n"); goto done; } /* Store the notAfter validity time as a UTC string */ ret = R_CERT_not_after_from_R_TIME(cert, na_time); if (ret != R_ERROR_NONE) { BIO_printf(bio_err, "Failed to set the notAfter time to the certificate\n"); goto done; } /* * Sign the certificate. All the certificate information is now in the * certificate object. Sign the certificate information with the * private key (pkey) using the specified signature algorithm * (sign_type). */ ret = R_CERT_sign(cert, pkey, sign_type); if (ret != R_ERROR_NONE) { BIO_printf(bio_err, "Failed to sign the certificate\n"); goto done; } } /* * Print the certificate request information. A number of possible output * formats can be specified and are available below. */ if (text) { ret = R_CERT_REQ_write(req, bio_out, R_FORMAT_TEXT, NULL); if (ret != R_ERROR_NONE) { BIO_printf(bio_err, "Unable to print the request\n"); goto done; } } /* Display the certificate request in C code format */ if (do_c) { ret = R_CERT_REQ_write(req, bio_out, R_FORMAT_CODE_FIELDS, NULL); if (ret != R_ERROR_NONE) { BIO_printf(bio_err, "Unable to print the code format of the certificate" " request\n"); goto done; } } #ifndef NO_CFUNC /* Display the certificate in C code fields format */ if (do_cf) { ret = R_CERT_REQ_write(req, bio_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" " request\n"); goto done; } } #endif /* !NO_CFUNC */ /* Display the certificate request in hexadecimal format */ if (do_hex) { ret = R_CERT_REQ_write(req, bio_out, R_FORMAT_HEX, NULL); if (ret != R_ERROR_NONE) { BIO_printf(bio_err, "Unable to display the hexadecimal format of a certificate" " request\n"); goto done; } } /* Display the certificate request in code hexadecimal format */ if (do_codehex) { ret = R_CERT_REQ_write(req, bio_out, R_FORMAT_CODE_HEX, NULL); if (ret != R_ERROR_NONE) { BIO_printf(bio_err, "Unable to print the code in hexadecimal format of a" " certificate request\n"); goto done; } } /* * Write the certificate to file. Open the output stream and print the * certificate into the stream. */ if (outfile != NULL) { bio_req_out = BIO_new_file(outfile, "wb"); if (bio_req_out == NULL) { BIO_printf(bio_err, "Unable to open the file: %s\n", outfile); ret = R_ERROR_ALLOC_FAILURE; goto done; } } else { bio_req_out = bio_out; bio_out = NULL; } /* Print the PEM format only to stdout */ if (!((out_form == R_FORMAT_BINARY) && (outfile == NULL))) { /* Output the certificate to file */ if (x509 == 1) { ret = R_CERT_write(cert, bio_req_out, out_form, NULL); if (ret != R_ERROR_NONE) { BIO_printf(bio_err, "Failed to write the certificate\n"); } } /* Output the certificate request to file */ else { ret = R_CERT_REQ_write(req, bio_req_out, out_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_printf(bio_out, "ERROR: (%d) %s\n", ret, R_LIB_CTX_get_error_string(lib_ctx, R_RES_MOD_ID_LIBRARY, ret)); } if (pkey != NULL) { R_PKEY_free(pkey); } if (pkey_ctx != NULL) { R_PKEY_CTX_free(pkey_ctx); } if (name != NULL) { R_CERT_NAME_free(name); } if (ca != NULL) { R_CERT_free(ca); } if (cert != NULL) { R_CERT_free(cert); } if (cert_ctx != NULL) { R_CERT_CTX_free(cert_ctx); } if (req != NULL) { R_CERT_REQ_free(req); } if (req_ctx != NULL) { R_CERT_REQ_CTX_free(req_ctx); } if (nb_time != NULL) { R_TIME_free(nb_time); } if (na_time != NULL) { R_TIME_free(na_time); } if (time_ctx != NULL) { R_TIME_CTX_free(time_ctx); } if (bio_req_in != NULL) { BIO_free(bio_req_in); } if (bio_req_out != NULL) { BIO_free(bio_req_out); } if (lib_ctx != NULL) { R_LIB_CTX_free(lib_ctx); } if (bio_in != NULL) { BIO_free(bio_in); } if (bio_out != NULL) { BIO_free(bio_out); } if (bio_err != NULL) { BIO_free(bio_err); } return(R_ERROR_EXIT_CODE(ret)); } /* * Creates an issuer name string. If the option no_in was specified, the name * values are the default. Otherwise, the values come from the user. * * @param max_str_len [In] The amount of memory allocated to string. * @param str [In] The issuer name. * @param no_in [In] Indicates that no user input is required. * * @returns R_ERROR_NONE indicates success.<br> * See @ref R_ERROR_IDS for valid values. */ static int get_issuer_name_string(unsigned int max_str_len, char *str, int no_in) { int ret=R_ERROR_NONE; /* The return value */ int i; /* The iterator over name * entries */ MS_STATIC char in_str[NAME_ITEM_STR_LEN]; /* The name entry value */ char *p; /* A pointer into a string */ /* Make the issuer name string empty */ str[0] = '\0'; /* Create an issuer name string with each of the entries completed */ for (i=0;i<CERT_NAME_NUM_ITEMS;i++) { /* Put in a separator between successive entries */ if (i != 0) { Strcat(str, ", "); } /* Enter a long name of the entry type */ Strcat(str, cert_name_items[i*3+1]); Strcat(str, "="); /* Retrieve the name entry value as the default, or from the user */ p=cert_name_items[i*3+2]; if (no_in == 0) { /* Print out the prompt */ BIO_printf(bio_err, "Enter %s [default %s]: ", cert_name_items[i*3], p); /* Empty the string and enter the user's input */ in_str[0]=0; BIO_gets(bio_in, in_str, NAME_ITEM_STR_LEN); /* 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 required */ if (in_str[0] != '\0') { p=in_str; } } /* Enter the entry value */ Strcat(str, p); } /* The return error value */ return(ret); } /* * Creates a serial number. If the option no_in was specified, the serial * number value is the default. Otherwise, the value comes from the user. * * @param max_buf_len [In] The amount of memory allocated to buffer. * @param buf [In] The serial number. * @param out_len [In] The amount of data going into buffer. * @param no_in [In] Indicates that no user input is wanted. * * @returns R_ERROR_NONE indicates success.<br> * See @ref R_ERROR_IDS for valid values. */ static int get_serial_number(unsigned int max_buf_len, unsigned char *buf, unsigned int *out_len, int no_in) { int ret = R_ERROR_NONE; /* The return value */ MS_STATIC char in_str[SERIAL_INPUT_LEN]; /* The string to read into */ int d; /* A digit */ int s; /* The step value */ int i; /* The iterator over input * string */ /* The default value of serial number is zero */ buf[0] = 0; *out_len = 1; /* Only retrieve the input if required */ if (no_in == 0) { /* Display the prompt */ BIO_printf(bio_err, "Enter Serial Number [default 0]: "); /* Empty the string and enter input */ in_str[0]=0; BIO_gets(bio_in, in_str, SERIAL_INPUT_LEN); /* 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'; } /* Convert the user input into a Byte array */ if (in_str[0] != '\0') { /* * If there is an uneven number of characters then the first one * is the low nibble of the Byte. The step value resolves this. */ s = (Strlen(in_str) & 1); /* * Process each character in the input string until the end of the * string or the end of the buffer */ for (i=0; (in_str[i] != '\0') && ((unsigned int)((s+i)/2) <= max_buf_len); i++) { /* Store the value and make sure it is a hexadecimal value */ d = in_str[i]; if (!isxdigit(d)) { ret = R_ERROR_FAILED; goto done; } /* Convert the hexadecimal digit to a number */ if ((d >= '0') && (d <= '9')) { d -= '0'; } else if ((d >= 'a') && (d <= 'f')) { d -= 'a' - 10; } else { d -= 'A' - 10; } /* If this is the nibble in the appropriate place */ if (((s+i) & 1) == 0) { buf[(s+i)>>1] = d << 4; } else { buf[(s+i)>>1] += d; } } /* Calculate the amount of data in the buffer */ *out_len = ((s + Strlen(in_str)) >> 1); } } done: /* The return error value */ return(ret); }