| RSA BSAFE Micro Edition Suite |
Streamlined security for mobile and embedded devices |
 
![]() |
/* $Id: cm_smpl.c,v 1.45 2005/08/08 05:33:31 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. * * */ /* * @file * This sample demonstrates verifying and printing PKCS #7 signed data * messages. No certificate verification is performed. * * For information detailing generating PKCS #7 signed messages, * see cm_sign.c. * * For example, to: * * Verify the signature and print the data: * cm_smpl -cm_msg signed.data -print_data * * Verify the signature with the certificate not in the PKCS #7 message * (the signer's certificate is supplied): * cm_smpl -cm_msg signed.data -certs signer.cert -print_signers -print_data * * where: signed.data = The output file where PKCS #7 data is written. * signer.cert = The signer's certificate (used when the signed data * was created). */ /* This sample only parses messages and does not print the signer(s) details */ #define NO_R_CM_ADD_SIGNERS #define NO_R_CM_PRINT_SIGNER #include "r_prod.h" #include "cm_com.h" #ifdef CM_SMPL_SMALL /* For a small executable use a minimized resource list */ #include "r_cm_r.h" #define CM_SMPL_RESOURCE_LIST R_CM_get_verify_small_resource_list #define CM_SMPL_CTX_TYPE R_CM_TYPE_SIGNED_DATA_READ #else /* !CM_SMPL_SMALL */ #define CM_SMPL_RESOURCE_LIST PRODUCT_DEFAULT_RESOURCE_LIST #define CM_SMPL_CTX_TYPE R_CM_TYPE_DEFAULT #endif /* !CM_SMPL_SMALL */ /* Usage help message */ static char *cm_smpl_usage[] = { "usage: cm_smpl [options]\n", "where options are:\n", " -cm_msg file - The file containing the cryptographic message\n", " -data_msg file - The file containing the data if it's not part of" "\n", " the cryptographic message\n", " -single - The cryptographic message and detached data are" "\n", " in the same file, the cryptographic message\n", " first followed by the detached data\n", " -wrap - The detached message is wrapped and should be\n", " and should be unwrapped before use\n", " -certs list - The list of certificates (colon separated)\n", " -certtype encoding - The encoding of the certificates - only X509\n", " (default) supported\n", #ifdef NO_PEM " -certform format - Format of the certs (BIN only)\n", #else " -certform format - Format of the certs one of BIN (default), PEM\n", #endif /* NO_PEM */ " -print - Print the data of the cryptographic message\n", #ifdef NO_SOFTWARE_CRYPTO " -no_fips140 - Use non FIPS140 crypto implementations\n", #endif /* NO_SOFTWARE_CRYPTO */ 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) { R_RES_LIST *res_list; R_LIB_CTX *lib_ctx = NULL; R_CM_CTX *ctx = NULL; R_CM *obj = NULL; R_CM *data_obj = NULL; R_CERT_CTX *cert_ctx = NULL; R_CERT_STORE_CTX *store_ctx = NULL; R_VERIFY_CTX *vfy_ctx = NULL; BIO *bio_out = NULL; R_ITEM data = { 0, NULL }; R_TITEM msg_data = { R_FLAG_SHARE_DATA, 0, NULL }; char *cm_file; char *datafile; char *certfile; char *certtype; char *certform; unsigned char *cm_data = NULL; unsigned char type[R_CM_TYPE_MAX_STR_LENGTH]; unsigned int num_used; unsigned int cm_len; int ret = R_ERROR_NONE; int is_verified; R_CM_TYPE data_type; int wrap; int single; int print; unsigned int slen; /* Set the defaults */ cm_file = NULL; datafile = NULL; certfile = NULL; certtype = "X509"; certform = "BIN"; single = 0; wrap = 0; print = 0; res_list = CM_SMPL_RESOURCE_LIST(); /* * Create BIO to stdout. BIOs are the Basic Input/Output mechanism provided * by RSA and 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; } /* Parse the command line parameters */ /* Skip the program name */ argc--; argv++; /* Process all command line options */ while (argc >= 1) { if (Strcmp(*argv, "-cm_msg") == 0) { if (--argc < 1) { goto bad; } cm_file = *(++argv); } else if (Strcmp(*argv, "-data_msg") == 0) { if (--argc < 1) { goto bad; } datafile = *(++argv); } else if (Strcmp(*argv, "-single") == 0) { single = 1; } else if (Strcmp(*argv, "-wrap") == 0) { wrap = 1; } else if (Strcmp(*argv, "-certs") == 0) { if (--argc < 1) { goto bad; } certfile = *(++argv); } else if (Strcmp(*argv, "-certtype") == 0) { if (--argc < 1) { goto bad; } certtype = *(++argv); } else if (Strcmp(*argv, "-certform") == 0) { if (--argc < 1) { goto bad; } certform = *(++argv); } else if (Strcmp(*argv, "-print") == 0) { print = 1; } #ifdef NO_SOFTWARE_CRYPTO else if (Strcmp(*argv, "-no_fips140") == 0) { res_list = PRODUCT_NON_FIPS_140_MODE_RESOURCE_LIST(); } #endif /* NO_SOFTWARE_CRYPTO */ else { BIO_printf(bio_out, "Unknown option %s\n", *argv); goto bad; } argc--; argv++; } /* Simple checks first */ if (cm_file == NULL) { BIO_printf(bio_out, "Input file required\n"); goto bad; } /* Display the help menu if an invalid command line option was entered */ if (0) { char **pp; bad: for (pp = cm_smpl_usage; (*pp != NULL); pp++) { BIO_printf(bio_out, *pp); } goto end; } /* * Create a library context to provide access to all configurable aspects * of the library */ if ((ret = PRODUCT_LIBRARY_NEW(res_list, R_RES_FLAG_DEF, &lib_ctx)) != R_ERROR_NONE) { BIO_printf(bio_out, "Library new failure\n"); goto end; } /* * Set up the certificate-related functionality. If any certificates are * specified: * - Create a certificate context. * - Create a store context. * - Create a store object. * For each certificate: * - Read the certificate from file. * - Set the certificate against the store object. * - Set the certificate trust level. * - Add the certificate to the store (using the store object). */ if ((ret = load_certificates(bio_out, lib_ctx, certfile, certtype, certform, &cert_ctx, &store_ctx)) != R_ERROR_NONE) { goto end; } /* * Create a verification context and set the verification options. This * sample does not perform any certificate verification. For certificate * verification, see cm.c or cm_adv.c. */ if ((ret = set_verification(bio_out, lib_ctx, "NONE", NULL, &vfy_ctx)) != R_ERROR_NONE) { goto end; } /* Create a new R_CM context */ if ((ret = R_CM_CTX_new(lib_ctx, R_RES_FLAG_DEF, CM_SMPL_CTX_TYPE, &ctx)) != R_ERROR_NONE) { BIO_printf(bio_out, "R_CM_CTX_new failure\n"); goto end; } /* * Read the data from cryptographic message file into the buffer. The * cryptographic message is in binary form and simply copied to a * buffer pointed to by cm_data. */ if ((ret = data_from_file(bio_out, cm_file, &cm_data, &cm_len)) != R_ERROR_NONE) { goto end; } /* * Load the cryptographic message buffer into a cryptographic message * object. Process the cryptographic message depending on the format: * - Attached Data: The data is inside the cryptographic * message. * - Detached Data: The data is detached from the cryptographic * message. * The detached data may be in a separate file or in the same file as the * cryptographic message and appended to the cryptographic message. * Furthermore the data may be wrapped (whether attached or not). These * variations need to be determined before the data can be accessed. */ if ((ret = R_CM_from_binary(ctx, R_FLAG_SHARE_DATA, R_CM_TYPE_UNKNOWN, R_CM_ENCODING_FORMAT_WRAPPED, cm_len, cm_data, &num_used, &obj)) != R_ERROR_NONE) { BIO_printf(bio_out, "From binary failure\n"); goto end; } /* * Access the data to verify. Determine where the data is and point the * msg_data structure at it. * * If the data is detached but in the same file, the data follows the * cryptographic message. Point to the data after the cryptographic message * that was just read above. * * If the data is detached but in a separate file, read the data from the * specified file. * * If the data is attached, it is inside the cryptographic message and no * further action must be taken. */ if (single == 1) { /* Set the data message with the remainder of the data */ msg_data.data = cm_data + num_used; msg_data.len = cm_len - num_used; } /* If there is any message data then read that as well */ else if (datafile != NULL) { if ((ret = data_from_file(bio_out, datafile, &data.data, &slen)) != R_ERROR_NONE) { goto end; } /* Use the data as is */ msg_data.data = data.data; msg_data.len = data.len = slen; } /* * Determine the content type of the cryptographic message. The content * type of the cryptographic message is used to determine how to handle the * attached data within the cryptographic message. Check to see if the data * is signed data. If it is, verify it. Otherwise, print the message only. */ if ((ret = R_CM_get_info(obj, R_CM_INFO_TYPE, &data_type)) != R_ERROR_NONE) { BIO_printf(bio_out, "Retrieve content type failure\n"); goto end; } else { BIO_printf(bio_out, "Content Type:%d\n",data_type); if ((ret = R_CM_TYPE_to_string(data_type, sizeof(type), (char *)type)) != R_ERROR_NONE) { BIO_printf(bio_out, "Content type string conversion failure\n"); } else { BIO_printf(bio_out, "Content Type: %s\n",type); } } /* * Load the data to be verified into a cryptographic message. See the * individual cases below. */ /* If the data is attached, obtain it from the object */ if ((datafile == NULL) && (single == 0)) { /* Attached data */ if (data_type != R_CM_TYPE_DATA) { /* If the content is not plain data access the actual message */ if ((ret = R_CM_content_to_R_CM(obj, R_FLAG_SHARE_DATA, &data_obj)) != R_ERROR_NONE) { BIO_printf(bio_out, "R_CM_content_to_R_CM failure\n"); goto end; } } else { /* * In this case a plain data message was handed to this application * so the signedData object (obj) is really the data object. */ data_obj = obj; obj = NULL; } } else if (wrap == 1) { /* * Detached and wrapped data case. If the detached data is wrapped, * strip it off. */ if ((ret = R_CM_from_binary(ctx, R_FLAG_SHARE_DATA, R_CM_TYPE_UNKNOWN, R_CM_ENCODING_FORMAT_WRAPPED, msg_data.len, msg_data.data, &num_used, &data_obj)) != R_ERROR_NONE) { BIO_printf(bio_out, "R_CM_from_binary failure\n"); goto end; } } else { /* * As the data is detached and not wrapped, create a new cryptographic * message and set the data against it. */ if ((ret = R_CM_new(ctx, R_CM_TYPE_DATA, &data_obj)) != R_ERROR_NONE) { BIO_printf(bio_out, "R_CM_new failure\n"); goto end; } /* Set the data against the object */ if ((ret = R_CM_set_info(data_obj, R_CM_INFO_DATA, &msg_data)) != R_ERROR_NONE) { BIO_printf(bio_out, "Set content data failure\n"); goto end; } } /* * Verify the cryptographic message. The actual data is in data_obj and all * the cryptographic information required to perform the verification (for * example, signer info) is in obj. */ /* Check for signed data */ if (data_type == R_CM_TYPE_SIGNED_DATA) { /* * Verify the signer data. No certificate verification is performed so * pass NULL for the store context and vfy_ctx. See cm.c and cm_adv.c * for certificate verification. */ if ((ret = R_CM_verify(obj, store_ctx, vfy_ctx, R_CM_INDEX_ALL, data_obj, &is_verified)) != R_ERROR_NONE) { BIO_printf(bio_out, "R_CM_verify failed\n"); goto end; } if (!is_verified) { ret = R_ERROR_FAILED; BIO_printf(bio_out, "Verify signer failed\n"); goto end; } } /* Print the message */ if (print == 1) { if ((ret = R_CM_write(data_obj, bio_out, R_FORMAT_TEXT, NULL, R_CM_ENCODING_FORMAT_RAW)) != R_ERROR_NONE) { BIO_printf(bio_out, "Failed to write decrypted data\n"); } } end: /* * 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_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 (cm_data != NULL) { Free(cm_data); } if (data.data != NULL) { Free(data.data); } if (obj != NULL) { R_CM_free(obj); } if (data_obj != NULL) { R_CM_free(data_obj); } if (ctx != NULL) { R_CM_CTX_free(ctx); } if (vfy_ctx != NULL) { R_VERIFY_CTX_free(vfy_ctx); } if (store_ctx != NULL) { R_CERT_STORE_CTX_free(store_ctx); } /* * The certificate context cannot be freed until the store has been emptied * as the certificates in the store hold a reference back to the * certificate context */ 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)); }