michael@0: /* -*- Mode: C; tab-width: 8 -*-*/ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "cmmf.h" michael@0: #include "cmmfi.h" michael@0: #include "secitem.h" michael@0: #include "pk11func.h" michael@0: #include "secder.h" michael@0: #include "sechash.h" michael@0: michael@0: CMMFPOPODecKeyChallContent* michael@0: CMMF_CreatePOPODecKeyChallContentFromDER(const char *buf, long len) michael@0: { michael@0: PLArenaPool *poolp; michael@0: CMMFPOPODecKeyChallContent *challContent; michael@0: SECStatus rv; michael@0: michael@0: poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE); michael@0: if (poolp == NULL) { michael@0: return NULL; michael@0: } michael@0: challContent = PORT_ArenaZNew(poolp, CMMFPOPODecKeyChallContent); michael@0: if (challContent == NULL) { michael@0: goto loser; michael@0: } michael@0: challContent->poolp = poolp; michael@0: rv = SEC_ASN1Decode(poolp, challContent, michael@0: CMMFPOPODecKeyChallContentTemplate, buf, len); michael@0: if (rv != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: if (challContent->challenges) { michael@0: while (challContent->challenges[challContent->numChallenges] != NULL) { michael@0: challContent->numChallenges++; michael@0: } michael@0: challContent->numAllocated = challContent->numChallenges; michael@0: } michael@0: return challContent; michael@0: loser: michael@0: if (poolp != NULL) { michael@0: PORT_FreeArena(poolp, PR_FALSE); michael@0: } michael@0: return NULL; michael@0: } michael@0: michael@0: int michael@0: CMMF_POPODecKeyChallContentGetNumChallenges michael@0: (CMMFPOPODecKeyChallContent *inKeyChallCont) michael@0: { michael@0: PORT_Assert(inKeyChallCont != NULL); michael@0: if (inKeyChallCont == NULL) { michael@0: return 0; michael@0: } michael@0: return inKeyChallCont->numChallenges; michael@0: } michael@0: michael@0: SECItem* michael@0: CMMF_POPODecKeyChallContentGetPublicValue michael@0: (CMMFPOPODecKeyChallContent *inKeyChallCont, michael@0: int inIndex) michael@0: { michael@0: PORT_Assert(inKeyChallCont != NULL); michael@0: if (inKeyChallCont == NULL || (inIndex > inKeyChallCont->numChallenges-1)|| michael@0: inIndex < 0) { michael@0: return NULL; michael@0: } michael@0: return SECITEM_DupItem(&inKeyChallCont->challenges[inIndex]->key); michael@0: } michael@0: michael@0: static SECAlgorithmID* michael@0: cmmf_get_owf(CMMFPOPODecKeyChallContent *inChalCont, michael@0: int inIndex) michael@0: { michael@0: int i; michael@0: michael@0: for (i=inIndex; i >= 0; i--) { michael@0: if (inChalCont->challenges[i]->owf != NULL) { michael@0: return inChalCont->challenges[i]->owf; michael@0: } michael@0: } michael@0: return NULL; michael@0: } michael@0: michael@0: SECStatus michael@0: CMMF_POPODecKeyChallContDecryptChallenge(CMMFPOPODecKeyChallContent *inChalCont, michael@0: int inIndex, michael@0: SECKEYPrivateKey *inPrivKey) michael@0: { michael@0: CMMFChallenge *challenge; michael@0: SECItem *decryptedRand=NULL; michael@0: PLArenaPool *poolp = NULL; michael@0: SECAlgorithmID *owf; michael@0: SECStatus rv = SECFailure; michael@0: SECOidTag tag; michael@0: CMMFRand randStr; michael@0: SECItem hashItem; michael@0: unsigned char hash[HASH_LENGTH_MAX]; michael@0: michael@0: PORT_Assert(inChalCont != NULL && inPrivKey != NULL); michael@0: if (inChalCont == NULL || inIndex <0 || inIndex > inChalCont->numChallenges michael@0: || inPrivKey == NULL){ michael@0: return SECFailure; michael@0: } michael@0: michael@0: poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE); michael@0: if (poolp == NULL) { michael@0: goto loser; michael@0: } michael@0: michael@0: challenge = inChalCont->challenges[inIndex]; michael@0: decryptedRand = SECITEM_AllocItem(poolp, NULL, challenge->challenge.len); michael@0: if (decryptedRand == NULL) { michael@0: goto loser; michael@0: } michael@0: rv = PK11_PrivDecryptPKCS1(inPrivKey, decryptedRand->data, michael@0: &decryptedRand->len, decryptedRand->len, michael@0: challenge->challenge.data, challenge->challenge.len); michael@0: if (rv != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: michael@0: rv = SEC_ASN1DecodeItem(poolp, &randStr, CMMFRandTemplate, michael@0: decryptedRand); michael@0: if (rv != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: rv = SECFailure; /* Just so that when we do go to loser, michael@0: * I won't have to set it again. michael@0: */ michael@0: owf = cmmf_get_owf(inChalCont, inIndex); michael@0: if (owf == NULL) { michael@0: /* No hashing algorithm came with the challenges. Can't verify */ michael@0: goto loser; michael@0: } michael@0: /* Verify the hashes in the challenge */ michael@0: tag = SECOID_FindOIDTag(&owf->algorithm); michael@0: hashItem.len = HASH_ResultLenByOidTag(tag); michael@0: if (!hashItem.len) michael@0: goto loser; /* error code has been set */ michael@0: michael@0: rv = PK11_HashBuf(tag, hash, randStr.integer.data, randStr.integer.len); michael@0: if (rv != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: hashItem.data = hash; michael@0: if (SECITEM_CompareItem(&hashItem, &challenge->witness) != SECEqual) { michael@0: /* The hash for the data we decrypted doesn't match the hash provided michael@0: * in the challenge. Bail out. michael@0: */ michael@0: PORT_SetError(SEC_ERROR_BAD_DATA); michael@0: rv = SECFailure; michael@0: goto loser; michael@0: } michael@0: rv = PK11_HashBuf(tag, hash, challenge->senderDER.data, michael@0: challenge->senderDER.len); michael@0: if (rv != SECSuccess) { michael@0: goto loser; michael@0: } michael@0: if (SECITEM_CompareItem(&hashItem, &randStr.senderHash) != SECEqual) { michael@0: /* The hash for the data we decrypted doesn't match the hash provided michael@0: * in the challenge. Bail out. michael@0: */ michael@0: PORT_SetError(SEC_ERROR_BAD_DATA); michael@0: rv = SECFailure; michael@0: goto loser; michael@0: } michael@0: /* All of the hashes have verified, so we can now store the integer away.*/ michael@0: rv = SECITEM_CopyItem(inChalCont->poolp, &challenge->randomNumber, michael@0: &randStr.integer); michael@0: loser: michael@0: if (poolp) { michael@0: PORT_FreeArena(poolp, PR_FALSE); michael@0: } michael@0: return rv; michael@0: } michael@0: michael@0: SECStatus michael@0: CMMF_POPODecKeyChallContentGetRandomNumber michael@0: (CMMFPOPODecKeyChallContent *inKeyChallCont, michael@0: int inIndex, michael@0: long *inDest) michael@0: { michael@0: CMMFChallenge *challenge; michael@0: michael@0: PORT_Assert(inKeyChallCont != NULL); michael@0: if (inKeyChallCont == NULL || inIndex > 0 || inIndex >= michael@0: inKeyChallCont->numChallenges) { michael@0: return SECFailure; michael@0: } michael@0: challenge = inKeyChallCont->challenges[inIndex]; michael@0: if (challenge->randomNumber.data == NULL) { michael@0: /* There is no random number here, nothing to see. */ michael@0: return SECFailure; michael@0: } michael@0: *inDest = DER_GetInteger(&challenge->randomNumber); michael@0: return (*inDest == -1) ? SECFailure : SECSuccess; michael@0: } michael@0: michael@0: SECStatus michael@0: CMMF_EncodePOPODecKeyRespContent(long *inDecodedRand, michael@0: int inNumRand, michael@0: CRMFEncoderOutputCallback inCallback, michael@0: void *inArg) michael@0: { michael@0: PLArenaPool *poolp; michael@0: CMMFPOPODecKeyRespContent *response; michael@0: SECItem *currItem; michael@0: SECStatus rv=SECFailure; michael@0: int i; michael@0: michael@0: poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE); michael@0: if (poolp == NULL) { michael@0: return SECFailure; michael@0: } michael@0: response = PORT_ArenaZNew(poolp, CMMFPOPODecKeyRespContent); michael@0: if (response == NULL) { michael@0: goto loser; michael@0: } michael@0: response->responses = PORT_ArenaZNewArray(poolp, SECItem*, inNumRand+1); michael@0: if (response->responses == NULL) { michael@0: goto loser; michael@0: } michael@0: for (i=0; iresponses[i] = PORT_ArenaZNew(poolp,SECItem); michael@0: if (currItem == NULL) { michael@0: goto loser; michael@0: } michael@0: currItem = SEC_ASN1EncodeInteger(poolp, currItem, inDecodedRand[i]); michael@0: if (currItem == NULL) { michael@0: goto loser; michael@0: } michael@0: } michael@0: rv = cmmf_user_encode(response, inCallback, inArg, michael@0: CMMFPOPODecKeyRespContentTemplate); michael@0: loser: michael@0: if (poolp != NULL) { michael@0: PORT_FreeArena(poolp, PR_FALSE); michael@0: } michael@0: return rv; michael@0: }