| RSA BSAFE Cert-C |
Certificate Components for C |
| Crypto-C 6.2.1 Developer's Guide | ||
| Search |
/* $Id: cmp.c,v 1.5 2004/03/02 05:18:35 gsingh Exp $ */ /* cmp.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. ** ** NOTE: The methods outlined in this sample file have been deprecated. ** Refer to the cmpreq.c, cmpku.c, and cmprev.c samples, which ** demonstrate the use of the new PKI request APIs. ** ** This program demonstrates how to construct and send a CMP initialization ** request message. This message is intended to be used for entities first ** initializing into the PKI. In response, the server sends an initialization ** response message (which is read into the certResp PKI_MSG_OBJ below) from ** which we extract the returned certificate. ** ** 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 "cmp.h" #include "rsacsp.h" #include "imdb.h" #include "pkixpath.h" #include "crlstat.h" #include "filelog.h" #include "demoutil.h" #include "keyutil.h" #include "certutil.h" #include "extnutil.h" #include "pkiutil.h" #ifdef _MSC_VER # pragma warning (disable: 171) #endif #ifdef USE_ENTRUST_CA #define CMP_URL "cmptcp://edsel.rsa.com:829" #define SHARED_SECRET "8AJL-AVFF-9MCX" #define SENDER_KEYID "21678943" #define CMP_RECIP_COUNTRY "US" #define CMP_RECIP_ORG "RSAS" #define CMP_RECIP_UID "EntrustCA" #define PKI_SP_NAME "Entrust CMP Transaction Provider" #else #define CMP_URL "cmptcp://gandalf.trustpoint.com:8081" #define SHARED_SECRET "interop" #define SENDER_KEYID "interop" /* These macros are used to construct the Recipient DN */ #define CMP_RECIP_COUNTRY "US" #define CMP_RECIP_ORG "Trustpoint" #define CMP_RECIP_CN "Test CA" #define PKI_SP_NAME "Trustpoint CMP Transaction Provider" #endif #define EE_DB_NAME "Requestor's Database" #define SP_COUNT 5 #define DBG_MSG __FILE__ ":" ## __LINE__ #define DBG_STR(a) # a #define DBG_LOC(a,b) a ":" DBG_STR(b) #define DBG_ERROR(a,status) RSA_PrintError( a " in:" DBG_LOC(__FILE__,__LINE__),status) /* This routine takes the request PKI_MSG_OBJ and gathers and sets the sender * information. */ static int SetSender (PKI_MSG_OBJ certReq); /* This routine takes the request PKI_MSG_OBJ and gathers and sets the * recipient information. */ static int SetRecipient (PKI_MSG_OBJ certReq); int main (int argc, char *argv[]) { int status = 0; char userInput[RSA_DEMO_MAX_LINE_LEN]; CERTC_CTX ctx = NULL; SERVICE db = NULL; LIST_OBJ destList = NULL; ITEM cmpUrl = {NULL, 0}; PKI_CMP_SP_INIT_PARAMS cmpInitParams; PKI_MSG_OBJ certReq = NULL, certResp = NULL; PKI_MSG_FIELDS msgFields; PKI_CERTREQ_FIELDS creqFields; PKI_CERTRESP_FIELDS certRespFields; NAME_OBJ requestorName = NULL; B_KEY_OBJ publicKey = NULL, privateKey = NULL; ITEM publicBer = {NULL, 0}, requestorDer = {NULL, 0}; ITEM secret = {NULL, 0}; #ifdef USE_ENTRUST_CA char secret_string[11]; #endif PKI_PROTECT_INFO protectInfo; PKI_POP_GEN_INFO popGenInfo; ITEM certDer = {NULL, 0}; PKI_CMP_STATUS_INFO cmpStatusInfo; PKI_STATUS_INFO statusInfo; FILE_LOG_PARAMS logParams = {NULL, NULL}; SERVICE_HANDLER logHandler = { SPT_LOG, "Default File Log", S_InitializeFileLog }; SERVICE_HANDLER spTable[SP_COUNT] = { {SPT_CRYPTO, "Default CSP", S_InitializeDefaultCSP}, {SPT_CERT_STATUS, "Cert Status Provider", S_InitializeCRLStatus}, {SPT_CERT_PATH, "Path Provider", S_InitializePKIXPath}, {SPT_DATABASE, EE_DB_NAME, S_InitializeMemoryDB}, {SPT_PKI, PKI_SP_NAME, S_InitializeCMP} }; POINTER spParams[SP_COUNT]; spParams[0] = NULL; spParams[1] = NULL; spParams[2] = NULL; spParams[3] = NULL; spParams[4] = (POINTER)&cmpInitParams; T_memset ((POINTER)&msgFields, 0, sizeof (msgFields)); T_memset ((POINTER)&creqFields, 0, sizeof (creqFields)); T_memset ((POINTER)&certRespFields, 0, sizeof (certRespFields)); T_memset ((POINTER)&cmpInitParams, 0, sizeof (cmpInitParams)); T_memset ((POINTER)&popGenInfo, 0, sizeof (popGenInfo)); T_memset ((POINTER)&protectInfo, 0, sizeof (protectInfo)); T_memset ((POINTER)&cmpStatusInfo, 0, sizeof (cmpStatusInfo)); T_memset ((POINTER)&statusInfo, 0, sizeof (statusInfo)); status = RSA_SetOptions (&logParams, argc, argv); if (status != 0) { /* DBG_ERROR("RSA_SetOptions",status);*/ goto CLEANUP; } RSA_PrintMessage ("CMP Provider Demonstration\n"); RSA_PrintMessage ("==========================\n"); /* Step 1: Initialize Cert-C context */ cmpUrl.data = (POINTER)CMP_URL; cmpUrl.len = T_strlen ((char *)cmpUrl.data); status = C_CreateListObject (&destList); if (status != 0) { DBG_ERROR("C_CreateListObject",status); goto CLEANUP; } status = C_AddItemToList (destList, &cmpUrl, NULL); if (status != 0) { DBG_ERROR("C_AddItemToList",status); goto CLEANUP; } cmpInitParams.initChoice = PKI_CMP_INIT_METHOD_STRUCT; #ifdef USE_ENTRUST_CA cmpInitParams.method.initStruct.profile = PKI_CMP_PROFILE_ENTRUST_V1; #else cmpInitParams.method.initStruct.profile = PKI_CMP_PROFILE_CERTICOM; #endif cmpInitParams.method.initStruct.transport.destList = destList; status = C_InitializeCertC (spTable, spParams, SP_COUNT, &ctx); if (status != 0) { DBG_ERROR("C_InitializeCertC",status); 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_LAST); #ifdef RSA_REQUIRE_FILE_LOG if (status != 0) { DBG_ERROR("C_RegisterService",status); goto CLEANUP; } #endif /* Step 2a: Create PKI Request Object */ status = C_CreatePKIMsgObject (ctx, &certReq); if (status != 0) { DBG_ERROR("C_CreatePKIMsgObject",status); goto CLEANUP; } status = C_GetPKIMsgFields (certReq, &msgFields); if (status != 0) { DBG_ERROR("C_GetPKIMsgFields",status); goto CLEANUP; } /* just to be absolutely sure... */ IgnoreAll (msgFields.flags); msgFields.msgType = PKI_MSGTYPE_CERTREQ; ClearIgnoreFlag (msgFields.flags, PKI_MSGFLAGS_IGNORE_MSGTYPE); /* This is the only option supported by the CMP specification */ SetMsgWrapType (msgFields.flags, PKI_MSGFLAGS_WRAP_NONE); status = C_SetPKIMsgFields (certReq, &msgFields); if (status != 0) { DBG_ERROR("C_SetPKIMsgFields",status); goto CLEANUP; } status = RSA_GetRequestorInfo (ctx, &requestorName, &publicKey, &privateKey); if (status != 0) { /* DBG_ERROR("RSA_GetRequestorInfo",status);*/ goto CLEANUP; } /* The values that go in to the certTemplate, controls and regInfo fields depend on the CA's requirements, so this code should be modified appropriately. Here, we access the request-specific fields. */ status = C_GetPKICertRequestFields (certReq, &creqFields); if (status != 0) { DBG_ERROR("C_GetPKICertRequestFields",status); goto CLEANUP; } IgnoreAll (creqFields.flags); creqFields.popType = PKI_POP_SIGNATURE; ClearIgnoreFlag (creqFields.flags, PKI_CERTREQFLAGS_IGNORE_POPTYPE); /* fill in the needed fields in the certTemplate */ status = C_GetNameDER (requestorName, &requestorDer.data, &requestorDer.len); if (status != 0) { DBG_ERROR("C_GetNameDER",status); goto CLEANUP; } status = C_SetNameBER (creqFields.certTemplate.subjectName, requestorDer.data, requestorDer.len); ClearIgnoreFlag (creqFields.flags, PKI_CERTREQFLAGS_IGNORE_TEMPLATE_SUBJECTNAME); status = RSA_GetKeyBer (RSA_DEMO_PUBLIC_KEY, publicKey, &publicBer); if (status != 0) { /* DBG_ERROR("RSA_GetKeyBer",status);*/ goto CLEANUP; } creqFields.certTemplate.publicKey.data = publicBer.data; creqFields.certTemplate.publicKey.len = publicBer.len; ClearIgnoreFlag (creqFields.flags, PKI_CERTREQFLAGS_IGNORE_TEMPLATE_PUBLICKEY); status = C_SetPKICertRequestFields (certReq, &creqFields); if (status != 0) { DBG_ERROR("C_SetPKICertRequestFields",status); goto CLEANUP; } /* Set sender info */ status = SetSender (certReq); if (status != 0) { /* DBG_ERROR("SetSender",status);*/ goto CLEANUP; } /* Set recipient info */ status = SetRecipient (certReq); if (status != 0) { /* DBG_ERROR("SetRecipient",status);*/ goto CLEANUP; } /* Step 2b: Generate proof of possession */ status = C_GeneratePKIProofOfPossession (ctx, PKI_SP_NAME, certReq, privateKey, &popGenInfo); if (status != 0) { DBG_ERROR("C_GeneratePKIProofOfPossession",status); goto CLEANUP; } status = S_CMPSetMessageType (ctx, cmpInitParams.handle, PKI_CMP_IR, certReq); if (status != 0) { DBG_ERROR("S_CMPSetMessageType",status); goto CLEANUP; } /* Step 2c: Prepare a PKI_PROTECT_INFO with the shared secret. In the case of the Trustpoint server above, the shared secret is "interop". */ #ifdef USE_ENTRUST_CA /* An undocumented feature of entrust CA 6.0 requires * that the shared secret 12.th byte is only a checksum and as * such does not participate in the password based authentication. * As well as any '-' in the authetication string */ { int l; char *i; for(i=SHARED_SECRET,l=0;l<11 && *i;i++) { if ( *i != '-') { secret_string[l++]=*i; } } secret.data = (POINTER)secret_string; secret.len = T_strlen (SHARED_SECRET); } #else secret.data = (POINTER)SHARED_SECRET; secret.len = T_strlen (SHARED_SECRET); #endif protectInfo.info.secret = &secret; status = C_BindService (ctx, SPT_DATABASE, EE_DB_NAME, &db); if (status != 0) { DBG_ERROR("C_BindService",status); goto CLEANUP; } status = C_CreatePKIMsgObject (ctx, &certResp); if (status != 0) { DBG_ERROR("C_CreatePKIMsgObject",status); goto CLEANUP; } #ifndef CMP_DEBUG RSA_PrintMessage ("Contacting %s...\n", CMP_URL); status = C_RequestPKICert (ctx, PKI_SP_NAME, certReq, &protectInfo, db, certResp); if (status != 0) { DBG_ERROR("C_RequestPKICert",status); goto CLEANUP; } #else { /* Use C_WritePKICertRequestMsg, C_SendPKIMsg, and C_ReadPKICertResponseMsg, in place of C_RequestPKICert to access and store the intermediate messages. */ ITEM irMsg = {NULL, 0}, ipMsg = {NULL, 0}; status = C_WritePKICertRequestMsg (ctx, PKI_SP_NAME, certReq, &protectInfo, &irMsg); if (status != 0) { DBG_ERROR("C_WritePKICertRequestMsg",status); goto CLEANUP; } status = RSA_WriteDataToFile (irMsg.data, irMsg.len, "Enter name of file to store outgoing IR msg"); if (status == RSA_DEMO_E_CANCEL) status = 0; /* not mandatory to save message */ else if (status != 0) { DBG_ERROR("C_WritePKICertRequestMsg",status); goto CLEANUP; } RSA_PrintMessage ("Contacting %s...\n", CMP_URL); status = C_SendPKIMsg (ctx, PKI_SP_NAME, &irMsg, &ipMsg, &statusInfo); if (status != 0) { DBG_ERROR("C_SendPKIMsg",status); goto CLEANUP; } RSA_PrintMessage ("Transport Status:\n"); RSA_PrintPkiStatusInfo (&statusInfo); status = RSA_WriteDataToFile (ipMsg.data, ipMsg.len, "Enter name of file to store incoming IP msg"); if (status == RSA_DEMO_E_CANCEL) status = 0; /* not mandatory to save message */ else if (status != 0) { DBG_ERROR("C_SendPKIMsg",status); goto CLEANUP; } #if 1 status = C_ReadPKICertResponseMsg (ctx, PKI_SP_NAME, &ipMsg, &protectInfo, certResp); if (status != 0) { DBG_ERROR("C_ReadPKICertResponseMsg",status); goto CLEANUP; } #endif } #endif /* Print out information about response message and request confirmation from user. */ status = C_GetPKICertResponseFields (certResp, &certRespFields); if (status != 0) { DBG_ERROR("C_GetPKICertResponseFields",status); goto CLEANUP; } RSA_PrintMessage ("Certificate Request Status\n"); status = RSA_PrintPkiStatusInfo (&certRespFields.statusInfo); if (status != 0) { /* DBG_ERROR("RSA_PrintPkiStatusInfo",status);*/ goto CLEANUP; } if (certRespFields.flags & PKI_CERTRESPFLAGS_IGNORE_CERT) { RSA_PrintMessage ("Certificate not returned.\n"); status = RSA_DEMO_E_INVALID_PARAMETER; { /* DBG_ERROR("RSA_PrintPkiStatusInfo",status);*/ goto CLEANUP; } } RSA_PrintMessage ("Examine the Resulting Certificate:\n"); status = RSA_PrintCertObject (certRespFields.cert); if (status != 0) { /* DBG_ERROR("RSA_PrintCertObject",status);*/ goto CLEANUP; } status = C_GetCertDER (certRespFields.cert, &certDer.data, &certDer.len); if (status != 0) { DBG_ERROR("C_GetCertDER",status); goto CLEANUP; } status = RSA_WriteDataToFile (certDer.data, certDer.len, "Enter name of file to store cert binary"); if (status == RSA_DEMO_E_CANCEL) status = 0; /* saving the cert is optional */ else if (status != 0) { /* DBG_ERROR("RSA_WriteDataToFile",status);*/ goto CLEANUP; } status = RSA_GetCommand (userInput, sizeof (userInput), "Is the above certificate acceptable (y/n)"); if (status != 0) { /* DBG_ERROR("RSA_WriteDataToFile",status);*/ goto CLEANUP; } if (userInput[0] == 'y' || userInput[0] == 'Y') cmpStatusInfo.certConfStatus = PKI_CMP_CERT_CONF_ACCEPT; else cmpStatusInfo.certConfStatus = PKI_CMP_CERT_CONF_REJECT; cmpStatusInfo.statusInfo = NULL; /* Step 2d: Call S_CMPCertConfirm to check status of request */ RSA_PrintMessage ("Sending confirmation...\n"); status = S_CMPCertConfirm (ctx, cmpInitParams.handle, certReq, certResp, &protectInfo, &cmpStatusInfo, &statusInfo); if (status != 0) { DBG_ERROR("S_CMPCertConfirm",status); goto CLEANUP; } RSA_PrintMessage ("Certificate Request Status\n"); status = RSA_PrintPkiStatusInfo (&statusInfo); if (status != 0) RSA_PrintError ("cmp.c", status); CLEANUP: B_DestroyKeyObject (&publicKey); B_DestroyKeyObject (&privateKey); C_DestroyListObject (&destList); C_DestroyNameObject (&requestorName); C_DestroyPKIMsgObject (&certReq); C_DestroyPKIMsgObject (&certResp); C_UnbindService (&db); C_FinalizeCertC (&ctx); return status; } /* end main */ static int SetSender (PKI_MSG_OBJ certReq) { int status = 0; PKI_SENDER_INFO pkiSenderInfo; T_memset ((POINTER)&pkiSenderInfo, 0, sizeof (pkiSenderInfo)); /* This information is determined by the CA's requirements. The CA will normally specify what general name the sender should use, along with the value that should be used for the key ID. In the case of the Trustpoint server specified above, the sender key ID is "interop". */ pkiSenderInfo.senderId.type = PKI_ENTITY_GENERALNAME_KEYID; pkiSenderInfo.senderId.id.generalNameKeyId.keyId.data = (POINTER)SENDER_KEYID; pkiSenderInfo.senderId.id.generalNameKeyId.keyId.len = T_strlen (SENDER_KEYID); pkiSenderInfo.digestAlgorithmId.algorithmId = DAI_PBM; status = C_SetPKIMsgSender (certReq, &pkiSenderInfo); if (status != 0) RSA_PrintError ("SetSender", status); return status; } /* end SetSender */ static int SetRecipient (PKI_MSG_OBJ certReq) { int status = 0; PKI_RECIPIENT_INFO pkiRecipientInfo; GENERAL_NAME generalName; NAME_OBJ recipient = NULL; T_memset ((POINTER)&pkiRecipientInfo, 0, sizeof (pkiRecipientInfo)); T_memset ((POINTER)&generalName, 0, sizeof (generalName)); status = C_CreateNameObject (&recipient); if (status != 0) { DBG_ERROR("C_CreateNameObject",status); goto CLEANUP; } /* This can be generalized using the demo utiltity function RSA_GetNameObject, but for the trustpoint server referenced at CMP_URL above, the DN expected is c=US,o=Trustpoint,cn=Test CA. */ status = C_AddNameAVA (recipient, AT_COUNTRY, AT_COUNTRY_LEN, VT_PRINTABLE_STRING, (POINTER)CMP_RECIP_COUNTRY, T_strlen (CMP_RECIP_COUNTRY), 1, NULL); if (status != 0) { DBG_ERROR("C_AddNameAVA",status); goto CLEANUP; } status = C_AddNameAVA (recipient, AT_ORGANIZATION, AT_ORGANIZATION_LEN, VT_PRINTABLE_STRING, (POINTER)CMP_RECIP_ORG, T_strlen (CMP_RECIP_ORG), 1, NULL); if (status != 0) { DBG_ERROR("C_AddNameAVA",status); goto CLEANUP; } #ifdef USE_ENTRUST_CA status = C_AddNameAVA (recipient, AT_UID, AT_UID_LEN, VT_PRINTABLE_STRING, (POINTER)CMP_RECIP_UID, T_strlen (CMP_RECIP_UID), 1, NULL); #else status = C_AddNameAVA (recipient, AT_COMMON_NAME, AT_COMMON_NAME_LEN, VT_PRINTABLE_STRING, (POINTER)CMP_RECIP_CN, T_strlen (CMP_RECIP_CN), 1, NULL); #endif if (status != 0) { DBG_ERROR("C_AddNameAVA",status); goto CLEANUP; } generalName.altNameType = CN_DIRECTORY_NAME; generalName.altName.directoryName = recipient; pkiRecipientInfo.type = PKI_RECIPIENT_GENERALNAME_KEYID; pkiRecipientInfo.info.generalNameKeyId.name = &generalName; status = C_SetPKIMsgRecipient (certReq, &pkiRecipientInfo); if (status != 0) RSA_PrintError ("SetRecipient", status); CLEANUP: C_DestroyNameObject (&recipient); return status; } /* end SetRecipient */