diff options
Diffstat (limited to '')
-rw-r--r-- | security/nss/lib/crmf/cmmfchal.c | 289 |
1 files changed, 289 insertions, 0 deletions
diff --git a/security/nss/lib/crmf/cmmfchal.c b/security/nss/lib/crmf/cmmfchal.c new file mode 100644 index 0000000000..2fee983c96 --- /dev/null +++ b/security/nss/lib/crmf/cmmfchal.c @@ -0,0 +1,289 @@ +/* -*- Mode: C; tab-width: 8 -*-*/ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "cmmf.h" +#include "cmmfi.h" +#include "sechash.h" +#include "genname.h" +#include "pk11func.h" +#include "cert.h" +#include "secitem.h" +#include "secmod.h" +#include "keyhi.h" + +static int +cmmf_create_witness_and_challenge(PLArenaPool *poolp, + CMMFChallenge *challenge, + long inRandom, + SECItem *senderDER, + SECKEYPublicKey *inPubKey, + void *passwdArg) +{ + SECItem *encodedRandNum; + SECItem encodedRandStr = { siBuffer, NULL, 0 }; + SECItem *dummy; + unsigned char *randHash, *senderHash, *encChal = NULL; + unsigned modulusLen = 0; + SECStatus rv = SECFailure; + CMMFRand randStr = { { siBuffer, NULL, 0 }, { siBuffer, NULL, 0 } }; + PK11SlotInfo *slot; + PK11SymKey *symKey = NULL; + CERTSubjectPublicKeyInfo *spki = NULL; + + encodedRandNum = SEC_ASN1EncodeInteger(poolp, &challenge->randomNumber, + inRandom); + if (!encodedRandNum) { + goto loser; + } + randHash = PORT_ArenaNewArray(poolp, unsigned char, SHA1_LENGTH); + senderHash = PORT_ArenaNewArray(poolp, unsigned char, SHA1_LENGTH); + if (randHash == NULL) { + goto loser; + } + rv = PK11_HashBuf(SEC_OID_SHA1, randHash, encodedRandNum->data, + (PRUint32)encodedRandNum->len); + if (rv != SECSuccess) { + goto loser; + } + rv = PK11_HashBuf(SEC_OID_SHA1, senderHash, senderDER->data, + (PRUint32)senderDER->len); + if (rv != SECSuccess) { + goto loser; + } + challenge->witness.data = randHash; + challenge->witness.len = SHA1_LENGTH; + + randStr.integer = *encodedRandNum; + randStr.senderHash.data = senderHash; + randStr.senderHash.len = SHA1_LENGTH; + dummy = SEC_ASN1EncodeItem(NULL, &encodedRandStr, &randStr, + CMMFRandTemplate); + if (dummy != &encodedRandStr) { + rv = SECFailure; + goto loser; + } + /* XXXX Now I have to encrypt encodedRandStr and stash it away. */ + modulusLen = SECKEY_PublicKeyStrength(inPubKey); + encChal = PORT_ArenaNewArray(poolp, unsigned char, modulusLen); + if (encChal == NULL) { + rv = SECFailure; + goto loser; + } + slot = PK11_GetBestSlotWithAttributes(CKM_RSA_PKCS, CKF_WRAP, 0, passwdArg); + if (slot == NULL) { + rv = SECFailure; + goto loser; + } + (void)PK11_ImportPublicKey(slot, inPubKey, PR_FALSE); + /* In order to properly encrypt the data, we import as a symmetric + * key, and then wrap that key. That in essence encrypts the data. + * This is the method recommended in the PK11 world in order + * to prevent threading issues as well as breaking any other semantics + * the PK11 libraries depend on. + */ + symKey = PK11_ImportSymKey(slot, CKM_RSA_PKCS, PK11_OriginGenerated, + CKA_VALUE, &encodedRandStr, passwdArg); + if (symKey == NULL) { + rv = SECFailure; + goto loser; + } + challenge->challenge.data = encChal; + challenge->challenge.len = modulusLen; + rv = PK11_PubWrapSymKey(CKM_RSA_PKCS, inPubKey, symKey, + &challenge->challenge); + PK11_FreeSlot(slot); + if (rv != SECSuccess) { + goto loser; + } + rv = SECITEM_CopyItem(poolp, &challenge->senderDER, senderDER); + crmf_get_public_value(inPubKey, &challenge->key); +/* Fall through */ +loser: + if (spki != NULL) { + SECKEY_DestroySubjectPublicKeyInfo(spki); + } + if (encodedRandStr.data != NULL) { + PORT_Free(encodedRandStr.data); + } + if (encodedRandNum != NULL) { + SECITEM_FreeItem(encodedRandNum, PR_TRUE); + } + if (symKey != NULL) { + PK11_FreeSymKey(symKey); + } + return rv; +} + +static SECStatus +cmmf_create_first_challenge(CMMFPOPODecKeyChallContent *challContent, + long inRandom, + SECItem *senderDER, + SECKEYPublicKey *inPubKey, + void *passwdArg) +{ + SECOidData *oidData; + CMMFChallenge *challenge; + SECAlgorithmID *algId; + PLArenaPool *poolp; + SECStatus rv; + + oidData = SECOID_FindOIDByTag(SEC_OID_SHA1); + if (oidData == NULL) { + return SECFailure; + } + poolp = challContent->poolp; + challenge = PORT_ArenaZNew(poolp, CMMFChallenge); + if (challenge == NULL) { + return SECFailure; + } + algId = challenge->owf = PORT_ArenaZNew(poolp, SECAlgorithmID); + if (algId == NULL) { + return SECFailure; + } + rv = SECITEM_CopyItem(poolp, &algId->algorithm, &oidData->oid); + if (rv != SECSuccess) { + return SECFailure; + } + rv = cmmf_create_witness_and_challenge(poolp, challenge, inRandom, + senderDER, inPubKey, passwdArg); + challContent->challenges[0] = (rv == SECSuccess) ? challenge : NULL; + challContent->numChallenges++; + return rv; +} + +CMMFPOPODecKeyChallContent * +CMMF_CreatePOPODecKeyChallContent(void) +{ + PLArenaPool *poolp; + CMMFPOPODecKeyChallContent *challContent; + + poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE); + if (poolp == NULL) { + return NULL; + } + challContent = PORT_ArenaZNew(poolp, CMMFPOPODecKeyChallContent); + if (challContent == NULL) { + PORT_FreeArena(poolp, PR_FALSE); + return NULL; + } + challContent->poolp = poolp; + return challContent; +} + +SECStatus +CMMF_POPODecKeyChallContentSetNextChallenge(CMMFPOPODecKeyChallContent *inDecKeyChall, + long inRandom, + CERTGeneralName *inSender, + SECKEYPublicKey *inPubKey, + void *passwdArg) +{ + CMMFChallenge *curChallenge; + PLArenaPool *genNamePool = NULL, *poolp; + SECStatus rv; + SECItem *genNameDER; + void *mark; + + PORT_Assert(inDecKeyChall != NULL && + inSender != NULL && + inPubKey != NULL); + + if (inDecKeyChall == NULL || + inSender == NULL || inPubKey == NULL) { + return SECFailure; + } + poolp = inDecKeyChall->poolp; + mark = PORT_ArenaMark(poolp); + + genNamePool = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE); + genNameDER = CERT_EncodeGeneralName(inSender, NULL, genNamePool); + if (genNameDER == NULL) { + rv = SECFailure; + goto loser; + } + if (inDecKeyChall->challenges == NULL) { + inDecKeyChall->challenges = + PORT_ArenaZNewArray(poolp, CMMFChallenge *, (CMMF_MAX_CHALLENGES + 1)); + inDecKeyChall->numAllocated = CMMF_MAX_CHALLENGES; + } + + if (inDecKeyChall->numChallenges >= inDecKeyChall->numAllocated) { + rv = SECFailure; + goto loser; + } + + if (inDecKeyChall->numChallenges == 0) { + rv = cmmf_create_first_challenge(inDecKeyChall, inRandom, + genNameDER, inPubKey, passwdArg); + } else { + curChallenge = PORT_ArenaZNew(poolp, CMMFChallenge); + if (curChallenge == NULL) { + rv = SECFailure; + goto loser; + } + rv = cmmf_create_witness_and_challenge(poolp, curChallenge, inRandom, + genNameDER, inPubKey, + passwdArg); + if (rv == SECSuccess) { + inDecKeyChall->challenges[inDecKeyChall->numChallenges] = + curChallenge; + inDecKeyChall->numChallenges++; + } + } + if (rv != SECSuccess) { + goto loser; + } + PORT_ArenaUnmark(poolp, mark); + PORT_FreeArena(genNamePool, PR_FALSE); + return SECSuccess; + +loser: + PORT_ArenaRelease(poolp, mark); + if (genNamePool != NULL) { + PORT_FreeArena(genNamePool, PR_FALSE); + } + PORT_Assert(rv != SECSuccess); + return rv; +} + +SECStatus +CMMF_DestroyPOPODecKeyRespContent(CMMFPOPODecKeyRespContent *inDecKeyResp) +{ + PORT_Assert(inDecKeyResp != NULL); + if (inDecKeyResp != NULL && inDecKeyResp->poolp != NULL) { + PORT_FreeArena(inDecKeyResp->poolp, PR_FALSE); + } + return SECSuccess; +} + +int +CMMF_POPODecKeyRespContentGetNumResponses(CMMFPOPODecKeyRespContent *inRespCont) +{ + int numResponses = 0; + + PORT_Assert(inRespCont != NULL); + if (inRespCont == NULL) { + return 0; + } + + while (inRespCont->responses[numResponses] != NULL) { + numResponses++; + } + return numResponses; +} + +SECStatus +CMMF_POPODecKeyRespContentGetResponse(CMMFPOPODecKeyRespContent *inRespCont, + int inIndex, + long *inDest) +{ + PORT_Assert(inRespCont != NULL); + + if (inRespCont == NULL || inIndex < 0 || + inIndex >= CMMF_POPODecKeyRespContentGetNumResponses(inRespCont)) { + return SECFailure; + } + *inDest = DER_GetInteger(inRespCont->responses[inIndex]); + return (*inDest == -1) ? SECFailure : SECSuccess; +} |