| RSA BSAFE Cert-C |
Certificate Components for C |
| Crypto-C 6.2.1 Developer's Guide | ||
| Search |
/* $Id: crl.c,v 1.7 2004/03/02 05:18:39 gsingh Exp $ */ /* crl.c ** Copyright (c) 1999-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 parse or generate 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 "demoutil.h" #include "crlutil.h" #ifdef _MSC_VER # pragma warning (disable: 171) #endif /* The number of service providers used in this example. Here, we must * register a crypto service provider. */ #define SP_COUNT 1 /* DisplayCRLObj reads in the BER encoding of a CRL from a file and * prints out its fields. A properly initialized CERTC_CTX must be * passed in. */ static int DisplayCrlObj (CERTC_CTX ctx); /* GenerateCRLObj creats a CRL and obtains user input to populate * the crl fields. A properly initialized CERTC_CTX must be * passed in. */ static int GenerateCrlObj (CERTC_CTX ctx); /* VerifyCrlSignature reads in the BER encoding of a CRL from a file * and verifies the CRL signature. A BER-encoded public key is obtained * from a file and used to verify the signature. A properly initialized * CERTC_CTX must be passed in. */ static int VerifyCrlSignature (CERTC_CTX ctx); /* GetCrlInnerDer reads in the BER encoding of a CRL from a file and * then obtains the DER encoding of the data to be signed. This data * is then stored in a file. A properly initialized CERTC_CTX must * be passed in. */ static int GetCrlInnerDer (CERTC_CTX ctx); /* SignCrlInnerDER reads in the BER encoded portion of the CRL to be signed * This function also reads in a BER encoded private key. The private key * is then used to sign the CRL data. The CRL is then saved in DER * format in a file. A properly initialized CERTC_CTX must be passed in. */ static int SignCrlInnerDer (CERTC_CTX ctx); /* FindCertInCrl reads in a BER encoded CRL from a file and a BER-encoded * certificate from a file. The crl is then searched to see if the * certificate is listed in the CRL. The result of this search is then * printed out. A properly initialized CERTC_CTX must be passed in. */ static int FindCertInCrl (CERTC_CTX ctx); /* ExtractObjsFromCRL reads in a BER encoded crl from a file and extracts * fields from this object. The fields are then saved to user specified * files. A properly initialized CERTC_CTX must be passed in. */ static int ExtractObjsFromCrl (CERTC_CTX ctx); /* RemoveCRLEntry reads in a BER-encoded CRL from a file. Then it asks the * user to select a CRL entry to be removed and then saves the new CRL in a * user-specified file. A properly-initialized CERTC_CTX must be passed in. */ static int RemoveCRLEntry (CERTC_CTX ctx); 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]; POINTER spParams[SP_COUNT]; FILE_LOG_PARAMS logParams = {NULL, NULL}; SERVICE_HANDLER logHandler = { SPT_LOG, "Default File Log", S_InitializeFileLog }; /* Since we are going to be performing operations using Crypto-C, we need to register an instance of the crypto provider. */ spTable[0].type = SPT_CRYPTO; spTable[0].name = "BSAFE Crypto-C"; spTable[0].Initialize = S_InitializeDefaultCSP; spParams[0] = NULL; 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 ("CRL Object Demonstration\n"); RSA_PrintMessage ("========================\n"); for (;;) { RSA_PrintMessage ("\nCRL Object Operations\n"); RSA_PrintMessage (" A - Display CRL object from a file\n"); RSA_PrintMessage (" B - Generate CRL object\n"); RSA_PrintMessage (" C - Verify CRL signature\n"); RSA_PrintMessage (" D - Get Inner DER of CRL\n"); RSA_PrintMessage (" E - Sign Inner DER\n"); RSA_PrintMessage (" F - Check whether a cert is listed in a CRL\n"); RSA_PrintMessage (" G - Extract objects from CRL\n"); RSA_PrintMessage (" H - Remove a CRL Entry\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 = DisplayCrlObj (ctx); break; case 'b': case 'B': status = GenerateCrlObj (ctx); break; case 'c': case 'C': status = VerifyCrlSignature (ctx); break; case 'd': case 'D': status = GetCrlInnerDer (ctx); break; case 'e': case 'E': status = SignCrlInnerDer (ctx); break; case 'f': case 'F': status = FindCertInCrl (ctx); break; case 'g': case 'G': status = ExtractObjsFromCrl(ctx); break; case 'h': case 'H': status = RemoveCRLEntry(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 ("crl.c", status); C_FinalizeCertC (&ctx); return status; } /* end main */ /* See function declaration at the top for a description */ static int DisplayCrlObj (CERTC_CTX ctx) { int status = 0; unsigned char *crlBer = NULL; unsigned int crlBerLen = 0; CRL_OBJ crlObj = NULL; ITEM output; status = RSA_GetFileToAllocBuffer (&crlBer, &crlBerLen, "Enter name of CRL object binary"); if (status != 0) goto CLEANUP; status = C_CreateCRLObject (&crlObj, ctx); if (status != 0) goto CLEANUP; status = C_SetCRLBER (crlObj, crlBer, crlBerLen); if (status != 0) goto CLEANUP; RSA_PrintMessage ("\nCRL Object Contents\n"); /* RSA_PrintCrlObject is described in samples/common/include/crlutil.h */ status = RSA_PrintCrlObject (crlObj); if (status != 0) goto CLEANUP; /* Check the CRL for any inconsistencies. Cert-C is lenient in allowing CRLs with abnormalities to be imported using C_SetCRLBER, but will not allow the export of CRLs with incorrect encodings to be exported using C_GetCRLDER. */ status = C_GetCRLDER (crlObj, &output.data, &output.len); if (status != 0) { RSA_PrintMessage ("Please examine the CRL binary "); RSA_PrintMessage ("for problems with the encoding.\n"); RSA_PrintMessage ("C_SetCRLBER passed but C_GetCRLDER fails.\n"); goto CLEANUP; } CLEANUP: if (status != 0) RSA_PrintError ("DisplayCrlObj", status); C_DestroyCRLObject (&crlObj); T_free (crlBer); return status; } /* end DisplayCrlObj */ /* See function declaration at the top for a description */ static int GenerateCrlObj (CERTC_CTX ctx) { int status = 0; CRL_OBJ crlObj = NULL; unsigned char *crlBer = NULL; unsigned int crlBerLen = 0; status = C_CreateCRLObject (&crlObj, ctx); if (status != 0) goto CLEANUP; /* RSA_GetInputToCrlObject is described in samples/common/include/crlutil.h */ status = RSA_GetInputToCrlObject (ctx, crlObj); if (status != 0) goto CLEANUP; status = C_GetCRLDER (crlObj, &crlBer, &crlBerLen); if (status != 0) goto CLEANUP; status = RSA_WriteDataToFile (crlBer, crlBerLen, "Enter file name to store CRL object binary"); if (status != 0) goto CLEANUP; CLEANUP: if (status != 0) RSA_PrintError ("GenerateCrlObj", status); C_DestroyCRLObject (&crlObj); return status; } /* end GenerateCrlObj */ /* See function declaration at the top for a description */ static int VerifyCrlSignature (CERTC_CTX ctx) { int status = 0; unsigned char *crlBer = NULL; unsigned int crlBerLen = 0; B_KEY_OBJ publicKey = NULL; CRL_OBJ crlObj = NULL; status = RSA_GetFileToAllocBuffer (&crlBer, &crlBerLen, "Enter name of CRL binary"); if (status != 0) goto CLEANUP; status = C_CreateCRLObject (&crlObj, ctx); if (status != 0) goto CLEANUP; status = C_SetCRLBER (crlObj, crlBer, crlBerLen); if (status != 0) goto CLEANUP; /* RSA_GetKeyObjFromFile is described in samples/common/include/keyutil.h */ status = RSA_GetKeyObjFromFile (RSA_DEMO_PUBLIC_KEY, &publicKey); if (status != 0) goto CLEANUP; status = C_VerifyCRLSignature (crlObj, publicKey); if (status != 0) goto CLEANUP; RSA_PrintMessage ("Signature verified!\n"); CLEANUP: if (status != 0) RSA_PrintError ("VerifyCrlSignature", status); C_DestroyCRLObject (&crlObj); B_DestroyKeyObject (&publicKey); T_free (crlBer); return status; } /* end VerifyCrlSignature */ /* See function declaration at the top for a description */ static int GetCrlInnerDer (CERTC_CTX ctx) { int status = 0; unsigned char *crlBer = NULL, *innerDer = NULL; unsigned int crlBerLen = 0, innerDerLen = 0; CRL_OBJ crlObj = NULL; status = RSA_GetFileToAllocBuffer (&crlBer, &crlBerLen, "Enter name of CRL object binary"); if (status != 0) goto CLEANUP; status = C_CreateCRLObject (&crlObj, ctx); if (status != 0) goto CLEANUP; status = C_SetCRLBER (crlObj, crlBer, crlBerLen); if (status != 0) goto CLEANUP; status = C_GetCRLInnerDER (crlObj, &innerDer, &innerDerLen); if (status != 0) goto CLEANUP; status = RSA_WriteDataToFile (innerDer, innerDerLen, "Enter name of file to store CRL inner DER binary"); if (status != 0) goto CLEANUP; CLEANUP: if (status != 0) RSA_PrintError ("GetCrlInnerDer", status); T_free (crlBer); C_DestroyCRLObject (&crlObj); return status; } /* end GetCrlInnerDer */ /* See function declaration at the top for a description */ static int SignCrlInnerDer (CERTC_CTX ctx) { int status = 0; unsigned char *innerDer = NULL, *crlBer = NULL; unsigned int innerDerLen = 0, crlBerLen = 0; B_KEY_OBJ privateKey = NULL; CRL_OBJ crlObj = NULL; status = RSA_GetFileToAllocBuffer (&innerDer, &innerDerLen, "Enter name of CRL inner DER binary"); if (status != 0) goto CLEANUP; status = C_CreateCRLObject (&crlObj, ctx); if (status != 0) goto CLEANUP; status = C_SetCRLInnerBER (crlObj, innerDer, innerDerLen); if (status != 0) goto CLEANUP; /* RSA_GetKeyObjFromFile is described in samples/common/include/keyutil.h */ status = RSA_GetKeyObjFromFile (RSA_DEMO_PRIVATE_KEY, &privateKey); if (status != 0) goto CLEANUP; status = C_SignCRL (crlObj, privateKey); if (status != 0) goto CLEANUP; status = C_GetCRLDER (crlObj, &crlBer, &crlBerLen); if (status != 0) goto CLEANUP; status = RSA_WriteDataToFile (crlBer, crlBerLen, "Enter file name to store CRL object binary"); if (status != 0) goto CLEANUP; CLEANUP: if (status != 0) RSA_PrintError ("SignCrlInnerDer", status); T_free (innerDer); C_DestroyCRLObject (&crlObj); return status; } /* end SignCrlInnerDer */ /* See function declaration at the top for a description */ static int FindCertInCrl (CERTC_CTX ctx) { int status = 0; unsigned char *crlBer = NULL, *certBer = NULL; unsigned int crlBerLen = 0, certBerLen = 0; CRL_OBJ crlObj = NULL; CERT_OBJ certObj = NULL; CERT_FIELDS certFields; CRL_FIELDS crlFields; unsigned int temp = 0; status = RSA_GetFileToAllocBuffer (&crlBer, &crlBerLen, "Enter name of CRL object binary"); if (status != 0) goto CLEANUP; status = C_CreateCRLObject (&crlObj, ctx); if (status != 0) goto CLEANUP; status = C_SetCRLBER (crlObj, crlBer, crlBerLen); if (status != 0) goto CLEANUP; status = C_GetCRLFields (crlObj, &crlFields); if (status != 0) goto CLEANUP; status = RSA_GetFileToAllocBuffer (&certBer, &certBerLen, "Enter name of cert object binary"); if (status != 0) goto CLEANUP; status = C_CreateCertObject (&certObj, ctx); if (status != 0) goto CLEANUP; status = C_SetCertBER (certObj, certBer, certBerLen); if (status != 0) goto CLEANUP; status = C_GetCertFields (certObj, &certFields); if (status != 0) goto CLEANUP; /* We use this method because we are checking for the presence of a cert in * an isolated CRL. For more sophisticated checking involving verification * of the CRL (need CRL issuer's cert for example), use C_CheckCertRevocation * or C_BuildCertPath. */ status = C_CompareName (certFields.issuerName, crlFields.issuerName); if (status != 0) { RSA_PrintMessage ("***The certificate and CRL issuers do not match.\n"); status = 0; goto CLEANUP; } status = C_FindCRLEntryBySerialNumber (crlFields.crlEntries, certFields.serialNumber.data, certFields.serialNumber.len, &temp); if (status == E_NOT_FOUND) { RSA_PrintMessage ("***Certificate not listed in CRL!\n"); status = 0; } else if (status == 0) RSA_PrintMessage ("***Certificate listed among CRL Entries!\n"); else goto CLEANUP; CLEANUP: if (status != 0) RSA_PrintError ("FindCertInCrl", status); T_free (crlBer); T_free (certBer); C_DestroyCRLObject (&crlObj); C_DestroyCertObject (&certObj); return status; } /* end FindCertInCrl */ /* See function declaration at the top for a description */ static int ExtractObjsFromCrl (CERTC_CTX ctx) { int status = 0; unsigned int crlEntryCount, i = 0; unsigned int skipEntries = 0; unsigned char *crlBer = NULL, *ber = NULL; unsigned int crlBerLen, berLen = 0; char command[RSA_DEMO_MAX_LINE_LEN]; CRL_OBJ crlObj = (CRL_OBJ)NULL_PTR; CRL_FIELDS crlFields; CRL_ENTRY_INFO crlEntryInfo; /* Obtain the CRL binary */ status = RSA_GetFileToAllocBuffer (&crlBer, &crlBerLen, "Enter name of CRL object binary"); if (status != 0) goto CLEANUP; status = C_CreateCRLObject (&crlObj, ctx); if (status != 0) goto CLEANUP; status = C_SetCRLBER (crlObj, crlBer, crlBerLen); if (status != 0) goto CLEANUP; /* Extract the fields from the CRL object, which we will modify */ status = C_GetCRLFields (crlObj, &crlFields); if (status != 0) goto CLEANUP; /* Print out the CRL fields, except for the CRL entries */ switch (crlFields.version) { case CRL_VERSION_1: RSA_PrintMessage ("Version 1 CRL\n"); break; case CRL_VERSION_2: RSA_PrintMessage ("Version 2 CRL\n"); break; default: RSA_PrintMessage ("Unknown version: %u\n", crlFields.version); } RSA_PrintSignatureAlgorithm (crlFields.signatureAlgorithm); RSA_PrintUint4Time ("Last Update", crlFields.lastUpdate); RSA_PrintUint4Time ("Next Update", crlFields.nextUpdate); /* Save the issuer name */ RSA_PrintNameObject ("Issuer Name", crlFields.issuerName); status = C_GetNameDER (crlFields.issuerName, &ber, &berLen); if (status != 0) goto CLEANUP; status = RSA_WriteDataToFile (ber, berLen, "Enter name of file to store issuer name binary"); if (status == RSA_DEMO_E_CANCEL) status = 0; /* you don't have to save if you don't want to */ else if (status != 0) goto CLEANUP; /* Save the CRL extensions (if they exist) */ if (crlFields.crlExtensions != NULL) { status = RSA_PrintExtensionsObject (crlFields.crlExtensions); if (status != 0) goto CLEANUP; status = C_GetExtensionsObjectDER (crlFields.crlExtensions, &ber, &berLen); if (status != 0) goto CLEANUP; status = RSA_WriteDataToFile (ber, berLen, "Enter name of file to store CRL extensions binary"); if (status == RSA_DEMO_E_CANCEL) status = 0; /* you don't have to save if you don't want to */ else if (status != 0) goto CLEANUP; } /* Getting the number of entries in the crl */ status = C_GetCRLEntriesCount (crlFields.crlEntries, &crlEntryCount); if (status != 0) goto CLEANUP; if (crlEntryCount != 0) { RSA_PrintMessage ("\nThere are %d CRL Entries. Would ", crlEntryCount); RSA_PrintMessage ("you like to recurse \nthrough the Entries to save "); RSA_PrintMessage ("the extensions objects"); status = RSA_GetCommand (command, sizeof (command), "(y/n)? "); if (status != 0) goto CLEANUP; switch (command[0]) { case 'y': case 'Y': skipEntries = 0; break; default: skipEntries = 1; RSA_PrintMessage ("Skipping the CRL Entries\n"); } if (skipEntries == 0) { /* Print out information about each entry */ for (i = 0; i < crlEntryCount; i++) { status = C_GetCRLEntry (crlFields.crlEntries, &crlEntryInfo, i); if (status != 0) goto CLEANUP; RSA_PrintMessage ("\nEntry Number %d\n\n", i+1); RSA_PrintBuf ("Serial Number ", crlEntryInfo.serialNumber.data, crlEntryInfo.serialNumber.len); RSA_PrintUint4Time ("Revoked at time: ", crlEntryInfo.actionTime); /* Save the CRL entry extensions (if they exist) */ if (crlEntryInfo.crlEntryExtensions != NULL) { status = C_GetExtensionsObjectDER (crlEntryInfo.crlEntryExtensions, &ber, &berLen); if (status != 0) goto CLEANUP; status = RSA_WriteDataToFile (ber, berLen, "Enter name of file to store CRL entry extensions binary"); if (status == RSA_DEMO_E_CANCEL) status = 0; /* you don't have to save if you don't want to */ else if (status != 0) goto CLEANUP; } /* end save CRL entry extensions option */ } /* end for loop to save individual CRL entry information */ } /* end condition to save CRL entries */ } /* end condition if CRL entries exist */ CLEANUP: if (status != 0) RSA_PrintError ("ExtractObjsFromCrl", status); T_free (crlBer); C_DestroyCRLObject (&crlObj); return status; } /* end ExtractObjsFromCrl */ /* See function declaration at the top for a description */ static int RemoveCRLEntry (CERTC_CTX ctx) { int status = 0; unsigned int crlEntryToDelete = 0; unsigned int crlEntryCount = 0; unsigned int index, temp = 0; unsigned int signCRL = 0; unsigned char *crlBer = NULL, *ber = NULL; unsigned int crlBerLen = 0, berLen = 0; CRL_OBJ crlObj = (CRL_OBJ)NULL_PTR; CRL_FIELDS crlFields; CRL_ENTRY_INFO crlEntryInfo; B_KEY_OBJ privateKey = (B_KEY_OBJ)NULL_PTR; /* Obtain the CRL binary */ status = RSA_GetFileToAllocBuffer (&crlBer, &crlBerLen, "Enter name of CRL object binary"); if (status != 0) goto CLEANUP; status = C_CreateCRLObject (&crlObj, ctx); if (status != 0) goto CLEANUP; status = C_SetCRLBER (crlObj, crlBer, crlBerLen); if (status != 0) goto CLEANUP; status = C_GetCRLFields (crlObj, &crlFields); if (status != 0) goto CLEANUP; /* Print out the serial numbers of all the entries */ status = C_GetCRLEntriesCount (crlFields.crlEntries, &crlEntryCount); if (status != 0) goto CLEANUP; if (crlEntryCount == 0) { RSA_PrintMessage ("\nThere are no CRL Entries to Delete\n"); goto CLEANUP; /* at this point, we're finished */ } /* prompt the user for CRL entries to delete and remove those entries from the CRL contents */ while (crlEntryCount != 0) { RSA_PrintMessage ("\nThe following are the serial numbers of "); RSA_PrintMessage ("the CRL entries\n"); /* print the serial numbers of the CRL entries */ for (index = 0; index < crlEntryCount; index++) { status = C_GetCRLEntry (crlFields.crlEntries, &crlEntryInfo, index); if (status != 0) goto CLEANUP; /* print the choice number */ RSA_PrintMessage (" %d -", index); /* print the hex-ascii serial number */ for (temp = 0; temp < crlEntryInfo.serialNumber.len; temp++) { /* remember the current character, if it's a printable ascii char */ RSA_PrintMessage (" %02x", crlEntryInfo.serialNumber.data[temp]); } RSA_PrintMessage ("\n"); } /* end printing all of the CRL entries' serial numbers */ RSA_PrintMessage ("Enter the number of the entry you want to delete "); status = RSA_GetInteger ((int *)&crlEntryToDelete, "(blank to exit)"); if (status == RSA_DEMO_E_CANCEL) { status = 0; break; } if (crlEntryToDelete < crlEntryCount) { /* mark the fact that the CRL needs to be re-signed since we've modified its contents */ signCRL = 1; /* Deleting the CRL entry */ status = C_DeleteCRLEntry (crlFields.crlEntries, crlEntryToDelete); if (status != 0) goto CLEANUP; /* Re-setting the crlObj with the new crl */ status = C_SetCRLFields (crlObj, &crlFields); if (status != 0) goto CLEANUP; } /* recompute the total number of CRL entries available */ status = C_GetCRLEntriesCount (crlFields.crlEntries, &crlEntryCount); if (status != 0) goto CLEANUP; } /* end loop allowing users to remove CRL entries */ /* if any contents of the CRL were modified, we need to re-sign it */ if (signCRL != 0) { RSA_PrintMessage ("Supply private key to sign CRL.\n"); status = RSA_GetKeyObjFromFile (RSA_DEMO_PRIVATE_KEY, &privateKey); if (status != 0) goto CLEANUP; status = C_SignCRL (crlObj, privateKey); if (status != 0) goto CLEANUP; /* Save the new CRL */ status = C_GetCRLDER (crlObj, &ber, &berLen); if (status != 0) goto CLEANUP; status = RSA_WriteDataToFile (ber, berLen, "Enter file name to store new CRL object binary"); if (status != 0) goto CLEANUP; } CLEANUP: if (status != 0) RSA_PrintError ("RemoveCRLEntry", status); T_free (crlBer); B_DestroyKeyObject (&privateKey); C_DestroyCRLObject (&crlObj); return status; } /* end RemoveCRLEntry */