| RSA BSAFE Cert-C |
Certificate Components for C |
| Crypto-C 6.2.1 Developer's Guide | ||
| Search |
/* $Id: p12memio.c,v 1.6 2004/03/02 05:18:41 gsingh Exp $ */ /* p12memio.c ** Copyright (c) 2001-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. ** ** This file takes in a PKCS #12 message and parses it using the sample ** in-memory I/O provider. ** ** 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 "imdb.h" #include "memio.h" #include "demoutil.h" #include "p12util.h" #include "certutil.h" #include "crlutil.h" #include "keyutil.h" #include "dbutil.h" #ifdef _MSC_VER # pragma warning (disable: 171) /* invalid type conversion (often of very similar ptrs) */ #endif #define SP_COUNT 2 #define DB_NAME "In-memory DB" #define MEM_IO_NAME "Memory IO" #define OUTPUT_MEM_IO_NAME "Output Memory IO" /* Given a LIST_OBJ of PKCS12_BAGs, parse the contents and place them in the * given database SERVICE. */ static int PopulateDb (CERTC_CTX ctx, LIST_OBJ p12Bags, SERVICE db); /* Takes in a SERVICE which should be bound to a database provider instance * and outputs any certs, CRLs, and private keys to files. */ static int DumpDbContents (SERVICE db); /* This routine uses C_WriteToPKCS12 to export some arbitrary private keys, * certificates, and CRLs. */ static int GeneratePKCS12 (CERTC_CTX ctx, LIST_OBJ pkcs12Bags); int main (int argc, char *argv[]) { int status = 0; char password[RSA_DEMO_MAX_LINE_LEN]; ITEM passwordItem = {NULL, 0}; CERTC_CTX ctx = NULL; SERVICE db = NULL; LIST_OBJ p12Bags = NULL; STREAM outputStream = (STREAM)NULL_PTR; SERVICE_HANDLER spTable[SP_COUNT] = { {SPT_CRYPTO, "Default CSP", S_InitializeDefaultCSP}, {SPT_DATABASE, DB_NAME, S_InitializeMemoryDB} }; POINTER spParams[SP_COUNT] = {NULL, NULL}; ITEM pfxItem = {NULL, 0}, outputPfxItem = {NULL, 0}; FILE_LOG_PARAMS logParams = {NULL, NULL}; SERVICE_HANDLER logHandler = { SPT_LOG, "Default File Log", S_InitializeFileLog }; SERVICE_HANDLER memioHandler = { SPT_IO, MEM_IO_NAME, S_InitializeMemoryIO }; SERVICE_HANDLER outputMemioHandler = { SPT_IO, OUTPUT_MEM_IO_NAME, S_InitializeMemoryIO }; status = RSA_SetOptions (&logParams, argc, argv); if (status != 0) goto CLEANUP; RSA_PrintMessage ("PKCS #12 Example\n"); RSA_PrintMessage ("================\n"); status = C_InitializeCertC (spTable, spParams, SP_COUNT, &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_GetFileToAllocBuffer (&pfxItem.data, &pfxItem.len, "Enter name of file containing PKCS #12 binary"); if (status != 0) goto CLEANUP; status = C_RegisterService (ctx, &memioHandler, (POINTER)&pfxItem, SERVICE_ORDER_FIRST); if (status != 0) goto CLEANUP; status = C_RegisterService (ctx, &outputMemioHandler, (POINTER)&outputPfxItem, SERVICE_ORDER_FIRST); if (status != 0) goto CLEANUP; status = C_BindService (ctx, SPT_DATABASE, DB_NAME, &db); if (status != 0) goto CLEANUP; status = RSA_GetCommand (password, sizeof (password), "Enter password to decrypt private key"); if (status != 0) goto CLEANUP; status = RSA_FormatPkcs12Password (password, &passwordItem); if (status != 0) goto CLEANUP; status = C_OpenStream (ctx, MEM_IO_NAME, NULL_PTR, 0, &outputStream); if (status != 0) goto CLEANUP; status = C_CreateListObject (&p12Bags); if (status != 0) goto CLEANUP; status = C_ReadFromPKCS12 (ctx, outputStream, &passwordItem, 0, p12Bags); if (status != 0) goto CLEANUP; status = PopulateDb (ctx, p12Bags, db); if (status != 0) goto CLEANUP; status = DumpDbContents (db); if (status != 0) goto CLEANUP; RSA_PrintMessage ("\nGenerating a new PFX with the same contents...\n"); /* Given a list of PKCS #12 bags, try to write a PKCS #12 to the memory I/O provider. */ status = GeneratePKCS12 (ctx, p12Bags); if (status != 0) goto CLEANUP; CLEANUP: if (status != 0) RSA_PrintError ("pkcs12", status); T_memset ((unsigned char *)password, 0, sizeof (password)); T_memset (passwordItem.data, 0, passwordItem.len); T_free (passwordItem.data); T_free (pfxItem.data); C_DestroyListObject (&p12Bags); C_CloseStream (outputStream); C_UnbindService (&db); C_FinalizeCertC (&ctx); return status; } /* end main */ static int PopulateDb (CERTC_CTX ctx, LIST_OBJ p12Bags, SERVICE db) { int status = 0; unsigned int numBags = 0, i = 0; PKCS12_BAG *p12Bag = NULL; status = C_GetListObjectCount (p12Bags, &numBags); if (status != 0) goto CLEANUP; for (i = 0; i < numBags; i++) { status = C_GetListObjectEntry (p12Bags, i, (POINTER *)&p12Bag); if (status != 0) goto CLEANUP; switch (p12Bag->type) { case PKCS12_KEY_BAG_TYPE: RSA_PrintMessage ("Key bag detected.\n"); if (p12Bag->content.keyContent.cert != (CERT_OBJ)NULL_PTR) { status = C_InsertPrivateKey (db, p12Bag->content.keyContent.cert, p12Bag->content.keyContent.key); if (status != 0) goto CLEANUP; status = C_InsertCert (db, p12Bag->content.keyContent.cert); if (status != 0) goto CLEANUP; } else { status = RSAUTIL_InsertPrivateKey (ctx, db, p12Bag->content.keyContent.key); if (status != 0) goto CLEANUP; } break; case PKCS12_CERT_BAG_TYPE: RSA_PrintMessage ("Cert bag detected.\n"); status = C_InsertCert (db, p12Bag->content.certContent); if (status != 0) goto CLEANUP; break; case PKCS12_CRL_BAG_TYPE: RSA_PrintMessage ("CRL bag detected.\n"); status = C_InsertCRL (db, p12Bag->content.crlContent); if (status != 0) goto CLEANUP; break; case PKCS12_SECRET_BAG_TYPE: RSA_PrintMessage ("Secret bag detected.\n"); RSA_PrintBuf ("Secret Content Type", p12Bag->content.secretContent.type.data, p12Bag->content.secretContent.type.len); RSA_PrintBuf ("Secret Content Value", p12Bag->content.secretContent.value.data, p12Bag->content.secretContent.value.len); break; default: RSA_PrintMessage ("Unrecognized bag type.\n"); } } CLEANUP: if (status != 0) RSA_PrintError ("PopulateDb", status); return status; } /* end PopulateDb */ static int DumpDbContents (SERVICE db) { int status = 0; DB_ITERATOR iterator = NULL; LIST_OBJ certList = NULL, crlList = NULL; ITEM certBer = {NULL, 0}, crlBer = {NULL, 0}, privateKeyBer = {NULL, 0}; unsigned int certCount = 0, crlCount = 0, i = 0; CERT_OBJ certObj = NULL; CRL_OBJ crlObj = NULL; B_KEY_OBJ privateKeyObj = NULL; /* Create containers for certs, CRLs, and private keys */ status = C_CreateListObject (&certList); if (status != 0) goto CLEANUP; status = C_CreateListObject (&crlList); if (status != 0) goto CLEANUP; status = B_CreateKeyObject (&privateKeyObj); if (status != 0) goto CLEANUP; /* Populate the containers with the database contents. Note that if * C_SelectFirstCert is unsuccessful or when C_SelectNextCert is * unsuccessful, iterator is destroyed and set to NULL by Cert-C. * On the status==E_NOT_FOUND condition, we do not need to set status to 0 * before continuing because it is subsequently set before its value is * checked again. If that is not the case, the application may want to set * status to 0 before continuing. */ status = C_SelectFirstCert (db, &iterator, certList); if (status == E_NOT_FOUND) RSA_PrintMessage ("No certificates present.\n"); else if (status != 0) goto CLEANUP; else for (;;) { status = C_SelectNextCert (&iterator, certList); if (status == E_NOT_FOUND) break; else if (status != 0) goto CLEANUP; } /* save the certs to files */ status = C_GetListObjectCount (certList, &certCount); if (status != 0) goto CLEANUP; for (i = 0; i < certCount; i++) { status = C_GetListObjectEntry (certList, i, (POINTER *)&certObj); if (status != 0) goto CLEANUP; status = C_GetCertDER (certObj, &certBer.data, &certBer.len); if (status != 0) goto CLEANUP; RSA_PrintMessage ("\nCertificate #%u\n", i+1); status = RSA_PrintCertInfo (certObj); if (status != 0) goto CLEANUP; status = RSA_WriteDataToFile (certBer.data, certBer.len, "Enter name of file to store cert binary"); if (status == RSA_DEMO_E_CANCEL) status = 0; /* don't force user to save cert */ else if (status != 0) goto CLEANUP; } /* extract CRLs */ status = C_SelectFirstCRL (db, &iterator, crlList); if (status == E_NOT_FOUND) RSA_PrintMessage ("No CRLs present.\n"); else if (status != 0) goto CLEANUP; else for (;;) { status = C_SelectNextCRL (&iterator, crlList); if (status == E_NOT_FOUND) break; else if (status != 0) goto CLEANUP; } /* save the CRLs to files */ status = C_GetListObjectCount (crlList, &crlCount); if (status != 0) goto CLEANUP; for (i = 0; i < crlCount; i++) { status = C_GetListObjectEntry (crlList, i, (POINTER *)&crlObj); if (status != 0) goto CLEANUP; status = C_GetCRLDER (crlObj, &crlBer.data, &crlBer.len); if (status != 0) goto CLEANUP; RSA_PrintMessage ("\nCRL #%u\n", i+1); status = RSA_PrintCrlInfo (crlObj); if (status != 0) goto CLEANUP; status = RSA_WriteDataToFile (crlBer.data, crlBer.len, "Enter name of file to store CRL binary"); if (status == RSA_DEMO_E_CANCEL) status = 0; /* don't force user to save CRL */ else if (status != 0) goto CLEANUP; } /* save private keys to files */ status = C_SelectFirstPrivateKey (db, &iterator, privateKeyObj); if (status == E_NOT_FOUND) { RSA_PrintMessage ("No private keys present.\n"); status = 0; } else if (status != 0) goto CLEANUP; else for (i = 0;; i++) { status = RSA_GetKeyBer (RSA_DEMO_PRIVATE_KEY, privateKeyObj, &privateKeyBer); if (status != 0) goto CLEANUP; RSA_PrintMessage ("\nPrivate Key #%u\n", i+1); status = RSA_WriteDataToFile (privateKeyBer.data, privateKeyBer.len, "Enter name of file to store private key binary"); if (status == RSA_DEMO_E_CANCEL) status = 0; /* don't force user to save key */ if (status != 0) goto CLEANUP; B_DestroyKeyObject (&privateKeyObj); status = B_CreateKeyObject (&privateKeyObj); if (status != 0) goto CLEANUP; status = C_SelectNextPrivateKey (&iterator, privateKeyObj); if (status == E_NOT_FOUND) { status = 0; break; } else if (status != 0) goto CLEANUP; } CLEANUP: if (status != 0) RSA_PrintError ("DumpDbContents", status); T_memset (privateKeyBer.data, 0, privateKeyBer.len); T_free (privateKeyBer.data); B_DestroyKeyObject (&privateKeyObj); C_FreeIterator (&iterator); C_DestroyListObject (&certList); C_DestroyListObject (&crlList); return status; } /* end DumpDbContents */ /* This routine uses C_WriteToPKCS12 to export some arbitrary private keys, * certificates, and CRLs. */ static int GeneratePKCS12 (CERTC_CTX ctx, LIST_OBJ pkcs12Bags) { int status = 0; char userInput[RSA_DEMO_MAX_LINE_LEN]; unsigned char outputBlock[100]; unsigned int outputLen = 0; FILE *outputFile = NULL; STREAM outputStream = NULL; int encryptionAlg = 0, macDigest = 0; int iterationCount = 0, exportOptions = 0; ITEM password = {NULL, 0}; status = RSA_Pkcs12EncryptionAlgPrompt (&encryptionAlg); if (status != 0) goto CLEANUP; status = RSA_Pkcs12FormatOptionsPrompt (&exportOptions); if (status != 0) goto CLEANUP; RSA_PrintMessage ("Using SHA-1 HMAC. Recommended iteration count "); RSA_PrintMessage ("is 1024.\n"); macDigest = DAI_SHA1; status = RSA_GetInteger (&iterationCount, "Specify an integer for the iteration count"); if (status == RSA_DEMO_E_CANCEL) iterationCount = PKCS12_DEFAULT_ITERATIONS; else if (status != 0) goto CLEANUP; status = RSA_GetCommand (userInput, sizeof (userInput), "Supply password to protect PKCS #12 contents"); if (status != 0) goto CLEANUP; status = RSA_FormatPkcs12Password (userInput, &password); if (status != 0) goto CLEANUP; T_memset ((POINTER)userInput, 0, sizeof (userInput)); status = C_OpenStream (ctx, OUTPUT_MEM_IO_NAME, NULL_PTR, 0, &outputStream); if (status != 0) goto CLEANUP; status = C_WriteToPKCS12 (ctx, pkcs12Bags, encryptionAlg, macDigest, iterationCount, exportOptions, &password, outputStream); if (status != 0) goto CLEANUP; status = RSA_OpenDataFilePrompt (&outputFile, RSA_DEMO_WRITE_BINARY, "Enter name of file to output PFX file"); if (status != 0) goto CLEANUP; for (;;) { status = C_ReadStream (outputStream, outputBlock, sizeof (outputBlock), &outputLen); if (status == E_EOS) { status = 0; break; } else if (status != 0) goto CLEANUP; status = RSA_AppendDataToFile (outputFile, outputBlock, outputLen); if (status != 0) goto CLEANUP; } CLEANUP: if (status != 0) RSA_PrintError ("GeneratePKCS12", status); T_memset (password.data, 0, password.len); T_free (password.data); C_CloseStream (outputStream); RSA_CloseDataFile (&outputFile); return status; } /* end GeneratePKCS12 */