| RSA BSAFE Cert-C |
Certificate Components for C |
| Crypto-C 6.2.1 Developer's Guide | ||
| Search |
/* $Id: pkcs11db.c,v 1.4 2004/03/02 05:18:39 gsingh Exp $ */ /* pkcs11db.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 setup of the PKCS #11 database provider. This is a stand-alone ** application that is a simple demonstration that generates a keypair on the ** device, generates a self-signed certificate, and puts that certificate on ** the device. ** ** For another example that shows the use of keys and certs stored in a ** PKCS #11 device being used for PKCS #7 messaging, see the sample in ** samples/pkcs7/pkcs11msg.c. Keep in mind that the device must be ** configured properly to allow the insertion of a cert and private key to the ** token. Also, make sure that there is enough available space on the token. ** ** An exercise for the user would be to modify this program, or write a ** similar program, that generated a PKCS #10 for the keypair on the device. ** Then, by whatever means that request is fulfilled, take the issued cert and ** place it on the device. ** ** 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 "pkcs11db.h" #include "rsacsp.h" #include "demoutil.h" #include "certutil.h" #include "p11util.h" #ifdef _MSC_VER # pragma warning (disable: 171) /* invalid type conversion (often of very similar ptrs) */ #endif /* This procedure generates a new RSA keypair on the PKCS #11 device. The * code here has been largely lifted from the Crypto-C p11rsakeygen.c sample * in the Crypto-C samples/pkcs11 directory. Be sure to examine the options * in the function definition below to make sure the options are compatible * with the configuration of your device. */ static int GeneratePkcs11RsaKeypair (CERTC_CTX ctx, B_KEY_OBJ publicKey, B_KEY_OBJ privateKey); /* This procedure generates a certificate for the given public key, signed * with the given private key. The user is prompted to supply information * for the other certificate fields. */ static int GenerateUserCert (CERTC_CTX ctx, B_KEY_OBJ publicKey, B_KEY_OBJ privateKey, CERT_OBJ certObj); /* InsertUserInfo inserts the given cert and private key into the database * specified by dbName. A properly initialized CERTC_CTX should be passed in. */ static int InsertUserInfo (CERTC_CTX ctx, char *dbName, CERT_OBJ certObj); /* DumpDatabaseContents retrieves all of the certificates from the * database specified by dbName. Information about all of these certificates * are then printed out. A properly initialized CERTC_CTX must be passed in. */ static int DumpDatabaseContents (CERTC_CTX ctx, char *dbName); int main (int argc, char *argv[]) { int status = 0; CERTC_CTX ctx = NULL; B_KEY_OBJ publicKey = NULL, privateKey = NULL; CERT_OBJ certObj = NULL; B_PKCS11_SESSION p11SessionInfo; PKCS11_INIT_PARAMS p11InitParams; PKCS11_CRYPTO_PARAMS p11CryptoParams; SERVICE_HANDLER p11DbServiceHandler = { SPT_DATABASE, "Sample PKCS #11 Database", S_InitializePKCS11DB }; SERVICE_HANDLER p11CryptoServiceHandler = { SPT_CRYPTO, "Crypto Provider with PKCS #11", S_InitializeDefaultCSP2 }; char *libraryName = NULL; ITEM tokenLabel = {NULL, 0}, passphrase = {NULL, 0}; FILE_LOG_PARAMS logParams = {NULL, NULL}; SERVICE_HANDLER logHandler = { SPT_LOG, "Default File Log", S_InitializeFileLog }; /* Initialize variables for graceful error-handling */ T_memset ((POINTER)&p11SessionInfo, 0, sizeof (p11SessionInfo)); T_memset ((POINTER)&p11InitParams, 0, sizeof (p11InitParams)); T_memset ((POINTER)&p11CryptoParams, 0, sizeof (p11CryptoParams)); status = RSA_SetOptions (&logParams, argc, argv); if (status != 0) goto CLEANUP; RSA_PrintMessage ("PKCS #11 Key Generation and Cert Storage 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 /* This function is described in samples/common/include/p11util.h */ 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"); /* We need the PKCS #11 Crypto provider since we're doing key generation. 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"); /* Generate a new keypair for the user */ status = B_CreateKeyObject (&publicKey); if (status != 0) goto CLEANUP; status = B_CreateKeyObject (&privateKey); if (status != 0) goto CLEANUP; status = GeneratePkcs11RsaKeypair (ctx, publicKey, privateKey); if (status != 0) goto CLEANUP; status = C_CreateCertObject (&certObj, ctx); if (status != 0) goto CLEANUP; status = GenerateUserCert (ctx, publicKey, privateKey, certObj); if (status != 0) goto CLEANUP; status = InsertUserInfo (ctx, p11DbServiceHandler.name, certObj); if (status != 0) goto CLEANUP; RSA_PrintMessage ("\nDumping database contents...\n"); status = DumpDatabaseContents (ctx, p11DbServiceHandler.name); if (status != 0) goto CLEANUP; CLEANUP: if (status != 0) RSA_PrintError ("pkcs11db.c", 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); B_DestroyKeyObject (&publicKey); B_DestroyKeyObject (&privateKey); C_DestroyCertObject (&certObj); C_FinalizeCertC (&ctx); return status; } /* end main */ /* See function declaration at the top for a description */ int GeneratePkcs11RsaKeypair (CERTC_CTX ctx, B_KEY_OBJ publicKey, B_KEY_OBJ privateKey) { int status = 0; B_ALGORITHM_OBJ keyGenObj = NULL; B_KEYPAIR_GEN_PARAMS keypairGenParams; A_RSA_KEY_GEN_PARAMS rsaKeyGenParams; B_ALGORITHM_OBJ randomObj = NULL; B_ALGORITHM_CHOOSER chooser; ITEM deviceName = {NULL, 0}; unsigned char f4data[] = {0x01, 0x00, 0x01}; RSA_PrintMessage ("Generating RSA keypair...\n"); status = B_CreateAlgorithmObject (&keyGenObj); if (status != 0) goto CLEANUP; /* Supply information needed to generate keypair */ status = RSA_GetInteger ((int *)&rsaKeyGenParams.modulusBits, "Enter desired RSA key size (512-2048)"); if (status != 0) goto CLEANUP; rsaKeyGenParams.publicExponent.data = f4data; rsaKeyGenParams.publicExponent.len = sizeof (f4data); keypairGenParams.privateKeyAttributes.keyUsage = CF_DIGITAL_SIGNATURE | CF_KEY_ENCIPHERMENT | CF_DATA_ENCIPHERMENT; keypairGenParams.privateKeyAttributes.tokenFlag = TF_RESIDE_ON_TOKEN | TF_PRIVATE; keypairGenParams.privateKeyAttributes.start = 0; keypairGenParams.privateKeyAttributes.end = 0; keypairGenParams.publicKeyAttributes.keyUsage = CF_DIGITAL_SIGNATURE | CF_KEY_ENCIPHERMENT | CF_DATA_ENCIPHERMENT; keypairGenParams.publicKeyAttributes.tokenFlag = TF_RESIDE_ON_TOKEN; keypairGenParams.publicKeyAttributes.start = 0; keypairGenParams.publicKeyAttributes.end = 0; keypairGenParams.keypairGenInfoType = AI_RSAKeyGen; keypairGenParams.keypairGenInfo = (POINTER)&rsaKeyGenParams; status = B_SetAlgorithmInfo (keyGenObj, AI_KeypairGen, (POINTER)&keypairGenParams); if (status != 0) goto CLEANUP; status = C_GetChooser (ctx, &chooser); if (status != 0) goto CLEANUP; status = B_GenerateInit (keyGenObj, chooser, NULL); if (status != 0) goto CLEANUP; status = B_GetDevice (&deviceName, keyGenObj); if (status != 0) goto CLEANUP; RSA_PrintBuf ("Device Name for RSA Key Generation", deviceName.data, deviceName.len); status = C_GetRandomObject (ctx, &randomObj); if (status != 0) goto CLEANUP; status = B_GenerateKeypair (keyGenObj, publicKey, privateKey, randomObj, NULL); CLEANUP: if (status != 0) RSA_PrintError ("GeneratePkcs11RsaKeypair", status); B_DestroyAlgorithmObject (&keyGenObj); return status; } /* end GeneratePkcs11RsaKeypair */ /* See function declaration at the top for a description */ int GenerateUserCert (CERTC_CTX ctx, B_KEY_OBJ publicKey, B_KEY_OBJ privateKey, CERT_OBJ certObj) { int status = 0; ALGORITHM_IDENTIFIER signatureAlg; CERT_FIELDS certFields; RSA_PrintMessage ("Generating User's Cert...\n"); T_memset ((POINTER)&certFields, 0, sizeof (certFields)); status = RSA_ChooseCertVersionPrompt (&certFields.version); if (status != 0) goto CLEANUP; status = RSA_GetItem (&certFields.serialNumber, "Enter hex-ascii serial number (blank to quit)"); if (status != 0) goto CLEANUP; status = RSA_ChooseSignatureAlgorithmPrompt (&signatureAlg); if (status != 0) goto CLEANUP; certFields.signatureAlgorithm = signatureAlg.algorithmId; status = C_CreateNameObject (&certFields.issuerName); if (status != 0) goto CLEANUP; status = RSA_GetNameObject (certFields.issuerName, "issuer"); if (status != 0) goto CLEANUP; status = RSA_GetInputToUint4Time (&certFields.validity.start, "Enter validity start"); if (status != 0) goto CLEANUP; status = RSA_GetInputToUint4Time (&certFields.validity.end, "Enter validity end"); if (status != 0) goto CLEANUP; status = C_CreateNameObject (&certFields.subjectName); if (status != 0) goto CLEANUP; status = RSA_GetNameObject (certFields.subjectName, "subject"); if (status != 0) goto CLEANUP; status = RSA_GetKeyBer (RSA_DEMO_PUBLIC_KEY, publicKey, &certFields.publicKey); if (status != 0) goto CLEANUP; if (certFields.version == CERT_VERSION_1) { certFields.issuerUniqueID.data = NULL_PTR; certFields.issuerUniqueID.len = 0; certFields.issuerUniqueID.unusedBits = 0; certFields.subjectUniqueID.data = NULL_PTR; certFields.subjectUniqueID.len = 0; certFields.subjectUniqueID.unusedBits = 0; } else { status = RSA_GetBitString (&certFields.issuerUniqueID, "Enter optional unique ID of cert issuer (blank to omit)"); if (status != 0 && status != RSA_DEMO_E_CANCEL) goto CLEANUP; status = RSA_GetBitString (&certFields.subjectUniqueID, "Enter optional unique ID of cert subject (blank to omit)"); if (status != 0 && status != RSA_DEMO_E_CANCEL) goto CLEANUP; } status = C_CreateExtensionsObject (&certFields.certExtensions, CERT_EXTENSIONS_OBJ, ctx); if (status != 0) goto CLEANUP; if (certFields.version == CERT_VERSION_3) { status = RSA_GetExtensionsObject (certFields.certExtensions, CERT_EXTENSIONS_OBJ); if (status != 0) goto CLEANUP; } status = C_SetCertFields (certObj, &certFields); if (status != 0) goto CLEANUP; status = C_SignCert (certObj, privateKey); if (status != 0) goto CLEANUP; CLEANUP: if (status != 0) RSA_PrintError ("GenerateUserCert", status); C_DestroyNameObject (&certFields.issuerName); C_DestroyNameObject (&certFields.subjectName); C_DestroyExtensionsObject (&certFields.certExtensions); T_free (certFields.publicKey.data); T_free (certFields.issuerUniqueID.data); T_free (certFields.subjectUniqueID.data); return status; } /* end GenerateUserCert */ /* See function declaration at the top for a description */ int InsertUserInfo (CERTC_CTX ctx, char *dbName, CERT_OBJ certObj) { int status = 0; SERVICE db = (SERVICE)NULL_PTR; status = C_BindService (ctx, SPT_DATABASE, dbName, &db); if (status != 0) goto CLEANUP; RSA_PrintMessage ("Inserting certificate into database...\n"); status = C_InsertCert (db, certObj); if (status != 0) goto CLEANUP; /* since the private key was generated on the PKCS #11 device, we do not need to insert it here */ CLEANUP: if (status != 0) RSA_PrintError ("InsertUserInfo", status); C_UnbindService (&db); return status; } /* end InsertUserInfo */ /* See function declaration at the top for a description */ int DumpDatabaseContents (CERTC_CTX ctx, char *dbName) { int status = 0; SERVICE db = (SERVICE)NULL_PTR; LIST_OBJ certList = (LIST_OBJ)NULL_PTR; DB_ITERATOR iterator = (DB_ITERATOR)NULL_PTR; CERT_OBJ certObj = (CERT_OBJ)NULL_PTR; unsigned int certCount = 0, i = 0; status = C_BindService (ctx, SPT_DATABASE, dbName, &db); if (status != 0) goto CLEANUP; status = C_CreateListObject (&certList); if (status != 0) goto CLEANUP; /* To walk through the certs in the database, we need to initialize an * iterator by first calling C_SelectFirstCert(). Subsequent calls can * then be made to C_SelectNextCert(). When the iterator is NULL_PTR, we * know that any memory associated with it has been freed and no certs * remain in the database. Should you need to dispose of the iterator * before all certs have been retrieved, you may call C_FreeIterator(). */ status = C_SelectFirstCert (db, &iterator, certList); if (iterator == NULL) { RSA_PrintMessage ("Database empty.\n"); status = 0; } else if (status != 0) goto CLEANUP; else { RSA_PrintMessage ("Retrieving first cert...\n"); /* Retrieve all of the remaining certificates. When there are no more * certificates, the iterator will be set to NULL. */ for (;;) { status = C_SelectNextCert (&iterator, certList); if (iterator == NULL) { status = 0; break; } else if (status != 0) goto CLEANUP; RSA_PrintMessage ("Retrieving another cert from database...\n"); } } /* Now that we have a list object filled with certificates, print out some * information about each certificate. */ 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; RSA_PrintMessage ("\n***Certificate #%u:\n", i + 1); status = RSA_PrintCertInfo (certObj); if (status != 0) goto CLEANUP; } CLEANUP: if (status != 0) RSA_PrintError ("DumpDatabaseContents", status); C_DestroyListObject (&certList); C_FreeIterator (&iterator); C_UnbindService (&db); return status; } /* end DumpDatabaseContents */