| RSA BSAFE Cert-C |
Certificate Components for C |
| Crypto-C 6.2.1 Developer's Guide | ||
| Search |
/* $Id: dhcert.c,v 1.3 2004/03/02 05:18:32 gsingh Exp $ */ /* dhcert.c ** Copyright (c) 2002, 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 program generates a BER-encoded Algorithm Identifier containing ** Diffie-Hellman Parameters in a dhpublicnumber. These parameters are ** then used to perform Diffie-Hellman key agreement. */ #include "certc.h" #include "demoutil.h" #include "rsacsp.h" #include "textsurr.h" /* BER-encoded Object Identifier for dhpublicnumber - 1.2.840.10046.2.1 */ #define DH_X942_OID_LEN 9 static unsigned char DH_X942_OID[DH_X942_OID_LEN] = { 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3e, 0x02, 0x01 }; /* This routine generates Diffie-Hellman parameters and outputs the * parameters as a BER-encoded AlgorithmIdentifier containing the encoded * DomainParameters as defined in RFC 2459, section 7.3.2, with p, q, and g. * * Note that the calling application must free algId->data. */ static int GenerateDHAlgId (ITEM *algIdBer, B_ALGORITHM_OBJ randomAlgorithm, A_SURRENDER_CTX *surrenderCtx, CERTC_CTX ctx); /* This routine takes a BER-encoded algorithm ID with a dhpublicnumber * and fills in an A_DH_KEY_AGREE_PARAMS structure with that information. * * Note that the calling application must call T_free on * dhParams->prime.data and dhParams->base.data. */ static int GetDHParams (A_DH_KEY_AGREE_PARAMS *dhParams, ITEM *algIdBer, CERTC_CTX ctx); /* This routine takes in a set of Diffie-Hellman parameters (See dhparam.c * for an example which generates a set of Diffie-Hellman parameters. Note * that the parameters may be transmitted in the clear and both parties who * wish to participate in the key agreement protocol must begin with the * same set of parameters.) and performs phase 1 of the DH key agreement * scheme. The output publicValue is to be sent to the other party; the * output stateInfo contains the private value and will be used to resume * DH key agreement when a restored algorithm object is needed for phase * 2 of the protocol. * * Note that the calling application must free publicValue->data and zeroize * and free stateInfo when it is no longer needed. Needless to say, the * private value in the stateInfo is sensitive data and should be treated * like any other private key. */ static int GenerateDHPhase1Values (A_DH_KEY_AGREE_PARAMS *dhParams, ITEM *publicValue, ITEM *stateInfo, B_ALGORITHM_OBJ randomAlgorithm, A_SURRENDER_CTX *surrenderCtx); /* This function takes the other party's public value and combines it with * the private value in the stateInfo to derive the secretValue. * * Note that the calling application must zeroize and free secretValue->data * when it is no longer needed. */ static int GenerateDHPhase2Secret (ITEM *otherPublicValue, ITEM *stateInfo, ITEM *secretValue, A_SURRENDER_CTX *surrenderCtx); /* Number of service providers */ #define SP_COUNT 2 int main (int argc, char *argv[]) { int status; 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 }; B_ALGORITHM_OBJ randomAlgorithm; A_SURRENDER_CTX *surrenderCtx; ITEM algIdBer = {NULL, 0}; ITEM alicePublic = {NULL, 0}, alicePrivate = {NULL, 0}; ITEM bobPublic = {NULL, 0}, bobPrivate = {NULL, 0}; ITEM aliceSecret = {NULL, 0}, bobSecret = {NULL, 0}; A_DH_KEY_AGREE_PARAMS dhParams = {0}; status = RSA_SetOptions (&logParams, argc, argv); if (status != 0) goto CLEANUP; spTable[0].type = SPT_CRYPTO; spTable[0].name = "Default crypto provider"; spTable[0].Initialize = S_InitializeDefaultCSP; spTable[1].type = SPT_SURRENDER; spTable[1].name = "Sample Surrender Context"; spTable[1].Initialize = S_InitializeTextSurrender; spParams[0] = NULL; spParams[1] = NULL; 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 = C_GetRandomObject (ctx, &randomAlgorithm); if (status != 0) goto CLEANUP; surrenderCtx = C_GetSurrenderCtx (ctx); status = GenerateDHAlgId (&algIdBer, randomAlgorithm, surrenderCtx, ctx); if (status != 0) goto CLEANUP; status = RSA_WriteDataToFile (algIdBer.data, algIdBer.len, "Enter name of file to store BER-encoded DH Algorithm ID"); if (status != 0 && status != RSA_DEMO_E_CANCEL) goto CLEANUP; status = GetDHParams (&dhParams, &algIdBer, ctx); if (status != 0) goto CLEANUP; RSA_PrintMessage ("\n Key Agreement -- Phase 1\n"); RSA_PrintMessage (" ========================\n"); /* Both parties start with a common set of parameters and generate public and private values. Note that in this example, Alice and Bob are sharing the same random algorithm object. This is simply done to present the same GenerateDHPhase1Values() function with a random algorithm object in a different state so that Alice and Bob generate different public/private values. In a real-world situation, Alice and Bob would both have different random algorithm objects which were independently-seeded. */ status = GenerateDHPhase1Values (&dhParams, &alicePublic, &alicePrivate, randomAlgorithm, surrenderCtx); if (status != 0) goto CLEANUP; RSA_PrintBuf ("\nAlice's Public Value", alicePublic.data, alicePublic.len); status = GenerateDHPhase1Values (&dhParams, &bobPublic, &bobPrivate, randomAlgorithm, surrenderCtx); if (status != 0) goto CLEANUP; RSA_PrintBuf ("\nBob's Public Value", bobPublic.data, bobPublic.len); RSA_PrintMessage ("\n Key Agreement -- Phase 2\n"); RSA_PrintMessage (" ========================\n"); RSA_PrintMessage (" Both sides exchange public values...\n"); status = GenerateDHPhase2Secret (&bobPublic, &alicePrivate, &aliceSecret, surrenderCtx); if (status != 0) goto CLEANUP; RSA_PrintBuf ("\nSecret Value Derived by Alice", aliceSecret.data, aliceSecret.len); status = GenerateDHPhase2Secret (&alicePublic, &bobPrivate, &bobSecret, surrenderCtx); if (status != 0) goto CLEANUP; RSA_PrintBuf ("\nSecretValue Derived by Bob", bobSecret.data, bobSecret.len); if (aliceSecret.len != bobSecret.len) { status = RSA_DEMO_E_INFO_DOES_NOT_VERIFY; goto CLEANUP; } if (T_memcmp (aliceSecret.data, bobSecret.data, bobSecret.len) != 0) { status = RSA_DEMO_E_INFO_DOES_NOT_VERIFY; goto CLEANUP; } RSA_PrintMessage ("\nSuccess! Keys agree!!\n"); CLEANUP: if (status != 0) RSA_PrintError ("dhcert", status); T_free (algIdBer.data); T_free (dhParams.prime.data); T_free (dhParams.base.data); T_memset (alicePrivate.data, 0, alicePrivate.len); T_memset (aliceSecret.data, 0, aliceSecret.len); T_memset (bobPrivate.data, 0, bobPrivate.len); T_memset (bobSecret.data, 0, bobSecret.len); T_free (alicePublic.data); T_free (alicePrivate.data); T_free (aliceSecret.data); T_free (bobPublic.data); T_free (bobPrivate.data); T_free (bobSecret.data); C_FinalizeCertC (&ctx); return (status); } /* end main */ static int GenerateDHAlgId (ITEM *algIdBer, B_ALGORITHM_OBJ randomAlgorithm, A_SURRENDER_CTX *surrenderCtx, CERTC_CTX ctx) { int status; B_ALGORITHM_OBJ paramGenObj = (B_ALGORITHM_OBJ)NULL_PTR; B_ALGORITHM_OBJ keyGenObj = (B_ALGORITHM_OBJ)NULL_PTR; B_DSA_PARAM_GEN_PARAMS dsaParamInfo; B_ALGORITHM_METHOD *dsaChooser[] = { &AM_DSA_PARAM_GEN, (B_ALGORITHM_METHOD *)NULL_PTR }; A_DSA_PARAMS *dsaParams; LIST_OBJ parametersList = (LIST_OBJ)NULL_PTR; LIST_OBJ algIdList = (LIST_OBJ)NULL_PTR; ITEM p = {NULL_PTR, 0}, q = {NULL_PTR, 0}, g = {NULL_PTR, 0}; ITEM domainParameters = {NULL_PTR, 0}, dhOid; algIdBer->data = NULL_PTR; algIdBer->len = 0; status = B_CreateAlgorithmObject (¶mGenObj); if (status != 0) goto CLEANUP; status = RSA_GetInteger ((int *)&dsaParamInfo.primeBits, "Enter desired prime size in bits (512-2048)"); if (status != 0) goto CLEANUP; status = B_SetAlgorithmInfo (paramGenObj, AI_DSAParamGen, (POINTER)&dsaParamInfo); if (status != 0) goto CLEANUP; status = B_GenerateInit (paramGenObj, dsaChooser, surrenderCtx); if (status != 0) goto CLEANUP; status = B_CreateAlgorithmObject (&keyGenObj); if (status != 0) goto CLEANUP; RSA_PrintMessage ("Generating Parameters...\n"); status = B_GenerateParameters (paramGenObj, keyGenObj, randomAlgorithm, surrenderCtx); if (status != 0) goto CLEANUP; RSA_PrintMessage ("\n"); status = B_GetAlgorithmInfo ((POINTER *)&dsaParams, keyGenObj, AI_DSAKeyGen); if (status != 0) goto CLEANUP; /* Construct the DomainParameters with p, q, and g only. DomainParameters ::= SEQUENCE { p INTEGER, -- odd prime, p=jq +1 g INTEGER, -- generator, g q INTEGER, -- factor of p-1 j INTEGER OPTIONAL, -- subgroup factor validationParms ValidationParms OPTIONAL } */ status = C_DEREncodeString (ctx, VT_INTEGER, VTC_UNIVERSAL, dsaParams->prime.data, dsaParams->prime.len, &p.data, &p.len); if (status != 0) goto CLEANUP; status = C_DEREncodeString (ctx, VT_INTEGER, VTC_UNIVERSAL, dsaParams->subPrime.data, dsaParams->subPrime.len, &q.data, &q.len); if (status != 0) goto CLEANUP; status = C_DEREncodeString (ctx, VT_INTEGER, VTC_UNIVERSAL, dsaParams->base.data, dsaParams->base.len, &g.data, &g.len); if (status != 0) goto CLEANUP; /* Put all the contents of the SEQUENCE in a LIST_OBJ */ status = C_CreateListObject (¶metersList); if (status != 0) goto CLEANUP; status = C_AddItemToList (parametersList, &p, (unsigned int *)NULL_PTR); if (status != 0) goto CLEANUP; status = C_AddItemToList (parametersList, &g, (unsigned int *)NULL_PTR); if (status != 0) goto CLEANUP; status = C_AddItemToList (parametersList, &q, (unsigned int *)NULL_PTR); if (status != 0) goto CLEANUP; status = C_DEREncodeList (ctx, VT_SEQUENCE, VTC_UNIVERSAL, parametersList, &domainParameters.data, &domainParameters.len); if (status != 0) goto CLEANUP; /* Assemble our AlgorithmIdentifier AlgorithmIdentifier ::= SEQUENCE { algorithm OBJECT IDENTIFIER, parameters ANY DEFINED BY algorithm OPTIONAL } */ dhOid.data = DH_X942_OID; dhOid.len = DH_X942_OID_LEN; status = C_CreateListObject (&algIdList); if (status != 0) goto CLEANUP; status = C_AddItemToList (algIdList, &dhOid, (unsigned int *)NULL_PTR); if (status != 0) goto CLEANUP; status = C_AddItemToList (algIdList, &domainParameters, (unsigned int *)NULL_PTR); if (status != 0) goto CLEANUP; status = C_DEREncodeList (ctx, VT_SEQUENCE, VTC_UNIVERSAL, algIdList, &algIdBer->data, &algIdBer->len); CLEANUP: if (status != 0) { T_free (algIdBer->data); algIdBer->data = NULL_PTR; algIdBer->len = 0; RSA_PrintError ("GenerateDHAlgId", status); } T_free (p.data); T_free (q.data); T_free (g.data); T_free (domainParameters.data); C_DestroyListObject (¶metersList); C_DestroyListObject (&algIdList); B_DestroyAlgorithmObject (&keyGenObj); B_DestroyAlgorithmObject (¶mGenObj); return status; } /* end GenerateDHAlgId */ static int GetDHParams (A_DH_KEY_AGREE_PARAMS *dhParams, ITEM *algIdBer, CERTC_CTX ctx) { int status; int tag; unsigned int tagClass; LIST_OBJ algIdList = (LIST_OBJ)NULL_PTR; LIST_OBJ parametersList = (LIST_OBJ)NULL_PTR; ITEM *dhOid, *domainParameters; ITEM *pBer, *gBer; T_memset ((POINTER)dhParams, 0, sizeof (*dhParams)); /* Pull apart the AlgorithmIdentifier AlgorithmIdentifier ::= SEQUENCE { algorithm OBJECT IDENTIFIER, parameters ANY DEFINED BY algorithm OPTIONAL } */ status = C_CreateListObject (&algIdList); if (status != 0) goto CLEANUP; status = C_BERDecodeList (ctx, algIdBer->data, algIdBer->len, &tag, &tagClass, algIdList); if (status != 0) goto CLEANUP; if (tag != VT_SEQUENCE) { status = RSA_DEMO_E_INVALID_TAG; goto CLEANUP; } status = C_GetListObjectEntry (algIdList, 0, (POINTER *)&dhOid); if (status != 0) goto CLEANUP; status = C_GetListObjectEntry (algIdList, 1, (POINTER *)&domainParameters); if (status != 0) goto CLEANUP; /* Check the object identifier to make sure that it is a dhpublicnumber */ if (!(dhOid->len == DH_X942_OID_LEN && !T_memcmp (dhOid->data, DH_X942_OID, dhOid->len))) { status = RSA_DEMO_E_NOT_IMPLEMENTED; goto CLEANUP; } /* Pull apart our DomainParameters DomainParameters ::= SEQUENCE { p INTEGER, -- odd prime, p=jq +1 g INTEGER, -- generator, g q INTEGER, -- factor of p-1 j INTEGER OPTIONAL, -- subgroup factor validationParms ValidationParms OPTIONAL } */ status = C_CreateListObject (¶metersList); if (status != 0) goto CLEANUP; status = C_BERDecodeList (ctx, domainParameters->data, domainParameters->len, &tag, &tagClass, parametersList); if (status != 0) goto CLEANUP; if (tag != VT_SEQUENCE) { status = RSA_DEMO_E_INVALID_TAG; goto CLEANUP; } /* Extract p and g */ status = C_GetListObjectEntry (parametersList, 0, (POINTER *)&pBer); if (status != 0) goto CLEANUP; status = C_GetListObjectEntry (parametersList, 1, (POINTER *)&gBer); if (status != 0) goto CLEANUP; status = C_BERDecodeString (ctx, pBer->data, pBer->len, &tag, &tagClass, &dhParams->prime.data, &dhParams->prime.len); if (status != 0) goto CLEANUP; if (tag != VT_INTEGER) { status = RSA_DEMO_E_INVALID_TAG; goto CLEANUP; } status = C_BERDecodeString (ctx, gBer->data, gBer->len, &tag, &tagClass, &dhParams->base.data, &dhParams->base.len); if (status != 0) goto CLEANUP; if (tag != VT_INTEGER) { status = RSA_DEMO_E_INVALID_TAG; goto CLEANUP; } /* Just set the length of the desired private value to be the same as the prime length */ dhParams->exponentBits = B_IntegerBits (dhParams->prime.data, dhParams->prime.len); CLEANUP: if (status != 0) { T_free (dhParams->prime.data); T_free (dhParams->base.data); T_memset ((POINTER)dhParams, 0, sizeof (*dhParams)); RSA_PrintError ("GenerateDHParams", status); } C_DestroyListObject (¶metersList); C_DestroyListObject (&algIdList); return status; } /* end GetDHParams */ static int GenerateDHPhase1Values (A_DH_KEY_AGREE_PARAMS *dhParams, ITEM *publicValue, ITEM *stateInfo, B_ALGORITHM_OBJ randomAlgorithm, A_SURRENDER_CTX *surrenderCtx) { int status; B_ALGORITHM_OBJ dhAgree = NULL; ITEM bsfStateInfo = {NULL, 0}; B_ALGORITHM_METHOD *DH_AGREE_SAMPLE_CHOOSER[] = { &AM_DH_KEY_AGREE, (B_ALGORITHM_METHOD *)NULL_PTR }; A_DH_KEY_AGREE_PARAMS *getParams = NULL; publicValue->data = NULL; publicValue->len = 0; stateInfo->data = NULL; stateInfo->len = 0; /* Creating and setting the dhAgree object with the algorithm * information for creating the phase 1 keys. */ status = B_CreateAlgorithmObject (&dhAgree); if (status != 0) goto CLEANUP; status = B_SetAlgorithmInfo (dhAgree, AI_DHKeyAgree, (POINTER)dhParams); if (status != 0) goto CLEANUP; status = B_KeyAgreeInit (dhAgree, NULL, DH_AGREE_SAMPLE_CHOOSER, surrenderCtx); if (status != 0) goto CLEANUP; /* Find out how big the prime is so we know how many bytes to * allocate for the public value buffer. */ status = B_GetAlgorithmInfo ((POINTER *)&getParams, dhAgree, AI_DHKeyAgree); if (status != 0) goto CLEANUP; publicValue->len = getParams->prime.len; publicValue->data = T_malloc (publicValue->len); if (publicValue->data == NULL) { status = RSA_DEMO_E_ALLOC; goto CLEANUP; } status = B_KeyAgreePhase1 (dhAgree, publicValue->data, &publicValue->len, publicValue->len, randomAlgorithm, surrenderCtx); if (status != 0) goto CLEANUP; /* Obtaining the state information from the algorithm object * so it can be used to restore the algorithm object in order to * resume this operation later. */ status = B_GetAlgorithmState (&bsfStateInfo, dhAgree); if (status != 0) goto CLEANUP; /* Since bsfStateInfo is a pointer to memory belonging to the Crypto-C * library, we make our own copy for use later because the buffer which * bsfStateInfo points might be changed by subsequent Crypto-C calls. */ stateInfo->len = bsfStateInfo.len; stateInfo->data = T_malloc (bsfStateInfo.len); if (stateInfo->data == NULL) { status = RSA_DEMO_E_ALLOC; goto CLEANUP; } T_memcpy (stateInfo->data, bsfStateInfo.data, stateInfo->len); CLEANUP: if (status != 0) { T_free (publicValue->data); publicValue->data = NULL; publicValue->len = 0; T_memset (stateInfo->data, 0, stateInfo->len); T_free (stateInfo->data); stateInfo->data = NULL; stateInfo->len = 0; RSA_PrintError ("GenerateDHPhase1Values", status); } B_DestroyAlgorithmObject (&dhAgree); return status; } /* end GenerateDHPhase1Values */ static int GenerateDHPhase2Secret (ITEM *otherPublicValue, ITEM *stateInfo, ITEM *secretValue, A_SURRENDER_CTX *surrenderCtx) { int status; B_ALGORITHM_OBJ dhAgree = NULL; B_ALGORITHM_METHOD *DH_AGREE_SAMPLE_CHOOSER[] = { &AM_DH_KEY_AGREE, (B_ALGORITHM_METHOD *)NULL_PTR }; A_DH_KEY_AGREE_PARAMS *getParams = NULL; secretValue->data = NULL; secretValue->len = 0; status = B_CreateAlgorithmObject (&dhAgree); if (status != 0) goto CLEANUP; /* Restore the algorithm object with the information retrieved following * Phase 1. This will allow us to continue with Phase 2 to derive a * secret value given our private value and the other party's public * value. */ status = B_SetAlgorithmState (dhAgree, AI_DHKeyAgree, stateInfo, DH_AGREE_SAMPLE_CHOOSER); if (status != 0) goto CLEANUP; /* Find out how big the prime is so we know how many bytes to * allocate for the secret value buffer. */ status = B_GetAlgorithmInfo ((POINTER *)&getParams, dhAgree, AI_DHKeyAgree); if (status != 0) goto CLEANUP; secretValue->len = getParams->prime.len; secretValue->data = T_malloc (secretValue->len); if (secretValue->data == NULL) { status = RSA_DEMO_E_ALLOC; goto CLEANUP; } status = B_KeyAgreePhase2 (dhAgree, secretValue->data, &secretValue->len, secretValue->len, otherPublicValue->data, otherPublicValue->len, surrenderCtx); if (status != 0) goto CLEANUP; CLEANUP: if (status != 0) { T_memset (secretValue->data, 0, secretValue->len); T_free (secretValue->data); secretValue->data = NULL; secretValue->len = 0; RSA_PrintError ("GenerateDHPhase2Secret", status); } B_DestroyAlgorithmObject (&dhAgree); return status; } /* end GenerateDHPhase2Secret */