2015-10-21 05:03:22 +02:00
|
|
|
/* -*- Mode: C; tab-width: 8 -*-*/
|
2018-05-04 16:08:28 +02:00
|
|
|
/* 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/. */
|
2015-10-21 05:03:22 +02:00
|
|
|
|
|
|
|
#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
|
2018-05-04 16:08:28 +02:00
|
|
|
cmmf_create_witness_and_challenge(PLArenaPool *poolp,
|
2015-10-21 05:03:22 +02:00
|
|
|
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);
|
|
|
|
encodedRandNum = &challenge->randomNumber;
|
|
|
|
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;
|
|
|
|
}
|
2018-05-04 16:08:28 +02:00
|
|
|
slot =PK11_GetBestSlotWithAttributes(CKM_RSA_PKCS, CKF_WRAP, 0, passwdArg);
|
2015-10-21 05:03:22 +02:00
|
|
|
if (slot == NULL) {
|
|
|
|
rv = SECFailure;
|
|
|
|
goto loser;
|
|
|
|
}
|
cherry-picked mozilla NSS upstream changes (to rev bad5fd065fa1, which is on par with 3.20):
bug1001332, 56b691c003ad, bug1086145, bug1054069, bug1155922, bug991783, bug1125025, bug1162521, bug1162644, bug1132941, bug1164364, bug1166205, bug1166163, bug1166515, bug1138554, bug1167046, bug1167043, bug1169451, bug1172128, bug1170322, bug102794, bug1128184, bug557830, bug1174648, bug1180244, bug1177784, bug1173413, bug1169174, bug1084669, bug951455, bug1183395, bug1177430, bug1183827, bug1160139, bug1154106, bug1142209, bug1185033, bug1193467, bug1182667(with sha512 changes backed out, which breaks VC6 compilation), bug1158489, bug337796
2018-07-12 15:44:51 +02:00
|
|
|
(void)PK11_ImportPublicKey(slot, inPubKey, PR_FALSE);
|
2015-10-21 05:03:22 +02:00
|
|
|
/* 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;
|
2018-05-04 16:08:28 +02:00
|
|
|
PLArenaPool *poolp;
|
2015-10-21 05:03:22 +02:00
|
|
|
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)
|
|
|
|
{
|
2018-05-04 16:08:28 +02:00
|
|
|
PLArenaPool *poolp;
|
2015-10-21 05:03:22 +02:00
|
|
|
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;
|
2018-05-04 16:08:28 +02:00
|
|
|
PLArenaPool *genNamePool = NULL, *poolp;
|
2015-10-21 05:03:22 +02:00
|
|
|
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;
|
|
|
|
}
|