RSA BSAFE Micro Edition Suite

Streamlined security for mobile and embedded devices

Search  Print

store.c

/* $Id: store.c,v 1.48 2005/08/08 05:33:32 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"

static char *store_usage[]={
"usage: store [options]\n",
"where options are:\n",
" -certs list          - The List of certificates (colon separated)\n",
#ifndef NO_WTLSCERT
" -certenc encoding    - Encode the certificates - one of X509 (default),",
" WTLS\n",
#else /* NO_WTLSCERT */
" -certenc encoding    - Encode the certificates - one of X509 (default)\n",
#endif /* !NO_WTLSCERT */
#ifdef NO_PEM
" -certform format     - The format of the certificates (BIN only)\n",
#else
" -certform format     - The format of the certificates",
" - one of BIN (default), PEM\n",
#endif /* NO_PEM */
" -certtype type       - The type of the certificate - one of CM, CVC or CA\n",
" -certstatus status   - The status of the certificates",
" - one of TRUST, UNTRUST, CHAIN\n",
" -lookup cert         - The certificate to look up\n",
#ifdef NO_PEM
" -lookupform format   - The format of the certificate (BIN only)\n",
#else
" -lookupform format   - The format of the certificate",
" - one of BIN (default), PEM\n",
#endif /* NO_PEM */
" -lookuptype type     - The type of the certificate to look up",
" - one of CM, CVC or CA\n",
" -lookupstatus status - The new status of the certificate to look up",
" - one of TRUST,UNTRUST, CHAIN\n",
#ifdef NO_SOFTWARE_CRYPTO
" -no_fips140          - Use non FIPS140 crypto implementations\n",
#endif /* NO_SOFTWARE_CRYPTO */
NULL
};

