| RSA BSAFE Micro Edition Suite |
Streamlined security for mobile and embedded devices |
 
![]() |
/* $Id: ocsp_resp_ext.c,v 1.1.2.14 2005/11/16 00:18:03 patrick Exp $ */ /* * Copyright (C) 1998-2005 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. * * */ /* * @file ocsp_resp_ext.c * This sample demonstrates how to extract extensions from an OCSP response. * It finds an extension given the extension's OID, and then prints all * singleExtensions in the response. * * For example, to: * * Extract an extension by OID and print all singleExtensions * in an OCSP response: * ocsp_resp_ext -resp response.bin * * where: response.bin = The OCSP response file (binary). */ #include "r_prod.h" #include "ocsp_com.h" /* Usage help message. */ static char *ocsp_resp_ext_usage[] = { "usage: ocsp_resp_ext [options]\n", "where options are:\n", " -resp file - The file containing the OCSP response message.\n", " -text - Display entire response before printing extension data.\n", " -help - Print help message.\n", " -eg - Print some example usages.\n", NULL }; static char *ocsp_resp_ext_example_usage[] = { "Extract an extension by OID and print all singleExtensions\n", " in an OCSP response:\n", " ocsp_resp_ext -resp response.bin\n", "\n", "where: response.bin = The OCSP response file (binary).\n", "\n", NULL }; int print_extension_info(R_EXT *extension, BIO *bio_out) { int ret = R_ERROR_NONE; R_ITEM ext_oid = {0, NULL}; R_ITEM ext_data = {0, NULL}; int criticality; /* Print the criticality. */ /* Returns 0 if criticality is omitted (DEFAULT FALSE) Extension ::= SEQUENCE { extnID OBJECT IDENTIFIER, critical BOOLEAN DEFAULT FALSE, extnValue OCTET STRING } */ if ((ret = R_EXT_get_info(extension, R_EXT_INFO_CRITICAL, &criticality)) != R_ERROR_NONE) { BIO_printf(bio_out, "R_EXT_get_info failure \ getting R_EXT_INFO_CRITICAL \n"); return ret; } BIO_printf(bio_out, " Criticality: "); if (criticality == 0) { BIO_printf(bio_out, "FALSE\n"); } else { BIO_printf(bio_out, "TRUE\n"); } /* Print the extension's OID and value in hex. This sample does not need to further parse the extension OID or value. Currently, only Acceptable Response Types and Nonce are known extensions. Acceptable Response Types is not expected here, because it appears only in requests (not in responses). Nonce is not expected here, because it is included only in responseExtensions (not in singleExtensions). */ if ((ret = R_EXT_get_info(extension, R_EXT_INFO_OID, &ext_oid)) != R_ERROR_NONE) { BIO_printf(bio_out, "R_EXT_get_info(R_EXT_INFO_OID) failure\n"); return ret; } if ((ret = R_EXT_get_info(extension, R_EXT_INFO_DATA, &ext_data)) != R_ERROR_NONE) { BIO_printf(bio_out, "R_EXT_get_info(R_EXT_INFO_DATA) failure\n"); return ret; } BIO_printf(bio_out, " OID: (%d bytes)\n", ext_oid.len); BIO_dump_format(bio_out, ext_oid.data, ext_oid.len, BIO_DUMP_FORMAT_HEX, ':', 4, 16); BIO_printf(bio_out, " Data: (%d bytes)\n", ext_data.len); BIO_dump_format(bio_out, ext_data.data, ext_data.len, BIO_DUMP_FORMAT_HEX, ':', 4, 16); BIO_printf(bio_out, "\n"); return ret; } /* * 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. * See @ref R_ERROR_IDS for valid values. */ int main(int argc, char **argv) { int ret = R_ERROR_NONE; R_LIB_CTX *lib_ctx = NULL; R_OCSP_CTX *ocsp_ctx = NULL; R_OCSP_RESP *ocsp_resp = NULL; BIO *bio_out = NULL; char *resp_file = NULL; unsigned char *resp_data = NULL; unsigned int resp_len; unsigned int num_bytes; int print_usage = 0; int print_text = 0; char **pp; unsigned int num_responses = 0; unsigned int response_index = 0; unsigned int num_extensions = 0; unsigned int extension_index = 0; unsigned int found_index = 0; R_OCSP_RESP_ENTRY *ocsp_resp_entry = NULL; R_EXT *extension = NULL; R_ITEM ext_oid = {0, NULL}; /* Example unknown extension OID: 1.3.6.1.4.1.8150.3.1.1 */ unsigned char EXAMPLE_UNKNOWN_EXT_OID[] = {0x2B, 0x06, 0x01, 0x04, 0x01, 0xBF, 0x56, 0x03, 0x01, 0x01}; /* * Create a BIO to stdout. BIOs are the Basic Input/Output mechanism * provided by RSA. These are recommended for all input and output * from applications. */ if ((bio_out = BIO_new_fp(stdout, BIO_NOCLOSE)) == NULL) { ret = R_ERROR_ALLOC_FAILURE; goto end; } /* Skip the program name. */ argc--; argv++; /* * Parse the command line parameters. */ while (argc >= 1) { /* The OCSP response message file. */ if (Strcmp(*argv, "-resp") == 0) { if (--argc < 1) { print_usage = 1; goto end; } resp_file = *(++argv); } /* Display the entire response before printing extension data. */ else if (Strcmp(*argv, "-text") == 0) { print_text = 1; } /* Display example usage */ else if (Strcmp(*argv,"-eg") == 0) { char **egp; for (egp = ocsp_resp_ext_example_usage; (*egp) != NULL; egp++) { BIO_printf(bio_out, *egp); } goto end; } /* Display the usage information. */ else if (Strcmp(*argv, "-help") == 0) { print_usage = 1; goto end; } /* Unknown option. */ else { BIO_printf(bio_out, "Unknown option %s\n", *argv); print_usage = 1; goto end; } argc--; argv++; } /* Check that the parameters provide all the data needed for performing * verification operations. */ if (resp_file == NULL) { BIO_printf(bio_out, "Input file required\n"); print_usage = 1; goto end; } /************************************************************************* * Step 1. Create the library context. * Retrieve the default resource list to provide access to all * configurable aspects of the library. *************************************************************************/ if ((ret = PRODUCT_LIBRARY_NEW(PRODUCT_DEFAULT_RESOURCE_LIST(), R_RES_FLAG_DEF, &lib_ctx)) != R_ERROR_NONE) { BIO_printf(bio_out, "Library new failure\n"); goto end; } /************************************************************************* * Step 2. Create a new OCSP context. * Create an R_OCSP_CTX with which to create the OCSP response object. *************************************************************************/ if ((ret = R_OCSP_CTX_new(lib_ctx, R_RES_FLAG_DEF, &ocsp_ctx)) != R_ERROR_NONE) { BIO_printf(bio_out, "R_OCSP_CTX_new failure\n"); goto end; } /************************************************************************* * Step 3. Create an OCSP response object from the response file. * Load the data from the file, and use the binary data to create an * OCSP response object with the OCSP context. *************************************************************************/ /* * Read the data from the OCSP response message file into the buffer. * The OCSP response message is in binary form, and copied to a * buffer pointed to by resp_data. */ if ((ret = data_from_file(bio_out, resp_file, &resp_data, &resp_len)) != R_ERROR_NONE) { goto end; } /* * Create an OCSP response object from the binary data. */ if ((ret = R_OCSP_RESP_from_binary(ocsp_ctx, R_FLAG_SHARE_DATA, resp_len, resp_data, &num_bytes, &ocsp_resp)) != R_ERROR_NONE) { BIO_printf(bio_out, "R_OCSP_RESP_from_binary failure\n"); goto end; } /************************************************************************* * (Optional) Print out the OCSP response information. *************************************************************************/ if (print_text) { if ((ret = R_OCSP_RESP_write(ocsp_resp, bio_out, R_FORMAT_TEXT, NULL)) != R_ERROR_NONE) { BIO_printf(bio_out, "R_OCSP_RESP_write failure\n"); goto end; } BIO_printf(bio_out, "\n"); } /************************************************************************* * The following is the structure of an OCSP response. ResponseData ::= SEQUENCE { version [0] EXPLICIT Version DEFAULT v1, responderID ResponderID, producedAt GeneralizedTime, responses SEQUENCE OF SingleResponse, responseExtensions [1] EXPLICIT Extensions OPTIONAL } SingleResponse ::= SEQUENCE { certID CertID, certStatus CertStatus, thisUpdate GeneralizedTime, nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL, singleExtensions [1] EXPLICIT Extensions OPTIONAL } *************************************************************************/ /************************************************************************* * Step 4. Extract the responses (SingleResponses) in ResponseData. *************************************************************************/ /* Retrieve the number of responses (SingleResponses) in ResponseData. */ if ((ret = R_OCSP_RESP_get_info(ocsp_resp, R_OCSP_RESP_INFO_RESP_ENTRY_COUNT, &num_responses)) != R_ERROR_NONE) { BIO_printf(bio_out, "R_OCSP_RESP_get_info failure getting \ R_OCSP_RESP_INFO_RESP_ENTRY_COUNT \n"); goto end; } BIO_printf(bio_out, "%d SingleResponses in this ResponseData.\n", num_responses); /* Go through each SingleResponse. */ for (response_index = 0; response_index < num_responses; response_index++) { /* Create an R_OCSP_RESP_ENTRY to hold a SingleResponse. */ if ((ret = R_OCSP_RESP_ENTRY_new(ocsp_ctx, R_RES_FLAG_DEF, &ocsp_resp_entry)) != R_ERROR_NONE) { BIO_printf(bio_out, "R_OCSP_RESP_ENTRY_new failure\n"); goto end; } /* Get the R_OCSP_RESP_ENTRY (SingleResponse) */ if ((ret = R_OCSP_RESP_get_entry(ocsp_resp, response_index, ocsp_resp_entry)) != R_ERROR_NONE) { BIO_printf(bio_out, "R_OCSP_RESP_get_entry failure getting \ index %d\n", response_index); goto end; } /********************************************************************* * Step 5. Extract the singleExtensions in a SingleResponse. *********************************************************************/ /* Retrieve the number of singleExtensions in a SingleResponse. */ if ((ret = R_OCSP_RESP_ENTRY_get_info(ocsp_resp_entry, R_OCSP_RESP_ENTRY_INFO_EXTENSION_COUNT, &num_extensions)) != R_ERROR_NONE) { BIO_printf(bio_out, "R_OCSP_RESP_ENTRY_get_info failure getting \ R_OCSP_RESP_INFO_RESP_ENTRY_COUNT \n"); goto end; } BIO_printf(bio_out, "%d singleExtensions in SingleResponse at index %d.\n", num_extensions, response_index); /********************************************************************* * Step 6. Extract a single extension given its OID. *********************************************************************/ ext_oid.len = sizeof(EXAMPLE_UNKNOWN_EXT_OID); if ((ext_oid.data = (unsigned char *)Malloc(ext_oid.len * sizeof(unsigned char))) == NULL) { ret = R_ERROR_ALLOC_FAILURE; goto end; } Memcpy(ext_oid.data, EXAMPLE_UNKNOWN_EXT_OID, ext_oid.len); BIO_printf(bio_out, "\nLooking for an extension with "); BIO_printf(bio_out, "OID: (%d bytes)\n", ext_oid.len); BIO_dump_format(bio_out, ext_oid.data, ext_oid.len, BIO_DUMP_FORMAT_HEX, ':', 4, 16); BIO_printf(bio_out, "\n"); /* Create an R_EXT to hold a singleExtension. */ if ((ret = R_EXT_new(lib_ctx, R_RES_FLAG_DEF, &extension)) != R_ERROR_NONE) { BIO_printf(bio_out, "R_EXT_new failure\n"); goto end; } /* Set the OID of the extension that you want to retrieve. */ if ((ret = R_EXT_set_info(extension, R_EXT_INFO_OID, &ext_oid)) != R_ERROR_NONE) { BIO_printf(bio_out, "R_EXT_set_info(R_EXT_INFO_OID) failure\n"); goto end; } /* Get the extension data for the extension identified by the OID. */ /* This finds the first matching extension. The subsequent code prints all of the extensions. */ if ((ret = R_OCSP_RESP_ENTRY_get_info(ocsp_resp_entry, R_OCSP_RESP_ENTRY_INFO_EXTENSION_BY_OID, extension)) != R_ERROR_NONE) { if (ret == R_ERROR_NOT_FOUND) { BIO_printf(bio_out, "Matching extension not found.\n"); } else { BIO_printf(bio_out, "R_EXT_get_info(R_EXT_INFO_OID) failure\n"); } } /* If the extension is found, print the extension's criticality, * type, and value. */ else { BIO_printf(bio_out, "Found a matching extension at index "); if ((ret = R_EXT_get_info(extension, R_EXT_INFO_INDEX, &found_index)) != R_ERROR_NONE) { BIO_printf(bio_out, "R_EXT_get_info failure getting \ R_EXT_INFO_INDEX\n"); goto end; } BIO_printf(bio_out, "%d:\n", found_index); if ((ret = print_extension_info(extension, bio_out)) != R_ERROR_NONE) { goto end; } } if (extension != NULL) { R_EXT_free(extension); extension = NULL; } /* Retrieve each individual extension in the SingleResponse. */ for (extension_index = 0; extension_index < num_extensions; extension_index++) { int copy_of_extension_index = extension_index; /* Create an R_EXT to hold a singleExtension. */ if ((ret = R_EXT_new(lib_ctx, R_RES_FLAG_DEF, &extension)) != R_ERROR_NONE) { BIO_printf(bio_out, "R_OCSP_RESP_ENTRY_new failure\n"); goto end; } /* Get the extension at the current index. */ if ((ret = R_EXT_set_info(extension, R_EXT_INFO_INDEX, ©_of_extension_index)) != R_ERROR_NONE) { BIO_printf(bio_out, "R_EXT_set_info failure setting \ R_EXT_INFO_INDEX\n"); goto end; } if ((ret = R_OCSP_RESP_ENTRY_get_info(ocsp_resp_entry, R_OCSP_RESP_ENTRY_INFO_EXTENSION, extension)) != R_ERROR_NONE) { BIO_printf(bio_out, "R_OCSP_RESP_ENTRY_get_info failure \ getting R_OCSP_RESP_ENTRY_INFO_EXTENSION \n"); goto end; } BIO_printf(bio_out, "singleExtension at index %d:\n", extension_index); /* Print the extension's criticality, type, and value. */ if ((ret = print_extension_info(extension, bio_out)) != R_ERROR_NONE) { goto end; } if (extension != NULL) { R_EXT_free(extension); extension = NULL; } } /* end for */ if (ocsp_resp_entry != NULL) { R_OCSP_RESP_ENTRY_free(ocsp_resp_entry); ocsp_resp_entry = NULL; } } /* end for */ end: /* Display the help menu if an invalid command line option was entered. */ if (print_usage) { for (pp = ocsp_resp_ext_usage; (*pp != NULL); pp++) { BIO_printf(bio_out, *pp); } } /************************************************************************* * Step 7. Clean up. * Report errors using both the error number and the string * representation. Destroy the dynamically allocated * objects, and return an exit code. *************************************************************************/ if ((ret != R_ERROR_NONE) && (bio_out != NULL)) { BIO_printf(bio_out, "ERROR: (%d) %s\n", ret, R_LIB_CTX_get_error_string(lib_ctx, R_RES_MOD_ID_LIBRARY, ret)); } if (resp_data != NULL) { Free(resp_data); } if (ext_oid.data != NULL) { Free(ext_oid.data); } if (extension != NULL) { R_EXT_free(extension); } if (ocsp_resp_entry != NULL) { R_OCSP_RESP_ENTRY_free(ocsp_resp_entry); } if (ocsp_resp != NULL) { R_OCSP_RESP_free(ocsp_resp); } if (ocsp_ctx != NULL) { R_OCSP_CTX_free(ocsp_ctx); } if (lib_ctx != NULL) { PRODUCT_LIBRARY_FREE(lib_ctx); } if (bio_out != NULL) { BIO_free(bio_out); } return(R_ERROR_EXIT_CODE(ret)); }