| RSA BSAFE Cert-C |
Certificate Components for C |
| Crypto-C 6.2.1 Developer's Guide | ||
| Search |
datamsg sample. Finds the first matching certificate and private key to use for signing. A real application could present the user with a choice of certificates/keys to use for signing.
/* $Id: pkcs11msg.c,v 1.4 2004/03/02 05:18:42 gsingh Exp $ */ /* pkcs11msg.c ** Copyright (c) 2000-2003, RSA Security Inc. ** ** This file is used to demonstrate how to interface to an RSA Security ** licensed development product. You have a royalty-free right to use, ** modify, reproduce and distribute this demonstration file (including ** any modified version), provided that you agree that RSA Security has ** no warranty, implied or otherwise, or liability for this demonstration ** file or any modified version. ** ** Create a PKCS #7 signed data message using a private key accessed on a ** token using PKCS #11. This signed data message should be able to be ** verified using the datamsg sample. ** ** You can use the samples/db/pkcs11db sample to put a private key and ** matching self-signed cert onto the device. ** ** This sample just finds the first matching cert and private key to use ** for signing. A real application could present the user with a choice ** of certs/keys to use for signing. ** ** When compiling, define the macro RSA_REQUIRE_FILE_LOG (-D compile ** option, or equivelent) to force the program to return an error code ** if file logging cannot be initialized. For example, if the file ** containing the log message format strings cannot be located (certc.msg ** or equivalent). */ #include "certc.h" #include "filelog.h" #include "rsacsp.h" #include "demoutil.h" #include "p7util.h" #include "p11util.h" #include "keyutil.h" #ifdef _MSC_VER # pragma warning (disable: 171) /* invalid type conversion (often of very similar ptrs) */ #endif /* Identifier for PKCS #11 database instance */ #define P11_DB_NAME "Sample PKCS #11 Database" /* This routine takes a SERVICE containing a PKCS #11 database source, a * cert object and key object which have been created but not initialized, * and finds a matching cert and private key to place in those objects. * A real application would do a better job of selection, but for the purposes * of this example, we just get a private key and matching cert. */ static int GetCertAndPrivateKey (SERVICE db, CERT_OBJ cert, B_KEY_OBJ privateKey); int main (int argc, char *argv[]) { int status = 0; CERTC_CTX ctx = NULL; SERVICE db = NULL; B_KEY_OBJ signerPrivateKey = NULL; CERT_OBJ signerCert = NULL; CERT_FIELDS certFields; LIST_OBJ signerInfos = NULL; SIGNER_INFO signerInfo; ITEM signedAttribBer = {NULL, 0}, unsignedAttribBer = {NULL, 0}; ITEM fileContents = {NULL, 0}, dataMsg = {NULL, 0}, signedMsg = {NULL, 0}; FILE_LOG_PARAMS logParams = {NULL, NULL}; SERVICE_HANDLER logHandler = { SPT_LOG, "Default File Log", S_InitializeFileLog }; B_PKCS11_SESSION p11SessionInfo; PKCS11_INIT_PARAMS p11InitParams; PKCS11_CRYPTO_PARAMS p11CryptoParams; SERVICE_HANDLER p11DbServiceHandler = { SPT_DATABASE, P11_DB_NAME, S_InitializePKCS11DB }; SERVICE_HANDLER p11CryptoServiceHandler = { SPT_CRYPTO, "Crypto Provider with PKCS #11", S_InitializeDefaultCSP2 }; char *libraryName = NULL; ITEM tokenLabel = {NULL, 0}, passphrase = {NULL, 0}; /* Initialize variables for graceful error-handling */ T_memset ((POINTER)&p11InitParams, 0, sizeof (p11InitParams)); T_memset ((POINTER)&p11SessionInfo, 0, sizeof (p11SessionInfo)); T_memset ((POINTER)&p11CryptoParams, 0, sizeof (p11CryptoParams)); T_memset ((POINTER)&signerInfo, 0, sizeof (signerInfo)); status = RSA_SetOptions (&logParams, argc, argv); if (status != 0) goto CLEANUP; RSA_PrintMessage ("Using PKCS #11 Device for Signing Data Example\n"); RSA_PrintMessage ("==============================================\n"); status = C_InitializeCertC (NULL, NULL, 0, &ctx); if (status != 0) goto CLEANUP; /* Attempt to initialize file logging, but unless RSA_REQUIRE_FILE_LOG is * defined, treat it as a non-fatal condition. */ status = C_RegisterService (ctx, &logHandler, (POINTER)&logParams, SERVICE_ORDER_FIRST); #ifdef RSA_REQUIRE_FILE_LOG if (status != 0) goto CLEANUP; #endif status = RSA_Pkcs11InfoPrompt (&libraryName, &tokenLabel, &passphrase); if (status != 0) goto CLEANUP; p11SessionInfo.libraryName = libraryName; p11SessionInfo.tokenLabel.data = tokenLabel.data; p11SessionInfo.tokenLabel.len = tokenLabel.len; p11SessionInfo.passPhrase.data = passphrase.data; p11SessionInfo.passPhrase.len = passphrase.len; p11InitParams.pPKCS11Info = &p11SessionInfo; status = C_RegisterService (ctx, &p11DbServiceHandler, (POINTER)&p11InitParams, SERVICE_ORDER_LAST); if (status != 0) goto CLEANUP; RSA_PrintMessage ("Registration of PKCS #11 DB provider successful.\n"); /* Currently, only one connection per chooser (crypto service provider instance) is supported */ p11CryptoParams.pSessionInfo = &p11SessionInfo; p11CryptoParams.sessionCount = 1; status = C_RegisterService (ctx, &p11CryptoServiceHandler, (POINTER)&p11CryptoParams, SERVICE_ORDER_LAST); if (status != 0) goto CLEANUP; RSA_PrintMessage ("Registration of Crypto Provider with PKCS #11 successful.\n"); status = C_BindService (ctx, SPT_DATABASE, P11_DB_NAME, &db); if (status != 0) goto CLEANUP; status = C_CreateCertObject (&signerCert, ctx); if (status != 0) goto CLEANUP; status = B_CreateKeyObject (&signerPrivateKey); if (status != 0) goto CLEANUP; status = GetCertAndPrivateKey (db, signerCert, signerPrivateKey); if (status != 0) goto CLEANUP; /* Obtain data to sign, which must be a PKCS #7 message of some type */ status = RSA_GetFileToAllocBuffer (&fileContents.data, &fileContents.len, "Enter name of file to sign"); if (status != 0) goto CLEANUP; status = C_WriteDataMsg (ctx, &fileContents, &dataMsg); if (status != 0) goto CLEANUP; /* Don't need fileContents any more... */ T_free (fileContents.data); fileContents.data = NULL; /* Set up signer information */ status = C_CreateListObject (&signerInfos); if (status != 0) goto CLEANUP; status = C_GetCertFields (signerCert, &certFields); if (status != 0) goto CLEANUP; signerInfo.signerCertId.type = ISSUER_SERIAL; signerInfo.signerCertId.id.issuerSerialNumber.issuerName = certFields.issuerName; signerInfo.signerCertId.id.issuerSerialNumber.serialNumber = certFields.serialNumber; /* Fill in the signer's digest algorithm and "signature" algorithm. Note * that the digest algorithm can be either MD5 or SHA1 and the "signature" * algorithm, which specifies the operation performed on the digest, can * either be RSA Encryption or DSA with SHA1. */ status = RSA_SignerInfoSignatureAlgPrompt (&signerInfo.digestAlgorithmId, &signerInfo.signatureAlgorithmId); if (status != 0) goto CLEANUP; /* prompt for attributes to be signed - this is optional * If RSA_GetFileToAllocBuffer returns RSA_DEMO_E_CANCEL, * signerInfo.signedAttributes will remain NULL. */ RSA_PrintMessage ("\nOptionally supply an attributes object to be "); RSA_PrintMessage ("authenticated attributes.\nEnter name of file "); RSA_PrintMessage ("containing attributes object, or blank to omit:\n"); status = RSA_GetFileToAllocBuffer (&signedAttribBer.data, &signedAttribBer.len, NULL); if (status != 0 && status != RSA_DEMO_E_CANCEL) goto CLEANUP; else if (status == 0) { status = C_CreateAttributesObject (&signerInfo.signedAttributes); if (status != 0) goto CLEANUP; status = C_SetAttributesBER (signerInfo.signedAttributes, signedAttribBer.data, signedAttribBer.len); if (status != 0) goto CLEANUP; } /* prompt for attributes which will not be signed - this is optional * If RSA_GetFileToAllocBuffer returns RSA_DEMO_E_CANCEL, * signerInfo.unsignedAttributes will remain NULL. */ RSA_PrintMessage ("\nOptionally supply unauthenticated attributes.\n"); RSA_PrintMessage ("Enter name of file containing attributes object, or "); RSA_PrintMessage ("blank to omit:\n"); status = RSA_GetFileToAllocBuffer (&unsignedAttribBer.data, &unsignedAttribBer.len, NULL); if (status != 0 && status != RSA_DEMO_E_CANCEL) goto CLEANUP; else if (status == 0) { status = C_CreateAttributesObject (&signerInfo.unsignedAttributes); if (status != 0) goto CLEANUP; status = C_SetAttributesBER (signerInfo.unsignedAttributes, unsignedAttribBer.data, unsignedAttribBer.len); if (status != 0) goto CLEANUP; } /* Other possibilities are C_AddUniqueSignerToList and * C_InsertSignerInList. */ status = C_AddSignerToList (signerInfos, &signerInfo, NULL); if (status != 0) goto CLEANUP; status = C_WriteSignedDataMsg (ctx, NULL, db, &dataMsg, CMSF_NONE, NULL, NULL, signerInfos, &signedMsg); if (status != 0) goto CLEANUP; /* Don't need data message any more... */ T_free (dataMsg.data); dataMsg.data = NULL; status = RSA_WriteDataToFile (signedMsg.data, signedMsg.len, "Enter name of file to store signed data message"); CLEANUP: if (status != 0) RSA_PrintError ("pkcs11msg", status); else RSA_PrintMessage ("Success!\n"); T_memset (passphrase.data, 0, passphrase.len); T_free ((POINTER)libraryName); T_free (tokenLabel.data); T_free (passphrase.data); T_free (signedAttribBer.data); T_free (unsignedAttribBer.data); T_free (fileContents.data); T_free (dataMsg.data); T_free (signedMsg.data); C_DestroyAttributesObject (&signerInfo.signedAttributes); C_DestroyAttributesObject (&signerInfo.unsignedAttributes); C_DestroyListObject (&signerInfos); B_DestroyKeyObject (&signerPrivateKey); C_DestroyCertObject (&signerCert); C_UnbindService (&db); C_FinalizeCertC (&ctx); return status; } /* end main */ /* See function declaration at the top for a description */ static int GetCertAndPrivateKey (SERVICE db, CERT_OBJ cert, B_KEY_OBJ privateKey) { int status = 0; DB_ITERATOR iterator = NULL; LIST_OBJ certList = NULL; CERT_OBJ currentCert = NULL; ITEM currentCertBer = {NULL, 0}; status = C_CreateListObject (&certList); if (status != 0) goto CLEANUP; status = C_SelectFirstCert (db, &iterator, certList); if (iterator == NULL) { RSA_PrintMessage ("Database empty - no certs present.\n"); status = 0; goto CLEANUP; } else if (status != 0) goto CLEANUP; for (;;) { /* We're done if there's a private key corresponding to the cert we've found */ status = C_GetListObjectEntry (certList, 0, (POINTER *)¤tCert); if (status != 0) goto CLEANUP; status = C_SelectPrivateKeyByCert (db, currentCert, privateKey); if (status == 0) { /* we're done - copy the resulting cert */ status = C_GetCertDER (currentCert, ¤tCertBer.data, ¤tCertBer.len); if (status != 0) goto CLEANUP; status = C_SetCertBER (cert, currentCertBer.data, currentCertBer.len); if (status != 0) goto CLEANUP; RSA_PrintMessage ("Found cert and private key...\n"); break; } /* Clear the certList and try again with the next cert */ C_ResetListObject (certList); status = C_SelectNextCert (&iterator, certList); if (status != 0) { RSA_PrintMessage ("Could not find cert and private key.\n"); goto CLEANUP; } RSA_PrintMessage ("Retrieving another cert from database...\n"); } CLEANUP: if (status != 0) RSA_PrintError ("GetCertAndPrivateKey", status); C_DestroyListObject (&certList); C_FreeIterator (&iterator); return status; } /* end GetCertAndPrivateKey */