int main(int argc, char **argv)
{
    int ret = R_ERROR_NONE;
    R_RES_LIST *res_list;
    R_LIB_CTX *lib_ctx = NULL;
    R_CERT_STORE_CTX *ctx = NULL;
    R_CERT_CTX *cert_ctx = NULL;
    R_CERT_STORE *obj = NULL;
    R_CERT *cert = NULL, *lookup = NULL;
    R_PKEY *pubkey = NULL;
    R_CERT_NAME *name = NULL;
    BIO *bio_out = NULL;
    char *certfile, *lookupfile, *str;
    R_CERT_TYPE certenc;
    int certtype;
    R_FORMAT certform;
    int certstatus, lookuptype;
    R_FORMAT lookupform;
    int lookupstatus, state;

    /* Set the defaults */
    certfile     = NULL;
    lookupfile   = NULL;
    certenc      = R_CERT_TYPE_X509;
    certform     = R_FORMAT_BINARY;
    certtype     = R_CERT_STORE_ANY_CERTIFICATE;
    certstatus   = R_CERT_STORE_STATE_TRUSTED_CERTIFICATE;
    lookupform   = R_FORMAT_BINARY;
    lookuptype   = R_CERT_STORE_ANY_CERTIFICATE;
    lookupstatus = R_CERT_STORE_STATE_TRUSTED_CERTIFICATE;

    res_list = PRODUCT_DEFAULT_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.
     */
    bio_out = BIO_new_fp(stdout, BIO_NOCLOSE);
    if (bio_out == 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,"-certs") == 0)
        {
            if (--argc < 1)
            {
                goto bad;
            }

            certfile = *(++argv);
        }
        else if (Strcmp(*argv,"-certenc") == 0)
        {
            if (--argc < 1)
            {
                goto bad;
            }

            str = *(++argv);

            /*
             * Convert the certificate's encoding string to its integer value
             */
            if ((ret = R_CERT_TYPE_from_string(str, &certenc)) != R_ERROR_NONE)
            {
                BIO_printf(bio_out, "Unknown encoding %s\n", str);
                goto bad;
            }
        }
        else if (Strcmp(*argv,"-certform") == 0)
        {
            if (--argc < 1)
            {
                goto bad;
            }

            str = *(++argv);

            /* Convert the certificate's format string to its integer value */
            if ((ret = R_FORMAT_from_string(str, &certform)) != R_ERROR_NONE)
            {
                BIO_printf(bio_out, "Unknown format %s\n", str);
                goto bad;
            }
        }
        else if (Strcmp(*argv,"-certtype") == 0)
        {
            if (--argc < 1)
            {
                goto bad;
            }

            str = *(++argv);

            /* Convert the certificate's type string to its integer value */
            if ((ret = R_CERT_STORE_cert_type_from_string(str,
                &certtype)) != R_ERROR_NONE)
            {
                BIO_printf(bio_out, "Unknown type %s\n", str);
                goto bad;
            }
        }
        else if (Strcmp(*argv,"-certstatus") == 0)
        {
            if (--argc < 1)
            {
                goto bad;
            }

            str = *(++argv);

            /* Convert the certificate's status string to its integer value */
            if ((R_CERT_STORE_STATE_from_string(str, &certstatus)) !=
                 R_ERROR_NONE)
            {
                BIO_printf(bio_out, "Unknown status %s\n", str);
                goto bad;
            }
        }
        else if (Strcmp(*argv,"-lookup") == 0)
        {
            if (--argc < 1)
            {
                goto bad;
            }

            lookupfile = *(++argv);
        }
        else if (Strcmp(*argv,"-lookupform") == 0)
        {
            if (--argc < 1)
            {
                goto bad;
            }

            str = *(++argv);

            /*
             * Convert the lookup certificate's format string to its integer
             * value
             */
            if ((ret = R_FORMAT_from_string(str, &lookupform)) != R_ERROR_NONE)
            {
                BIO_printf(bio_out, "Unknown format %s\n", str);
                goto bad;
            }
        }
        else if (Strcmp(*argv,"-lookuptype") == 0)
        {
            if (--argc < 1)
            {
                goto bad;
            }

            str = *(++argv);

            /*
             * Convert the lookup certificate's type string to its integer
             * value
             */
            if ((ret = R_CERT_STORE_cert_type_from_string(str, &lookuptype)) !=
                R_ERROR_NONE)
            {
                BIO_printf(bio_out, "Unknown type %s\n", str);
                goto bad;
            }
        }
        else if (Strcmp(*argv,"-lookupstatus") == 0)
        {
            if (--argc < 1)
            {
                goto bad;
            }

            str = *(++argv);

            /*
             * Convert the lookup certificate's status string to its integer
             * value
             */
            if ((R_CERT_STORE_STATE_from_string(str, &lookupstatus)) !=
                R_ERROR_NONE)
            {
                BIO_printf(bio_out, "Unknown status %s\n", str);
                goto bad;
            }
        }
