| RSA BSAFE Micro Edition Suite |
Streamlined security for mobile and embedded devices |
 
![]() |
/* $Id: ocsp_resp_find_key.c,v 1.1.2.10 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_find_key.c * This sample demonstrates how to use the ResponderID to find the responder's * public key and verify the signature of an OCSP response. * * For example, to: * * Find the responder's public key and verify an OCSP response: * ocsp_resp_find_key -resp response.bin * * where: response.bin = The OCSP response file (binary). */ #include "r_prod.h" #include "ocsp_com.h" #define MAX_BUF_LEN 1024 /* Usage help message. */ static char *ocsp_resp_find_key_usage[] = { "usage: ocsp_resp_find_key [options]\n", "where options are:\n", " -resp file - The file containing the OCSP response message.\n", " -help - Print help message.\n", " -eg - Print some example usages.\n", NULL }; static char *ocsp_resp_find_key_example_usage[] = { "Find the responder's public key and verify an OCSP response:\n", " ocsp_resp_find_key -resp response.bin\n", "\n", "where: response.bin = The OCSP response file (binary).\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. * 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; R_TITEM responder_id; R_CERT_NAME *responder_name = NULL; unsigned int num_certs; unsigned int cert_index; R_CERT *current_cert = NULL; R_CERT_NAME *current_name = NULL; int found_match = 0; unsigned char *name_string = NULL; R_OCSP_RESP_ENTRY *ocsp_resp_entry = NULL; R_EXT *extension = NULL; /* The public key in the certificate, used to verify the signature. */ R_PKEY *public_key = NULL; int is_verified = 0; /* * 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 usage information. */ else if (Strcmp(*argv, "-help") == 0) { print_usage = 1; goto end; } /* print the example usage */ else if (Strcmp(*argv,"-eg") == 0) { char **egp; for (egp = ocsp_resp_find_key_example_usage; (*egp) != NULL; egp++) { BIO_printf(bio_out, *egp); } 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 an 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 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 } ResponderID ::= CHOICE { byName [1] Name, byKey [2] KeyHash } KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key (excluding the tag and length fields) *************************************************************************/ /************************************************************************* * Step 4. Retrieve the responderID in ResponseData. *************************************************************************/ if ((ret = R_OCSP_RESP_get_info(ocsp_resp, R_OCSP_RESP_INFO_RESPONDER_ID, &responder_id)) != R_ERROR_NONE) { BIO_printf(bio_out, "R_OCSP_RESP_get_info failure getting \ R_OCSP_RESP_INFO_RESPONDER_ID, \n"); goto end; } /************************************************************************* * Step 5. Retrieve the certificates in a BasicOCSPResponse. BasicOCSPResponse ::= SEQUENCE { tbsResponseData ResponseData, signatureAlgorithm AlgorithmIdentifier, signature BIT STRING, certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL } *************************************************************************/ /* Get the number of certificates in a BasicOCSPResponse. */ num_certs = (unsigned int)-1; if ((ret = R_OCSP_RESP_get_info(ocsp_resp, R_OCSP_RESP_INFO_CERTIFICATE_COUNT, &num_certs)) != R_ERROR_NONE) { BIO_printf(bio_out, "R_OCSP_RESP_get_info failure getting \ R_OCSP_RESP_INFO_CERTIFICATE_COUNT\n"); goto end; } BIO_printf(bio_out, "%d certificates in this BasicOCSPResponse.\n\n", num_certs); switch (responder_id.type) { case R_OCSP_RESPONDER_ID_TYPE_KEY_HASH: /* This sample does not handle OCSP responses that contain the ResponderID as a KeyHash, because it is more common for the ResponderID to be a Name. To add this functionality, go through each certificate, get the public key, and calculate the SHA-1 hash of the public key (excluding the tag and length fields). Then compare the calculated hash to the ResponderID. */ BIO_printf(bio_out, "This sample does not handle OCSP responses that"); BIO_printf(bio_out, "contain the ResponderID as a KeyHash.\n"); goto end; break; case R_OCSP_RESPONDER_ID_TYPE_NAME: responder_name = (R_CERT_NAME *)responder_id.data; /********************************************************************** * Step 6. Check each certificate until you find a matching name. *********************************************************************/ for (cert_index = 0; cert_index < num_certs; cert_index++) { R_INDEXED_INFO indexed_info; indexed_info.index = cert_index; /* Get the current certificate. */ if ((ret = R_OCSP_RESP_get_info(ocsp_resp, R_OCSP_RESP_INFO_CERTIFICATE, &indexed_info)) != R_ERROR_NONE) { BIO_printf(bio_out, "R_OCSP_RESP_get_info failure getting \ R_OCSP_RESP_INFO_CERTIFICATE\n"); goto end; } current_cert = (R_CERT *)(indexed_info.data); /* Retrieve the subject name from the certificate. */ if ((ret = R_CERT_subject_name_to_R_CERT_NAME(current_cert, R_FLAG_SHARE_DEFAULT, ¤t_name)) != R_ERROR_NONE) { BIO_printf(bio_out,"R_CERT_subject_name_to_R_CERT_NAME \ failure\n"); goto end; } /* Compare the responder name with the subject name from the certificate. */ if (R_CERT_NAME_is_equal(responder_name, current_name)) { BIO_printf(bio_out,"Found a matching certificate at index \ %d\n", cert_index); found_match = 1; break; } } /* end for */ if (!found_match) { BIO_printf(bio_out,"Did not find a matching certificate.\n"); ret = R_ERROR_NOT_FOUND; goto end; } /* Print out the subject name of the matching certificate. */ if ((name_string = (unsigned char *)Malloc(MAX_BUF_LEN)) == NULL) { BIO_printf(bio_out, "Malloc failure allocating memory for name \ string\n"); ret = R_ERROR_ALLOC_FAILURE; goto end; } ret = R_CERT_NAME_to_string(current_name, MAX_BUF_LEN, (char *)name_string); BIO_printf(bio_out, " Subject name: \"%s\"\n\n", name_string); /********************************************************************** * Step 7. Retrieve the public key from the certificate. *********************************************************************/ if ((ret = R_CERT_public_key_to_R_PKEY(current_cert, R_FLAG_SHARE_DEFAULT, &public_key)) != R_ERROR_NONE) { BIO_printf(bio_out,"R_CERT_public_key_to_R_PKEY failure\n"); goto end; } /* Clean up. */ if (current_name != NULL) { R_CERT_NAME_free(current_name); current_name = NULL; } if (name_string != NULL) { Free(name_string); name_string = NULL; } break; /* end case R_OCSP_RESPONDER_ID_TYPE_NAME */ default: break; } /* end switch */ /************************************************************************* * Step 8. Verify the signature of the OCSP response. *************************************************************************/ if ((ret = R_OCSP_RESP_verify(ocsp_resp, public_key, &is_verified)) != R_ERROR_NONE) { BIO_printf(bio_out,"R_OCSP_RESP_verify failure\n"); goto end; } BIO_printf(bio_out,"Signature of OCSP response "); if (is_verified) { BIO_printf(bio_out,"verifies.\n"); } else { BIO_printf(bio_out,"does not verify.\n"); } end: /* Display the help menu if an invalid command line option was entered. */ if (print_usage) { for (pp = ocsp_resp_find_key_usage; (*pp != NULL); pp++) { BIO_printf(bio_out, *pp); } } /************************************************************************* * Step 9. 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 (public_key != NULL) { R_PKEY_free(public_key); } if (responder_name != NULL) { R_CERT_NAME_free(responder_name); } if (current_name != NULL) { R_CERT_NAME_free(current_name); } if (name_string != NULL) { Free(name_string); } if (resp_data != NULL) { Free(resp_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)); }