| RSA BSAFE Cert-C |
Certificate Components for C |
| Crypto-C 6.2.1 Developer's Guide | ||
| Search |
/* $Id: pkcs12exp.c,v 1.4 2004/03/02 05:18:41 gsingh Exp $ */ /* pkcs12exp.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. ** ** Demonstrate how to use Cert-C to create a PKCS #12 message in order ** to export a password-protected private key and its associated certificates ** and CRLs. ** ** 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 "pkixpath.h" #include "crlstat.h" #include "fileio.h" #include "demoutil.h" /* demo code */ #include "p12util.h" /* demo code */ #include "certutil.h" /* demo code */ #include "crlutil.h" /* demo code */ #ifdef _MSC_VER # pragma warning (disable: 171) /* invalid type conversion (often of very similar ptrs) */ #endif /* This routine uses C_ExportPKCS12 to export a private key and corresponding * certificate chain. */ static int ExportKeyAndCert (CERTC_CTX ctx); /* This routine uses C_WriteToPKCS12 to export some arbitrary private keys, * certificates, and CRLs. */ static int GeneratePKCS12 (CERTC_CTX ctx); /* The number of service providers used in this example. Here, we must * register a crypto service provider. */ #define SP_COUNT 5 #define DATABASE_NAME "PKCS #12 export database" #define STREAM_SP_NAME "Sample File I/O" int main (int argc, char *argv[]) { int status = 0; char command[RSA_DEMO_MAX_LINE_LEN]; CERTC_CTX ctx = NULL; SERVICE_HANDLER spTable[SP_COUNT] = { {SPT_CRYPTO, "Crypto Provider", S_InitializeDefaultCSP}, {SPT_DATABASE, DATABASE_NAME, S_InitializeMemoryDB}, {SPT_CERT_PATH, "Cert Path Processing Provider", S_InitializePKIXPath}, {SPT_CERT_STATUS, "Revocation Status Provider", S_InitializeCRLStatus}, {SPT_IO, STREAM_SP_NAME, S_InitializeFileIO} }; POINTER spParams[SP_COUNT] = { NULL, NULL, NULL, NULL, NULL }; FILE_LOG_PARAMS logParams = {NULL, NULL}; SERVICE_HANDLER logHandler = { SPT_LOG, "Default File Log", S_InitializeFileLog }; status = RSA_SetOptions (&logParams, argc, argv); if (status != 0) goto CLEANUP; 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 RSA_PrintMessage ("PKCS #12 Export Example\n"); RSA_PrintMessage ("=======================\n"); for (;;) { RSA_PrintMessage ("\nPKCS #12 Export Operations\n"); RSA_PrintMessage (" A - Export a private key and certificate chain\n"); RSA_PrintMessage (" B - Create an arbitrary PKCS #12 message\n"); status = RSA_GetCommand (command, sizeof (command), "Enter choice (blank to quit)"); if (status != 0) goto CLEANUP; switch (command[0]) { case 'a': case 'A': status = ExportKeyAndCert (ctx); break; case 'b': case 'B': status = GeneratePKCS12 (ctx); break; case '\0': case 'q': case 'Q': goto CLEANUP; default: RSA_PrintMessage ("Unrecognized Option: %c\n", command[0]); status = RSA_DEMO_E_INVALID_PARAMETER; } if (status != 0) RSA_PrintMessage ("Operation not completed.\n"); else RSA_PrintMessage ("Operation successful!\n"); } CLEANUP: if (status != 0) RSA_PrintError ("pkcs12exp.c", status); C_FinalizeCertC (&ctx); return status; } /* end main */ /* This routine uses C_ExportPKCS12 to export a private key and corresponding * certificate chain. */ static int ExportKeyAndCert (CERTC_CTX ctx) { int status = 0; char userInput[RSA_DEMO_MAX_LINE_LEN]; char filename[RSA_DEMO_MAX_LINE_LEN]; CERT_OBJ certObj = NULL; CERT_FIELDS certFields; NAME_OBJ subjectName = NULL; B_KEY_OBJ privateKey = NULL; LIST_OBJ trustedCerts = NULL, crlList = NULL; unsigned int numCrls = 0; SERVICE database = NULL; CERT_PATH_CTX pathCtx; int encryptionAlg = 0, macDigest = 0; int iterationCount = 0, exportOptions = 0; ITEM macPassword = {NULL, 0}, encPassword = {NULL, 0}; T_memset ((POINTER)&pathCtx, 0, sizeof (pathCtx)); RSA_PrintMessage ("Supply the keypair to enclose in the PKCS #12 message "); RSA_PrintMessage ("in the form of a\nbinary BER-encoded X.509 certificate"); RSA_PrintMessage (" and a binary PKCS #8 PrivateKeyInfo.\n"); status = C_BindService (ctx, SPT_DATABASE, DATABASE_NAME, &database); if (status != 0) goto CLEANUP; status = C_CreateCertObject (&certObj, ctx); if (status != 0) goto CLEANUP; status = B_CreateKeyObject (&privateKey); if (status != 0) goto CLEANUP; /* Collect private key and corresponding certificate for PKCS #12 message */ status = RSA_GetCertAndPvtKey (ctx, certObj, privateKey); if (status != 0) goto CLEANUP; status = C_InsertCert (database, certObj); if (status != 0) goto CLEANUP; status = C_InsertPrivateKey (database, certObj, privateKey); if (status != 0) goto CLEANUP; status = C_GetCertFields (certObj, &certFields); if (status != 0) goto CLEANUP; subjectName = certFields.subjectName; /* Collect other certificates and CRLs for the PKCS #12, which should be placed in a CERT_PATH_CTX. */ status = C_CreateListObject (&trustedCerts); if (status != 0) goto CLEANUP; RSA_PrintMessage ("If you don't want to export an entire chain, just "); RSA_PrintMessage ("supply the subject's\ncert (or uppermost cert "); RSA_PrintMessage ("in the chain) as a trusted certificate.\n"); RSA_PrintMessage ("Supply trusted certificate(s).\n"); status = RSA_AddCertsToListPrompt (ctx, trustedCerts); if (status != 0) goto CLEANUP; RSA_PrintMessage ("Optionally supply other certificates necessary for"); RSA_PrintMessage (" path validation.\n"); status = RSA_AddCertsToDbPrompt (ctx, database); if (status != 0) goto CLEANUP; status = C_CreateListObject (&crlList); if (status != 0) goto CLEANUP; RSA_PrintMessage ("Optionally supply CRLs necessary for path validation.\n"); status = RSA_AddCrlsToListPrompt (ctx, crlList); if (status != 0) goto CLEANUP; status = C_InsertCRLList (database, crlList); if (status != 0) goto CLEANUP; pathCtx.pathAlgorithm = PA_X509_V1; status = C_GetListObjectCount (crlList, &numCrls); if (status != 0) goto CLEANUP; /* Of course, your application can choose to always require CRLs... */ if (numCrls == 0) pathCtx.pathOptions = PF_IGNORE_REVOCATION; else pathCtx.pathOptions = 0; pathCtx.trustedCerts = trustedCerts; pathCtx.policies = ANY_POLICY; pathCtx.validationTime = PF_VALIDATION_TIME_NOW; pathCtx.database = database; 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 (filename, sizeof (filename), "Enter name of file to store PKCS #12 binary"); if (status != 0) goto CLEANUP; status = RSA_GetCommand (userInput, sizeof (userInput), "Supply MAC password for message integrity"); if (status != 0) goto CLEANUP; status = RSA_FormatPkcs12Password (userInput, &macPassword); if (status != 0) goto CLEANUP; RSA_PrintMessage ("Supply password to protect PKCS #12 contents\n"); status = RSA_GetCommand (userInput, sizeof (userInput), "(blank to use the same password)"); if (T_strlen (userInput) == 0) { T_memset ((POINTER)userInput, 0, sizeof (userInput)); status = C_ExportPKCS12 (ctx, subjectName, &pathCtx, encryptionAlg, macDigest, iterationCount, exportOptions, filename, &macPassword); if (status != 0) goto CLEANUP; } else if (status != 0) { goto CLEANUP; } else { status = RSA_FormatPkcs12Password (userInput, &encPassword); if (status != 0) goto CLEANUP; T_memset ((POINTER)userInput, 0, sizeof (userInput)); exportOptions |= PKCS12_USE_TWO_PASSWORDS; status = C_ExportPKCS12 (ctx, subjectName, &pathCtx, encryptionAlg, macDigest, iterationCount, exportOptions, filename, &macPassword, &encPassword); if (status != 0) goto CLEANUP; } CLEANUP: if (status != 0) RSA_PrintError ("ExportKeyAndCert", status); T_memset (macPassword.data, 0, macPassword.len); T_memset (encPassword.data, 0, encPassword.len); T_free (macPassword.data); T_free (encPassword.data); C_DestroyCertObject (&certObj); B_DestroyKeyObject (&privateKey); C_DestroyListObject (&trustedCerts); C_DestroyListObject (&crlList); C_UnbindService (&database); return status; } /* end ExportKeyAndCert */ /* This routine uses C_WriteToPKCS12 to export some arbitrary private keys, * certificates, and CRLs. */ static int GeneratePKCS12 (CERTC_CTX ctx) { int status = 0; char userInput[RSA_DEMO_MAX_LINE_LEN]; char filename[RSA_DEMO_MAX_LINE_LEN]; LIST_OBJ pkcs12Bags = NULL; STREAM outputStream = NULL; int encryptionAlg = 0, macDigest = 0; int iterationCount = 0, exportOptions = 0; ITEM macPassword = {NULL, 0}, encPassword = {NULL, 0}; status = C_CreateListObject (&pkcs12Bags); if (status != 0) goto CLEANUP; /* Prompt the user to supply the PKCS #12 contents */ status = RSA_Pkcs12BagInfoPrompt (ctx, pkcs12Bags); if (status != 0) goto CLEANUP; 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 (filename, sizeof (filename), "Enter name of file to store PKCS #12 binary"); if (status != 0) goto CLEANUP; status = C_OpenStream (ctx, STREAM_SP_NAME, (POINTER)filename, IO_WRONLY|IO_CREAT|IO_TRUNC|IO_BINARY, &outputStream); if (status != 0) goto CLEANUP; status = RSA_GetCommand (userInput, sizeof (userInput), "Supply MAC password for message integrity"); if (status != 0) goto CLEANUP; status = RSA_FormatPkcs12Password (userInput, &macPassword); if (status != 0) goto CLEANUP; RSA_PrintMessage ("Supply password to protect PKCS #12 contents\n"); status = RSA_GetCommand (userInput, sizeof (userInput), "(blank to use the same password)"); if (T_strlen (userInput) == 0) { T_memset ((POINTER)userInput, 0, sizeof (userInput)); status = C_WriteToPKCS12 (ctx, pkcs12Bags, encryptionAlg, macDigest, iterationCount, exportOptions, &macPassword, outputStream); if (status != 0) goto CLEANUP; } else if (status != 0) { goto CLEANUP; } else { status = RSA_FormatPkcs12Password (userInput, &encPassword); if (status != 0) goto CLEANUP; T_memset ((POINTER)userInput, 0, sizeof (userInput)); exportOptions |= PKCS12_USE_TWO_PASSWORDS; status = C_WriteToPKCS12 (ctx, pkcs12Bags, encryptionAlg, macDigest, iterationCount, exportOptions, &macPassword, outputStream, &encPassword); if (status != 0) goto CLEANUP; } CLEANUP: if (status != 0) RSA_PrintError ("GeneratePKCS12", status); T_memset (macPassword.data, 0, macPassword.len); T_memset (encPassword.data, 0, encPassword.len); T_free (macPassword.data); T_free (encPassword.data); C_CloseStream (outputStream); C_DestroyListObject (&pkcs12Bags); return status; } /* end GeneratePKCS12 */