| RSA BSAFE Micro Edition Suite |
Streamlined security for mobile and embedded devices |
 
![]() |
/* $Id: ocsp_resp_vfy.c,v 1.1.2.19 2005/11/09 07:18:18 clindgre 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. * * */ /* * @file * This sample demonstrates operations with OCSP response messages. * * For example, to: * * Verify the signature with the issuer certificate and print the message: * ocsp_resp_vfy -resp response.data -issuer ca_cert.data -print * * Verify the signature of the OCSP response and verify the validity of the * certificate : * ocsp_resp_vfy -resp response.data -req request.data -cert cert.data * -issuer ca_cert.data * * Verify the signature of the OCSP response with the responder's certificate * and verify the validity of the certificate at the specified time : * ocsp_resp_vfy -resp response.data -req request.data -cert cert.data * -issuer ca_cert.data -resp_cert resp_cert.data -time 20050101000000Z * * where: response.data = The OCSP response file. * ca_cert.data = The signer's certificate. * request.data = The OCSP request file. * cert.data = The certificate to verify. * resp_cert.data = The OCSP resonder's certificate. * */ #include "r_prod.h" #include "r_oid.h" #include "ocsp_com.h" int ocsp_response_verify_signature(R_LIB_CTX *lib_ctx, R_OCSP_RESP *resp, R_CERT *cert, BIO *bio_out); int ocsp_response_verify_nonce(R_LIB_CTX *lib_ctx, R_OCSP_REQ *req, R_OCSP_RESP *resp, BIO *bio_out); int ocsp_response_revoked_check(R_LIB_CTX *lib_ctx, R_OCSP_RESP_ENTRY *resp_entry, char *vfy_time_str, BIO *bio_out); int ocsp_response_verify_certificate(R_LIB_CTX *lib_ctx, R_OCSP_CTX *ctx, R_OCSP_RESP *resp, R_CERT *cert, R_CERT *issuer, char *vfy_time_str, BIO *bio_out); /* Usage help message. */ static char *ocsp_resp_vfy_usage[] = { "usage: ocsp_resp_vfy [options]\n", "where options are:\n", " -resp file - The file containing the OCSP response message\n", " -req file - The file containing the OCSP request message\n", " -cert file - A file containing a certificate to check\n", " -issuer file - A file containing the issuer certificate\n", " -resp_cert file - A file containing the responder's certificate\n", " -cert_type encoding - Encoding the certificates - only X509\n", " (default) supported\n", #ifdef NO_PEM " -cert_form format - The format of the certificates (BIN only)\n", #else " -cert_form format - The format of the certificates - one of BIN " "(default),\n", " PEM\n", " -time YYYYMMDDHHMMSSZ - Set the verification time rather than use the\n", " system time\n", #endif /* NO_PEM */ " -help - Print this usage message.\n", " -eg - Print some example usages.\n", NULL }; /* Examples of usage. */ static char *ocsp_resp_vfy_example_usage[] = { "Verify the signature with the issuer certificate and print the message:\n", " ocsp_resp_vfy -resp response.data -issuer ca_cert.data -print\n", "\n", "Verify the signature of the OCSP response and verify the validity of the\n", "certificate :\n", " ocsp_resp_vfy -resp response.data -req request.data -cert cert.data\n", " -issuer ca_cert.data\n", "\n", "Verify the signature of the OCSP response with the responder's " "certificate\n", "and verify the validity of the certificate at the specified time :\n", " ocsp_resp_vfy -resp response.data -req request.data -cert cert.data\n", " -issuer ca_cert.data -resp_cert resp_cert.data -time 20050101000000Z\n", "\n", "where: response.data = The OCSP response file.\n", " ca_cert.data = The signer's certificate.\n", " request.data = The OCSP request file.\n", " cert.data = The certificate to verify.\n", " resp_cert.data = The OCSP resonder's certificate.\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 *ctx = NULL; R_OCSP_RESP *resp = NULL; R_OCSP_REQ *req = NULL; R_CERT_CTX *cert_ctx = NULL; R_CERT *cert = NULL; R_CERT *issuer = NULL; R_CERT *resp_cert = NULL; BIO *bio_out = NULL; char *resp_file; char *req_file; char *cert_file; char *issuer_file; char *resp_cert_file; char *cert_type; char *cert_form; unsigned char *resp_data = NULL; unsigned int resp_len; unsigned char *req_data = NULL; unsigned int req_len; unsigned int num_used; int print_msg; char *vfy_time = NULL; R_OID signing; R_OID *oid; /* Set the defaults */ resp_file = NULL; req_file = NULL; cert_file = NULL; issuer_file = NULL; resp_cert_file = NULL; cert_type = "X509"; cert_form = "BIN"; print_msg = 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) { goto bad; } resp_file = *(++argv); } /* The OCSP request message file. */ else if (Strcmp(*argv, "-req") == 0) { if (--argc < 1) { goto bad; } req_file = *(++argv); } /* The certificate file. */ else if (Strcmp(*argv, "-cert") == 0) { if (--argc < 1) { goto bad; } cert_file = *(++argv); } /* The issuer certificate file. */ else if (Strcmp(*argv, "-issuer") == 0) { if (--argc < 1) { goto bad; } issuer_file = *(++argv); } /* The responder certificate file. */ else if (Strcmp(*argv, "-resp_cert") == 0) { if (--argc < 1) { goto bad; } resp_cert_file = *(++argv); } /* The certificate type. */ else if (Strcmp(*argv, "-cert_type") == 0) { if (--argc < 1) { goto bad; } cert_type = *(++argv); } /* The certificate format. */ else if (Strcmp(*argv, "-cert_form") == 0) { if (--argc < 1) { goto bad; } cert_form = *(++argv); } /* Print out the details of the message. */ else if (Strcmp(*argv, "-print") == 0) { print_msg = 1; } else if (Strcmp(*argv, "-time") == 0) { if (--argc < 1) { goto bad; } vfy_time = *(++argv); } /* Display the usage information. */ else if (Strcmp(*argv, "-help") == 0) { goto bad; } /* Display examples of usage information. */ else if (Strcmp(*argv,"-eg") == 0) { char **egp; for (egp = ocsp_resp_vfy_example_usage; (*egp) != NULL; egp++) { BIO_printf(bio_out, *egp); } goto end; } /* Unknown option. */ else { BIO_printf(bio_out, "Unknown option %s\n", *argv); goto bad; } 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"); goto bad; } if (issuer_file == NULL) { BIO_printf(bio_out, "An issuer certificate file is required\n"); goto bad; } if ((req_file != NULL) && (cert_file == NULL)) { BIO_printf(bio_out, "A certificate file to verify is required\n"); goto bad; } /* If you entered an invalid command line option, display the help menu. */ if (0) { char **pp; bad: for (pp = ocsp_resp_vfy_usage; (*pp != NULL); pp++) { BIO_printf(bio_out, *pp); } 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. Load the certificates. * The load function creates a certificate context and reads the * certificate from the file. * When the responer has not specified a certificate (that is when the * OCSP signing is not delegated), the responder's certificate is the * issuer certificate. *************************************************************************/ /* Load the certificate that is being checked. */ if ((ret = load_certificate(bio_out, lib_ctx, cert_file, cert_type, cert_form, &cert_ctx, &cert)) != R_ERROR_NONE) { BIO_printf(bio_out, "Certificate being checked failed\n"); goto end; } /* Load the issuer certificate. */ if ((ret = load_certificate(bio_out, lib_ctx, issuer_file, cert_type, cert_form, &cert_ctx, &issuer)) != R_ERROR_NONE) { BIO_printf(bio_out, "Issuer certificate failed\n"); goto end; } /* If the responder certificate is specified, load it. */ if (resp_cert_file == NULL) { resp_cert = issuer; } else { if ((ret = load_certificate(bio_out, lib_ctx, resp_cert_file, cert_type, cert_form, &cert_ctx, &resp_cert)) != R_ERROR_NONE) { BIO_printf(bio_out, "Responder certificate failed\n"); goto end; } /* Ensure that the OCSP signing extended key usage extension is * present. */ if (!R_CERT_is_info_present(resp_cert, R_CERT_INFO_EXTENDED_KEY_USAGE)) { BIO_printf(bio_out, "No OCSP signing delegation extension present\n"); ret = R_ERROR_FAILED; goto end; } /* Create an OID object containing the OCSP signing OID. */ if ((ret = R_OID_init_with_constant(&signing, R_OID_OCSP_SIGNING)) != R_ERROR_NONE) { BIO_printf(bio_out, "Unable to initialize R_OID structure\n"); goto end; } oid = &signing; /* Check for the OCSP signing extended key usage. */ if (!R_CERT_test_extended_key_usage(resp_cert, &oid, 1)) { BIO_printf(bio_out, "No OCSP signing delegation extension present\n"); ret = R_ERROR_FAILED; goto end; } } /************************************************************************* * Step 3. 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, &ctx)) != R_ERROR_NONE) { BIO_printf(bio_out, "R_OCSP_CTX_new failure\n"); goto end; } /************************************************************************* * Step 4. Create an OCSP response object from the response file. * Load the data from the file. Use the binary data to create an * OCSP response object with the OCSP context. *************************************************************************/ /* * Read the data from 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; } /* * Load the OCSP message buffer into an OCSP response message object. */ if ((ret = R_OCSP_RESP_from_binary(ctx, R_FLAG_SHARE_DATA, resp_len, resp_data, &num_used, &resp)) != R_ERROR_NONE) { BIO_printf(bio_out, "R_OCSP_RESP_from_binary failure\n"); goto end; } /************************************************************************* * Step 5. Create an OCSP request object from the request file. * Load the data from the file. Use the binary data to create an * OCSP request object with the OCSP context. *************************************************************************/ if (req_file != NULL) { /* * Read the data from the OCSP request message file into the buffer. * The OCSP request message is in binary form, and copied to a * buffer pointed to by req_data. */ if ((ret = data_from_file(bio_out, req_file, &req_data, &req_len)) != R_ERROR_NONE) { goto end; } /* * Load the OCSP message buffer into an OCSP request message object. */ if ((ret = R_OCSP_REQ_from_binary(ctx, R_FLAG_SHARE_DATA, req_len, req_data, &num_used, &req)) != R_ERROR_NONE) { BIO_printf(bio_out, "R_OCSP_REQ_from_binary failure\n"); goto end; } } /************************************************************************* * Step 6. If requested, print the OCSP response message. *************************************************************************/ if (print_msg) { if ((ret = R_OCSP_RESP_write(resp, bio_out, R_FORMAT_TEXT, NULL)) != R_ERROR_NONE) { BIO_printf(bio_out, "Failed to write OCSP response message\n"); goto end; } } /************************************************************************* * Step 7. Verify the OCSP response message with the responder's * certificate. *************************************************************************/ if ((ret = ocsp_response_verify_signature(lib_ctx, resp, resp_cert, bio_out)) != R_ERROR_NONE) { goto end; } /************************************************************************* * Step 8. Verify that the nonce from the request matches the nonce in * the response. * If a nonce was specified in the request, the same nonce must appear * in the response. *************************************************************************/ /* Check that there is a request to extract a nonce from. */ if (req != NULL) { if ((ret = ocsp_response_verify_nonce(lib_ctx, req, resp, bio_out)) != R_ERROR_NONE) { goto end; } } /************************************************************************* * Step 9. Verify the certificate with the OCSP response message. *************************************************************************/ if ((ret = ocsp_response_verify_certificate(lib_ctx, ctx, resp, cert, issuer, vfy_time, bio_out)) != R_ERROR_NONE) { goto end; } end: /************************************************************************* * Step 10. Clean up. * If there is an output stream, report errors using both the error 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 (req_data != NULL) { Free(req_data); } if (resp_data != NULL) { Free(resp_data); } if (req != NULL) { R_OCSP_REQ_free(req); } if (resp != NULL) { R_OCSP_RESP_free(resp); } if (ctx != NULL) { R_OCSP_CTX_free(ctx); } if ((resp_cert != issuer) && (resp_cert != NULL)) { R_CERT_free(resp_cert); } if (issuer != NULL) { R_CERT_free(issuer); } if (cert != NULL) { R_CERT_free(cert); } if (cert_ctx != NULL) { R_CERT_CTX_free(cert_ctx); } if (lib_ctx != NULL) { PRODUCT_LIBRARY_FREE(lib_ctx); } if (bio_out != NULL) { BIO_free(bio_out); } return(R_ERROR_EXIT_CODE(ret)); } /* * Verify the signature in the OCSP response with the responder's certificate. * If a key usage is specified, ensure that the certificate can be used for * digital signatures. * * @param lib_ctx [In] The library context. * @param resp [In] The OCSP response. * @param cert [In] The responder's response. * @param bio_out [In] The I/O stream to write information to. * @return #R_ERROR_NONE indicates success.<br> * See @ref R_ERROR_IDS for valid values. */ int ocsp_response_verify_signature(R_LIB_CTX *lib_ctx, R_OCSP_RESP *resp, R_CERT *cert, BIO *bio_out) { int ret; R_PKEY *pkey = NULL; int is_verified; R_EXT *no_check_ext = NULL; int ext_nid = R_EXT_ID_OCSP_NOCHECK; /************************************************************************* * Step 1. Check that the certificate can be used for digital signatures. * If there is a key usage, check it for the digital signatures bit. *************************************************************************/ if (R_CERT_is_info_present(cert, R_CERT_INFO_KEY_USAGE)) { if (!R_CERT_test_key_usage(cert, R_CERT_KEY_USAGE_DIGITAL_SIGNATURE)) { BIO_printf(bio_out, "The key is not to be used for digital signatures\n"); ret = R_ERROR_FAILED; goto end; } } /************************************************************************* * Step 2. Check that the certificate is valid. * Check for the extension indicating that there is no need to verify * the validity. If no such extension is present, perform checks as per * the local security policy (for example the CRL validation). *************************************************************************/ /* Create an extension. */ if ((ret = R_EXT_new(lib_ctx, R_RES_FLAG_DEF, &no_check_ext)) != R_ERROR_NONE) { BIO_printf(bio_out, "Unable to create an extension\n"); goto end; } /* Set the OCSP No Check numeric identifier in the extension object. */ if ((ret = R_EXT_set_info(no_check_ext, R_EXT_INFO_ID, &ext_nid)) != R_ERROR_NONE) { BIO_printf(bio_out, "Unable to set the OID into the extension\n"); goto end; } /* Attempt to get the OCSP No Check extension from the certificate. * If the return value is R_ERROR_NONE then you do not need to perform * further checks. */ ret = R_CERT_get_info(cert, R_CERT_INFO_EXTENSION_BY_OID, no_check_ext); if (ret == R_ERROR_NOT_FOUND) { /* Perform checks as per the local security policy. */ } else if (ret != R_ERROR_NONE) { BIO_printf(bio_out, "Unable to get an extension from the certificate\n"); goto end; } /************************************************************************* * Step 3. Obtain the public key from the certificate. *************************************************************************/ if ((ret = R_CERT_public_key_to_R_PKEY(cert, R_FLAG_SHARE_DATA, &pkey)) != R_ERROR_NONE) { BIO_printf(bio_out, "Unable to retrieve public key from certificate\n"); goto end; } /************************************************************************* * Step 4. Verify the signature. * If the verification process fails, calling verify will return an error. * The is_verified parameter contains the return code that indicates * whether the public key verified the signature in the OCSP response * message. *************************************************************************/ if ((ret = R_OCSP_RESP_verify(resp, pkey, &is_verified)) != R_ERROR_NONE) { BIO_printf(bio_out, "Signature verification process failed\n"); goto end; } /* * Check that the signature verified. */ if (!is_verified) { BIO_printf(bio_out, "Signature failed verification\n"); ret = R_ERROR_FAILED; goto end; } BIO_printf(bio_out, "Signature verified!\n"); end: /************************************************************************* * Step 5. Clean up. *************************************************************************/ if (pkey != NULL) { R_PKEY_free(pkey); } if (no_check_ext != NULL) { R_EXT_free(no_check_ext); } return(ret); } /* * Ensure that if there is a nonce in the request that there is a nonce in the * response and that the nonce in the response has the same data as the nonce * in the request. * * @param lib_ctx [In] The library context. * @param req [In] The OCSP request. * @param resp [In] The OCSP response. * @param bio_out [In] The I/O stream to write information to. * @return #R_ERROR_NONE indicates success.<br> * See @ref R_ERROR_IDS for valid values. */ int ocsp_response_verify_nonce(R_LIB_CTX *lib_ctx, R_OCSP_REQ *req, R_OCSP_RESP *resp, BIO *bio_out) { int ret = R_ERROR_NONE; R_ITEM nonce_req; R_ITEM nonce_resp; /************************************************************************* * Step 1. Get the nonce from the request. * If the request does not contain a nonce, the call will return * R_ERROR_NOT_FOUND. In this case there is no data to verify. * If the call returns any other error value (other than R_ERROR_NONE) * then there is something wrong with the request message. * If no error value is returned, the request nonce was found. *************************************************************************/ ret = R_OCSP_REQ_get_info(req, R_OCSP_REQ_INFO_NONCE, &nonce_req); if (ret == R_ERROR_NOT_FOUND) { /* There is no nonce in the request, and therefore no data with * which to verify. */ ret = R_ERROR_NONE; goto end; } if (ret != R_ERROR_NONE) { /* An error occurred when extracting the nonce. */ BIO_printf(bio_out, "Unable to extract nonce from OCSP request\n"); goto end; } /************************************************************************* * Step 2. Get the nonce from the response. * If the response does not contain a nonce, the call will return * R_ERROR_NOT_FOUND. In this case the response is missing the * required nonce. * If the call returns any other error value (other than R_ERROR_NONE) * then there is something wrong with the response message. * If no error value is returned, the response nonce was found. *************************************************************************/ ret = R_OCSP_RESP_get_info(resp, R_OCSP_RESP_INFO_NONCE, &nonce_resp); if (ret == R_ERROR_NOT_FOUND) { /* No nonce was found. The nonce should have been present. */ BIO_printf(bio_out, "Nonce missing from response\n"); goto end; } else if (ret != R_ERROR_NONE) { /* An error occurred when extracting the nonce. */ BIO_printf(bio_out, "Unable to extract nonce from OCSP response\n"); goto end; } /************************************************************************* * Step 3. Compare the nonces from the request and response. * The data of the nonces in the request and response must be identical * for the verification process to pass. *************************************************************************/ if ((nonce_req.len != nonce_resp.len) || (Memcmp(nonce_req.data, nonce_resp.data, nonce_req.len) != 0)) { /* Nonces do not match - error. */ BIO_printf(bio_out, "Nonce from request does not match nonce in response\n"); ret = R_ERROR_FAILED; } end: return(ret); } /* * Verify the certificate from the response. * The status is checked; and if the certificate is revoked, the time * is checked. * * @param lib_ctx [In] The library context. * @param ctx [In] The OCSP context. * @param resp [In] The OCSP response. * @param cert [In] The certificate to be checked. * @param issuer [In] The issuer certificate for the certificate to be * checked. * @param vfy_time_str [In] The time of verification of the certificate. * @param bio_out [In] The I/O stream to write information to. * @return #R_ERROR_NONE indicates success.<br> * See @ref R_ERROR_IDS for valid values. */ int ocsp_response_verify_certificate(R_LIB_CTX *lib_ctx, R_OCSP_CTX *ctx, R_OCSP_RESP *resp, R_CERT *cert, R_CERT *issuer, char *vfy_time_str, BIO *bio_out) { int ret; R_OCSP_RESP_ENTRY *resp_entry = NULL; R_OCSP_CERT_STATUS status; /************************************************************************* * Step 1. Get the entry for the certificate from the response. *************************************************************************/ /* Create a response entry. */ if ((ret = R_OCSP_RESP_ENTRY_new(ctx, R_RES_FLAG_DEF, &resp_entry)) != R_ERROR_NONE) { BIO_printf(bio_out, "Unable to create response entry\n"); goto end; } /* Get the OCSP response entry for the certificate. */ if ((ret = R_OCSP_RESP_find_entry_by_cert(resp, cert, NULL, resp_entry)) != R_ERROR_NONE) { BIO_printf(bio_out, "No entry in response for certificate\n"); goto end; } /************************************************************************* * Step 2. Determine the status of the certificate. * Check the revocation time to verify whether the certificate was * revoked at the verification time. *************************************************************************/ /* Get the status from the response entry. */ if ((ret = R_OCSP_RESP_ENTRY_get_info(resp_entry, R_OCSP_RESP_ENTRY_INFO_CERT_STATUS, &status)) != R_ERROR_NONE) { BIO_printf(bio_out, "Unable to get certificate status\n"); goto end; } /* Check the status. */ if (status == R_OCSP_CERT_STATUS_GOOD) { BIO_printf(bio_out, "Certificate status: Valid!\n"); } else if (status == R_OCSP_CERT_STATUS_UNKNOWN) { BIO_printf(bio_out, "Certificate status: Not Known\n"); } else { BIO_printf(bio_out, "Certificate status: Revoked\n"); ret = ocsp_response_revoked_check(lib_ctx, resp_entry, vfy_time_str, bio_out); } end: /************************************************************************* * Step 3. Clean up. *************************************************************************/ if (resp_entry != NULL) { R_OCSP_RESP_ENTRY_free(resp_entry); } return(ret); } /* * Check the time of revocation for the certificate from the OCSP response * entry. * * @param lib_ctx [In] The library context. * @param resp_entry [In] The OCSP response entry. * @param vfy_time_str [In] The time of verification of the certificate. * @param bio_out [In] The I/O stream to write information to. * @return #R_ERROR_NONE indicates success.<br> * See @ref R_ERROR_IDS for valid values. */ int ocsp_response_revoked_check(R_LIB_CTX *lib_ctx, R_OCSP_RESP_ENTRY *resp_entry, char *vfy_time_str, BIO *bio_out) { int ret; R_OCSP_REVOCATION_REASON reason; R_TIME_CTX *time_ctx = NULL; R_TIME *rev_time = NULL; R_TIME *vfy_time = NULL; int time_cmp; char time_str[R_TIME_SHRF_SIZE]; unsigned int len; /************************************************************************* * Step 1. Retrieve the revocation reason (if available). *************************************************************************/ ret = R_OCSP_RESP_ENTRY_get_info(resp_entry, R_OCSP_RESP_ENTRY_INFO_REVOCATION_REASON, &reason); if (ret != R_ERROR_NOT_FOUND) { if (ret != R_ERROR_NONE) { BIO_printf(bio_out, "Unable to get revocation reason\n"); goto end; } else { BIO_printf(bio_out, "Reason for revocation: %d\n", reason); } } /************************************************************************* * Step 2. Create a time context with which to create time objects. *************************************************************************/ if ((ret = R_TIME_CTX_new(lib_ctx, R_RES_FLAG_DEF, &time_ctx)) != R_ERROR_NONE) { BIO_printf(bio_out, "Unable to create a time context\n"); goto end; } /************************************************************************* * Step 3. Check the revocation time to determine whether the certificate * has been revoked. * Retrieve the revocation into a time object and display the time. *************************************************************************/ /* Create a new time object for the revocation time. */ if ((ret = R_TIME_new(time_ctx, &rev_time)) != R_ERROR_NONE) { BIO_printf(bio_out, "Unable to create a new time object\n"); goto end; } /* Get the revocation time. */ if ((ret = R_OCSP_RESP_ENTRY_get_info(resp_entry, R_OCSP_RESP_ENTRY_INFO_REVOCATION_TIME, rev_time)) != R_ERROR_NONE) { BIO_printf(bio_out, "Unable to get revocation time\n"); goto end; } /* Convert the time to a string. */ if ((ret = R_TIME_export(rev_time, R_TIME_EXTERNAL_FORMAT_SHRF, (unsigned char *)time_str, &len, sizeof(time_str))) != R_ERROR_NONE) { BIO_printf(bio_out, "Unable to convert revocation time to string\n"); goto end; } BIO_printf(bio_out, "Revocation time: %s\n", time_str); /************************************************************************* * Step 4. Create a time object with the verification time. * If a time was not specified, use the current time. * Display the verification time. *************************************************************************/ /* Create a new time object for the verification time. */ if ((ret = R_TIME_new(time_ctx, &vfy_time)) != R_ERROR_NONE) { BIO_printf(bio_out, "Unable to create a new time object\n"); goto end; } /* If no verification time string is specified, take the current time. */ if (vfy_time_str == NULL) { if ((ret = R_TIME_time(vfy_time)) != R_ERROR_NONE) { BIO_printf(bio_out, "Unable to deteremint the current time\n"); goto end; } } /* Import the verification time string. */ else { if ((ret = R_TIME_import(vfy_time, R_TIME_EXTERNAL_FORMAT_GT, (unsigned char *)vfy_time_str, Strlen(vfy_time_str))) != R_ERROR_NONE) { BIO_printf(bio_out, "Unable to import time string\n"); goto end; } } /* Convert the time to a string. */ if ((ret = R_TIME_export(vfy_time, R_TIME_EXTERNAL_FORMAT_SHRF, (unsigned char *)time_str, &len, sizeof(time_str))) != R_ERROR_NONE) { BIO_printf(bio_out, "Unable to convert verification time to string\n"); goto end; } BIO_printf(bio_out, "Verification time: %s\n", time_str); /************************************************************************* * Step 5. Compare the revocation time with the time at which the * verification is taking place. *************************************************************************/ if ((ret = R_TIME_cmp(rev_time, vfy_time, &time_cmp)) != R_ERROR_NONE) { BIO_printf(bio_out, "Unable to compare with the revocation time\n"); goto end; } if (time_cmp > 0) { BIO_printf(bio_out, "Certificate is not revoked yet\n"); } else { BIO_printf(bio_out, "Certificate is revoked\n"); } end: /************************************************************************* * Step 6. Clean up. *************************************************************************/ if (vfy_time != NULL) { R_TIME_free(vfy_time); } if (rev_time != NULL) { R_TIME_free(rev_time); } if (time_ctx != NULL) { R_TIME_CTX_free(time_ctx); } return(ret); }