#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++;
    }

    /* Perform simple checks first */
    if ((certfile == NULL) || (lookupfile == NULL))
    {
        BIO_printf(bio_out, "Both -certs and -lookup are required\n");
        goto bad;
    }

    /* Display the help menu if an invalid command line option was entered */
    if (0)
    {
        char **pp;
bad:
        for (pp = store_usage; (*pp) != NULL; pp++)
        {
            BIO_printf(bio_out, *pp);
        }

        goto end;
    }

    /*
     * 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(res_list, R_RES_FLAG_DEF, &lib_ctx)) !=
        R_ERROR_NONE)
    {
        BIO_printf(bio_out, "Library new failure\n");
        goto end;
    }

    /*
     * Create a new certificate store context. The certificate store context
     * contains the repository that holds the certificates that are added to
     * the store.
     */
    if ((ret = R_CERT_STORE_CTX_new(lib_ctx, R_RES_FLAG_DEF, &ctx)) !=
        R_ERROR_NONE)
    {
        BIO_printf(bio_out, "Store context new failure\n");
        goto end;
    }

    /*
     * Create a certificate context. All certificate operations require a
     * certificate context (#R_CERT_CTX). This context provides access to the
     * certificate functionality.
     */
    if ((ret = R_CERT_CTX_new(lib_ctx, R_RES_FLAG_DEF, certenc,
        &cert_ctx)) != R_ERROR_NONE)
    {
        BIO_printf(bio_out, "Certificate context new failure\n");
        goto end;
    }

    /*
     * Create a new store object. The store object can be used to interact with
     * the certificate store. For example, the store object is used to add
     * certificates to the store.
     */
    if ((ret = R_CERT_STORE_new(ctx, &obj)) != R_ERROR_NONE)
    {
        BIO_printf(bio_out, "Store object new failure\n");
        goto end;
    }

    /*
     * Process all certificates. The following loop reads in all the
     * certificates, sets their trust level and type, and adds them to the
     * store repository using the certificate store object created above.
     */
    str = strtok(certfile, ":");
    while (str != NULL)
    {
        /* Read the certificate from file */
        if ((ret = R_CERT_read_file(cert_ctx, str, certenc, certform,
                                    &cert)) != R_ERROR_NONE)
        {
            BIO_printf(bio_out, "Certificate from file failure: %s\n", str);
            goto end;
        }

        /* Sets the certificate into the store object */
        if ((ret = R_CERT_STORE_set_cert(obj, cert, NULL)) != R_ERROR_NONE)
        {
            BIO_printf(bio_out, "Add certificate failure\n");
            goto end;
        }
        /*
         * The store object now owns the certificate and therefore the
         * application does not need to free it
         */
        cert = NULL;

        /* Set the trust level of the certificate */
        if ((ret = R_CERT_STORE_set_cert_state(obj, certstatus)) !=
            R_ERROR_NONE)
        {
            BIO_printf(bio_out, "Set trust failure\n");
            goto end;
        }

        /* Set the class of the certificate */
        if ((ret = R_CERT_STORE_set_cert_class(obj, certtype)) != R_ERROR_NONE)
        {
            BIO_printf(bio_out, "Set class failure\n");
            goto end;
        }

        /* Add the certificate into the store repository */
        if ((ret = R_CERT_STORE_add(obj)) != R_ERROR_NONE)
        {
            BIO_printf(bio_out, "Add certificate failure\n");
            goto end;
        }

        /* Initialize the store object for the next certificate */
        if ((ret = R_CERT_STORE_init(obj)) != R_ERROR_NONE)
        {
            BIO_printf(bio_out, "Initializing store object failure\n");
            goto end;
        }

        /* Retrieve the next file */
        str = strtok(NULL, ":");
    }

    /* Read the certificate to look up */
    if ((ret = R_CERT_read_file(cert_ctx, lookupfile, certenc, lookupform,
                                &lookup)) != R_ERROR_NONE)
    {
        BIO_printf(bio_out, "Certificate from file failure: %s\n", lookupfile);
        goto end;
    }

    /*
     * Search the store repository by issuer name. Extract the issuer name from
     * the certificate being searched for.
     */
    BIO_printf(bio_out, "Finding certificate by issuer name...");

    /* Access the issuer name in order to do the find operation */
    ret = R_CERT_issuer_name_to_R_CERT_NAME(lookup, R_FLAG_SHARE_DATA, &name);

    if (ret == R_ERROR_NONE)
    {
        ret = R_CERT_STORE_find_entry_by_issuer(obj, name, lookuptype);
    }

    /* As the data is by reference, free the R_CERT_NAME structure */
    R_CERT_NAME_free(name);
    name = NULL;

    if (ret == R_ERROR_NONE)
    {
        BIO_printf(bio_out, " found\n");
    }
    else
    {
        BIO_printf(bio_out," not found\n");
    }

    /*
     * Search the store repository by subject name. Extract the subject name
     * from the certificate being searched for.
     */
    BIO_printf(bio_out, "Finding certificate by subject name...");

    /* Access the subject name in order to do the find operation */
    ret = R_CERT_subject_name_to_R_CERT_NAME(lookup, R_FLAG_SHARE_DATA, &name);

    if (ret == R_ERROR_NONE)
    {
        ret = R_CERT_STORE_find_entry_by_subject(obj, name, lookuptype);
    }

    /* As the data is by reference, free the R_CERT_NAME structure */
    R_CERT_NAME_free(name);
    name = NULL;

    if (ret == R_ERROR_NONE)
    {
        BIO_printf(bio_out, " found\n");
    }
    else
    {
        BIO_printf(bio_out, " not found\n");
    }

    /*
     * Search the store repository by public key. Extract the public key from
     * the certificate being searched for.
     */
    BIO_printf(bio_out, "Finding certificate by public key...");

    /* Access the public key in order to do the find operation */
    ret = R_CERT_public_key_to_R_PKEY(lookup, R_FLAG_SHARE_DATA, &pubkey);

    if (ret == R_ERROR_NONE)
    {
        ret = R_CERT_STORE_find_entry_by_pubkey(obj, pubkey, lookuptype);
    }

    if (ret == R_ERROR_NONE)
    {
        BIO_printf(bio_out, " found\n");
    }
    else
    {
        BIO_printf(bio_out, " not found\n");
    }

    /*
     * Change the state of a certificate in the store. This part of the sample
     * demonstrates how to manipulate the state of a certificate in the store
     * repository. This sample:
     *     - Retrieves the state of the certificate that was found previously.
     *     - Sets a new state for the certificate.
     *     - Updates the new state for the certificate in the store repository.
     *     - Retrieves the state of the certificate from the repository.
     *     - Checks that the status has changed.
     */
    BIO_printf(bio_out, "Retrieving the current state...");

    if ((ret = R_CERT_STORE_get_cert_state(obj, &state)) != R_ERROR_NONE)
    {
        BIO_printf(bio_out, "\nRetrieve state failure\n");
        goto end;
    }

    BIO_printf(bio_out, "found %d\n", state);

    /* Set a new state */
    if ((ret = R_CERT_STORE_set_cert_state(obj, lookupstatus)) != R_ERROR_NONE)
    {
        BIO_printf(bio_out, "Set state failure\n");
        goto end;
    }

    /* Update the new state into the store context */
    if ((ret = R_CERT_STORE_update(obj)) != R_ERROR_NONE)
    {
        BIO_printf(bio_out, "Update failure\n");
        goto end;
    }

    BIO_printf(bio_out, "Retrieving new state...");

    /*
     * Retrieve the store object again from the context and check that
     * the state has changed
     */
    if ((ret = R_CERT_STORE_find_entry_by_pubkey(obj, pubkey,
        lookuptype)) != R_ERROR_NONE)
    {
        BIO_printf(bio_out, "Failed to look up the certificate in store\n");
        goto end;
    }

    /* Retrieve the state from the store and check it has been updated */
    if ((ret = R_CERT_STORE_get_cert_state(obj, &state)) != R_ERROR_NONE)
    {
        BIO_printf(bio_out, "\nRetrieve state failure\n");
        goto end;
    }

    BIO_printf(bio_out, "found %d\n", state);

    if (state != lookupstatus)
    {
        ret = R_ERROR_FAILED;
        BIO_printf(bio_out, "Failed to update store context state\n");
        goto end;
    }

    /*
     * Delete the certificate object from the store context. Confirm that the
     * certificate was deleted by looking it up again and confirming that it
     * was not found.
     */
    if ((ret = R_CERT_STORE_delete(obj)) != R_ERROR_NONE)
    {
        BIO_printf(bio_out,"Remove certificate failure\n");
        goto end;
    }

    /* Attempt to retrieve the removed object from the store context */
    ret = R_CERT_STORE_find_entry_by_pubkey(obj, pubkey, lookuptype);
    if (ret != R_ERROR_NOT_FOUND)
    {
        ret = R_ERROR_FAILED;
        BIO_printf(bio_out, "Failed to delete object from store context\n");
    }
    else
    {
        ret = R_ERROR_NONE;
    }

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));
    }

    /* Clean up all objects and contexts */
    if (pubkey != NULL)
    {
        R_PKEY_free(pubkey);
    }
    if (name != NULL)
    {
        R_CERT_NAME_free(name);
    }
    if (cert != NULL)
    {
        R_CERT_free(cert);
    }
    if (lookup != NULL)
    {
        R_CERT_free(lookup);
    }
    if (obj != NULL)
    {
        R_CERT_STORE_free(obj);
    }
    if (ctx != NULL)
    {
        R_CERT_STORE_CTX_free(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));
}


Copyright (c) 1999-2005 RSA Security Inc. All rights reserved. 072-001001-2100-001-000 - 2.1