1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/crmf/cmmfchal.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,290 @@ 1.4 +/* -*- Mode: C; tab-width: 8 -*-*/ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "cmmf.h" 1.10 +#include "cmmfi.h" 1.11 +#include "sechash.h" 1.12 +#include "genname.h" 1.13 +#include "pk11func.h" 1.14 +#include "cert.h" 1.15 +#include "secitem.h" 1.16 +#include "secmod.h" 1.17 +#include "keyhi.h" 1.18 + 1.19 +static int 1.20 +cmmf_create_witness_and_challenge(PLArenaPool *poolp, 1.21 + CMMFChallenge *challenge, 1.22 + long inRandom, 1.23 + SECItem *senderDER, 1.24 + SECKEYPublicKey *inPubKey, 1.25 + void *passwdArg) 1.26 +{ 1.27 + SECItem *encodedRandNum; 1.28 + SECItem encodedRandStr = {siBuffer, NULL, 0}; 1.29 + SECItem *dummy; 1.30 + unsigned char *randHash, *senderHash, *encChal=NULL; 1.31 + unsigned modulusLen = 0; 1.32 + SECStatus rv = SECFailure; 1.33 + CMMFRand randStr= { {siBuffer, NULL, 0}, {siBuffer, NULL, 0}}; 1.34 + PK11SlotInfo *slot; 1.35 + PK11SymKey *symKey = NULL; 1.36 + CK_OBJECT_HANDLE id; 1.37 + CERTSubjectPublicKeyInfo *spki = NULL; 1.38 + 1.39 + 1.40 + encodedRandNum = SEC_ASN1EncodeInteger(poolp, &challenge->randomNumber, 1.41 + inRandom); 1.42 + encodedRandNum = &challenge->randomNumber; 1.43 + randHash = PORT_ArenaNewArray(poolp, unsigned char, SHA1_LENGTH); 1.44 + senderHash = PORT_ArenaNewArray(poolp, unsigned char, SHA1_LENGTH); 1.45 + if (randHash == NULL) { 1.46 + goto loser; 1.47 + } 1.48 + rv = PK11_HashBuf(SEC_OID_SHA1, randHash, encodedRandNum->data, 1.49 + (PRUint32)encodedRandNum->len); 1.50 + if (rv != SECSuccess) { 1.51 + goto loser; 1.52 + } 1.53 + rv = PK11_HashBuf(SEC_OID_SHA1, senderHash, senderDER->data, 1.54 + (PRUint32)senderDER->len); 1.55 + if (rv != SECSuccess) { 1.56 + goto loser; 1.57 + } 1.58 + challenge->witness.data = randHash; 1.59 + challenge->witness.len = SHA1_LENGTH; 1.60 + 1.61 + randStr.integer = *encodedRandNum; 1.62 + randStr.senderHash.data = senderHash; 1.63 + randStr.senderHash.len = SHA1_LENGTH; 1.64 + dummy = SEC_ASN1EncodeItem(NULL, &encodedRandStr, &randStr, 1.65 + CMMFRandTemplate); 1.66 + if (dummy != &encodedRandStr) { 1.67 + rv = SECFailure; 1.68 + goto loser; 1.69 + } 1.70 + /* XXXX Now I have to encrypt encodedRandStr and stash it away. */ 1.71 + modulusLen = SECKEY_PublicKeyStrength(inPubKey); 1.72 + encChal = PORT_ArenaNewArray(poolp, unsigned char, modulusLen); 1.73 + if (encChal == NULL) { 1.74 + rv = SECFailure; 1.75 + goto loser; 1.76 + } 1.77 + slot =PK11_GetBestSlotWithAttributes(CKM_RSA_PKCS, CKF_WRAP, 0, passwdArg); 1.78 + if (slot == NULL) { 1.79 + rv = SECFailure; 1.80 + goto loser; 1.81 + } 1.82 + id = PK11_ImportPublicKey(slot, inPubKey, PR_FALSE); 1.83 + /* In order to properly encrypt the data, we import as a symmetric 1.84 + * key, and then wrap that key. That in essence encrypts the data. 1.85 + * This is the method recommended in the PK11 world in order 1.86 + * to prevent threading issues as well as breaking any other semantics 1.87 + * the PK11 libraries depend on. 1.88 + */ 1.89 + symKey = PK11_ImportSymKey(slot, CKM_RSA_PKCS, PK11_OriginGenerated, 1.90 + CKA_VALUE, &encodedRandStr, passwdArg); 1.91 + if (symKey == NULL) { 1.92 + rv = SECFailure; 1.93 + goto loser; 1.94 + } 1.95 + challenge->challenge.data = encChal; 1.96 + challenge->challenge.len = modulusLen; 1.97 + rv = PK11_PubWrapSymKey(CKM_RSA_PKCS, inPubKey, symKey, 1.98 + &challenge->challenge); 1.99 + PK11_FreeSlot(slot); 1.100 + if (rv != SECSuccess) { 1.101 + goto loser; 1.102 + } 1.103 + rv = SECITEM_CopyItem(poolp, &challenge->senderDER, senderDER); 1.104 + crmf_get_public_value(inPubKey, &challenge->key); 1.105 + /* Fall through */ 1.106 + loser: 1.107 + if (spki != NULL) { 1.108 + SECKEY_DestroySubjectPublicKeyInfo(spki); 1.109 + } 1.110 + if (encodedRandStr.data != NULL) { 1.111 + PORT_Free(encodedRandStr.data); 1.112 + } 1.113 + if (encodedRandNum != NULL) { 1.114 + SECITEM_FreeItem(encodedRandNum, PR_TRUE); 1.115 + } 1.116 + if (symKey != NULL) { 1.117 + PK11_FreeSymKey(symKey); 1.118 + } 1.119 + return rv; 1.120 +} 1.121 + 1.122 +static SECStatus 1.123 +cmmf_create_first_challenge(CMMFPOPODecKeyChallContent *challContent, 1.124 + long inRandom, 1.125 + SECItem *senderDER, 1.126 + SECKEYPublicKey *inPubKey, 1.127 + void *passwdArg) 1.128 +{ 1.129 + SECOidData *oidData; 1.130 + CMMFChallenge *challenge; 1.131 + SECAlgorithmID *algId; 1.132 + PLArenaPool *poolp; 1.133 + SECStatus rv; 1.134 + 1.135 + oidData = SECOID_FindOIDByTag(SEC_OID_SHA1); 1.136 + if (oidData == NULL) { 1.137 + return SECFailure; 1.138 + } 1.139 + poolp = challContent->poolp; 1.140 + challenge = PORT_ArenaZNew(poolp, CMMFChallenge); 1.141 + if (challenge == NULL) { 1.142 + return SECFailure; 1.143 + } 1.144 + algId = challenge->owf = PORT_ArenaZNew(poolp, SECAlgorithmID); 1.145 + if (algId == NULL) { 1.146 + return SECFailure; 1.147 + } 1.148 + rv = SECITEM_CopyItem(poolp, &algId->algorithm, &oidData->oid); 1.149 + if (rv != SECSuccess) { 1.150 + return SECFailure; 1.151 + } 1.152 + rv = cmmf_create_witness_and_challenge(poolp, challenge, inRandom, 1.153 + senderDER, inPubKey, passwdArg); 1.154 + challContent->challenges[0] = (rv == SECSuccess) ? challenge : NULL; 1.155 + challContent->numChallenges++; 1.156 + return rv ; 1.157 +} 1.158 + 1.159 +CMMFPOPODecKeyChallContent* 1.160 +CMMF_CreatePOPODecKeyChallContent (void) 1.161 +{ 1.162 + PLArenaPool *poolp; 1.163 + CMMFPOPODecKeyChallContent *challContent; 1.164 + 1.165 + poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE); 1.166 + if (poolp == NULL) { 1.167 + return NULL; 1.168 + } 1.169 + challContent = PORT_ArenaZNew(poolp, CMMFPOPODecKeyChallContent); 1.170 + if (challContent == NULL) { 1.171 + PORT_FreeArena(poolp, PR_FALSE); 1.172 + return NULL; 1.173 + } 1.174 + challContent->poolp = poolp; 1.175 + return challContent; 1.176 +} 1.177 + 1.178 +SECStatus 1.179 +CMMF_POPODecKeyChallContentSetNextChallenge 1.180 + (CMMFPOPODecKeyChallContent *inDecKeyChall, 1.181 + long inRandom, 1.182 + CERTGeneralName *inSender, 1.183 + SECKEYPublicKey *inPubKey, 1.184 + void *passwdArg) 1.185 +{ 1.186 + CMMFChallenge *curChallenge; 1.187 + PLArenaPool *genNamePool = NULL, *poolp; 1.188 + SECStatus rv; 1.189 + SECItem *genNameDER; 1.190 + void *mark; 1.191 + 1.192 + PORT_Assert (inDecKeyChall != NULL && 1.193 + inSender != NULL && 1.194 + inPubKey != NULL); 1.195 + 1.196 + if (inDecKeyChall == NULL || 1.197 + inSender == NULL || inPubKey == NULL) { 1.198 + return SECFailure; 1.199 + } 1.200 + poolp = inDecKeyChall->poolp; 1.201 + mark = PORT_ArenaMark(poolp); 1.202 + 1.203 + genNamePool = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE); 1.204 + genNameDER = CERT_EncodeGeneralName(inSender, NULL, genNamePool); 1.205 + if (genNameDER == NULL) { 1.206 + rv = SECFailure; 1.207 + goto loser; 1.208 + } 1.209 + if (inDecKeyChall->challenges == NULL) { 1.210 + inDecKeyChall->challenges = 1.211 + PORT_ArenaZNewArray(poolp, CMMFChallenge*,(CMMF_MAX_CHALLENGES+1)); 1.212 + inDecKeyChall->numAllocated = CMMF_MAX_CHALLENGES; 1.213 + } 1.214 + 1.215 + if (inDecKeyChall->numChallenges >= inDecKeyChall->numAllocated) { 1.216 + rv = SECFailure; 1.217 + goto loser; 1.218 + } 1.219 + 1.220 + if (inDecKeyChall->numChallenges == 0) { 1.221 + rv = cmmf_create_first_challenge(inDecKeyChall, inRandom, 1.222 + genNameDER, inPubKey, passwdArg); 1.223 + } else { 1.224 + curChallenge = PORT_ArenaZNew(poolp, CMMFChallenge); 1.225 + if (curChallenge == NULL) { 1.226 + rv = SECFailure; 1.227 + goto loser; 1.228 + } 1.229 + rv = cmmf_create_witness_and_challenge(poolp, curChallenge, inRandom, 1.230 + genNameDER, inPubKey, 1.231 + passwdArg); 1.232 + if (rv == SECSuccess) { 1.233 + inDecKeyChall->challenges[inDecKeyChall->numChallenges] = 1.234 + curChallenge; 1.235 + inDecKeyChall->numChallenges++; 1.236 + } 1.237 + } 1.238 + if (rv != SECSuccess) { 1.239 + goto loser; 1.240 + } 1.241 + PORT_ArenaUnmark(poolp, mark); 1.242 + PORT_FreeArena(genNamePool, PR_FALSE); 1.243 + return SECSuccess; 1.244 + 1.245 + loser: 1.246 + PORT_ArenaRelease(poolp, mark); 1.247 + if (genNamePool != NULL) { 1.248 + PORT_FreeArena(genNamePool, PR_FALSE); 1.249 + } 1.250 + PORT_Assert(rv != SECSuccess); 1.251 + return rv; 1.252 +} 1.253 + 1.254 +SECStatus 1.255 +CMMF_DestroyPOPODecKeyRespContent(CMMFPOPODecKeyRespContent *inDecKeyResp) 1.256 +{ 1.257 + PORT_Assert(inDecKeyResp != NULL); 1.258 + if (inDecKeyResp != NULL && inDecKeyResp->poolp != NULL) { 1.259 + PORT_FreeArena(inDecKeyResp->poolp, PR_FALSE); 1.260 + } 1.261 + return SECSuccess; 1.262 +} 1.263 + 1.264 +int 1.265 +CMMF_POPODecKeyRespContentGetNumResponses(CMMFPOPODecKeyRespContent *inRespCont) 1.266 +{ 1.267 + int numResponses = 0; 1.268 + 1.269 + PORT_Assert(inRespCont != NULL); 1.270 + if (inRespCont == NULL) { 1.271 + return 0; 1.272 + } 1.273 + 1.274 + while (inRespCont->responses[numResponses] != NULL) { 1.275 + numResponses ++; 1.276 + } 1.277 + return numResponses; 1.278 +} 1.279 + 1.280 +SECStatus 1.281 +CMMF_POPODecKeyRespContentGetResponse (CMMFPOPODecKeyRespContent *inRespCont, 1.282 + int inIndex, 1.283 + long *inDest) 1.284 +{ 1.285 + PORT_Assert(inRespCont != NULL); 1.286 + 1.287 + if (inRespCont == NULL || inIndex < 0 || 1.288 + inIndex >= CMMF_POPODecKeyRespContentGetNumResponses(inRespCont)) { 1.289 + return SECFailure; 1.290 + } 1.291 + *inDest = DER_GetInteger(inRespCont->responses[inIndex]); 1.292 + return (*inDest == -1) ? SECFailure : SECSuccess; 1.293 +}