security/nss/lib/crmf/cmmfchal.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C; tab-width: 8 -*-*/
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "cmmf.h"
michael@0 7 #include "cmmfi.h"
michael@0 8 #include "sechash.h"
michael@0 9 #include "genname.h"
michael@0 10 #include "pk11func.h"
michael@0 11 #include "cert.h"
michael@0 12 #include "secitem.h"
michael@0 13 #include "secmod.h"
michael@0 14 #include "keyhi.h"
michael@0 15
michael@0 16 static int
michael@0 17 cmmf_create_witness_and_challenge(PLArenaPool *poolp,
michael@0 18 CMMFChallenge *challenge,
michael@0 19 long inRandom,
michael@0 20 SECItem *senderDER,
michael@0 21 SECKEYPublicKey *inPubKey,
michael@0 22 void *passwdArg)
michael@0 23 {
michael@0 24 SECItem *encodedRandNum;
michael@0 25 SECItem encodedRandStr = {siBuffer, NULL, 0};
michael@0 26 SECItem *dummy;
michael@0 27 unsigned char *randHash, *senderHash, *encChal=NULL;
michael@0 28 unsigned modulusLen = 0;
michael@0 29 SECStatus rv = SECFailure;
michael@0 30 CMMFRand randStr= { {siBuffer, NULL, 0}, {siBuffer, NULL, 0}};
michael@0 31 PK11SlotInfo *slot;
michael@0 32 PK11SymKey *symKey = NULL;
michael@0 33 CK_OBJECT_HANDLE id;
michael@0 34 CERTSubjectPublicKeyInfo *spki = NULL;
michael@0 35
michael@0 36
michael@0 37 encodedRandNum = SEC_ASN1EncodeInteger(poolp, &challenge->randomNumber,
michael@0 38 inRandom);
michael@0 39 encodedRandNum = &challenge->randomNumber;
michael@0 40 randHash = PORT_ArenaNewArray(poolp, unsigned char, SHA1_LENGTH);
michael@0 41 senderHash = PORT_ArenaNewArray(poolp, unsigned char, SHA1_LENGTH);
michael@0 42 if (randHash == NULL) {
michael@0 43 goto loser;
michael@0 44 }
michael@0 45 rv = PK11_HashBuf(SEC_OID_SHA1, randHash, encodedRandNum->data,
michael@0 46 (PRUint32)encodedRandNum->len);
michael@0 47 if (rv != SECSuccess) {
michael@0 48 goto loser;
michael@0 49 }
michael@0 50 rv = PK11_HashBuf(SEC_OID_SHA1, senderHash, senderDER->data,
michael@0 51 (PRUint32)senderDER->len);
michael@0 52 if (rv != SECSuccess) {
michael@0 53 goto loser;
michael@0 54 }
michael@0 55 challenge->witness.data = randHash;
michael@0 56 challenge->witness.len = SHA1_LENGTH;
michael@0 57
michael@0 58 randStr.integer = *encodedRandNum;
michael@0 59 randStr.senderHash.data = senderHash;
michael@0 60 randStr.senderHash.len = SHA1_LENGTH;
michael@0 61 dummy = SEC_ASN1EncodeItem(NULL, &encodedRandStr, &randStr,
michael@0 62 CMMFRandTemplate);
michael@0 63 if (dummy != &encodedRandStr) {
michael@0 64 rv = SECFailure;
michael@0 65 goto loser;
michael@0 66 }
michael@0 67 /* XXXX Now I have to encrypt encodedRandStr and stash it away. */
michael@0 68 modulusLen = SECKEY_PublicKeyStrength(inPubKey);
michael@0 69 encChal = PORT_ArenaNewArray(poolp, unsigned char, modulusLen);
michael@0 70 if (encChal == NULL) {
michael@0 71 rv = SECFailure;
michael@0 72 goto loser;
michael@0 73 }
michael@0 74 slot =PK11_GetBestSlotWithAttributes(CKM_RSA_PKCS, CKF_WRAP, 0, passwdArg);
michael@0 75 if (slot == NULL) {
michael@0 76 rv = SECFailure;
michael@0 77 goto loser;
michael@0 78 }
michael@0 79 id = PK11_ImportPublicKey(slot, inPubKey, PR_FALSE);
michael@0 80 /* In order to properly encrypt the data, we import as a symmetric
michael@0 81 * key, and then wrap that key. That in essence encrypts the data.
michael@0 82 * This is the method recommended in the PK11 world in order
michael@0 83 * to prevent threading issues as well as breaking any other semantics
michael@0 84 * the PK11 libraries depend on.
michael@0 85 */
michael@0 86 symKey = PK11_ImportSymKey(slot, CKM_RSA_PKCS, PK11_OriginGenerated,
michael@0 87 CKA_VALUE, &encodedRandStr, passwdArg);
michael@0 88 if (symKey == NULL) {
michael@0 89 rv = SECFailure;
michael@0 90 goto loser;
michael@0 91 }
michael@0 92 challenge->challenge.data = encChal;
michael@0 93 challenge->challenge.len = modulusLen;
michael@0 94 rv = PK11_PubWrapSymKey(CKM_RSA_PKCS, inPubKey, symKey,
michael@0 95 &challenge->challenge);
michael@0 96 PK11_FreeSlot(slot);
michael@0 97 if (rv != SECSuccess) {
michael@0 98 goto loser;
michael@0 99 }
michael@0 100 rv = SECITEM_CopyItem(poolp, &challenge->senderDER, senderDER);
michael@0 101 crmf_get_public_value(inPubKey, &challenge->key);
michael@0 102 /* Fall through */
michael@0 103 loser:
michael@0 104 if (spki != NULL) {
michael@0 105 SECKEY_DestroySubjectPublicKeyInfo(spki);
michael@0 106 }
michael@0 107 if (encodedRandStr.data != NULL) {
michael@0 108 PORT_Free(encodedRandStr.data);
michael@0 109 }
michael@0 110 if (encodedRandNum != NULL) {
michael@0 111 SECITEM_FreeItem(encodedRandNum, PR_TRUE);
michael@0 112 }
michael@0 113 if (symKey != NULL) {
michael@0 114 PK11_FreeSymKey(symKey);
michael@0 115 }
michael@0 116 return rv;
michael@0 117 }
michael@0 118
michael@0 119 static SECStatus
michael@0 120 cmmf_create_first_challenge(CMMFPOPODecKeyChallContent *challContent,
michael@0 121 long inRandom,
michael@0 122 SECItem *senderDER,
michael@0 123 SECKEYPublicKey *inPubKey,
michael@0 124 void *passwdArg)
michael@0 125 {
michael@0 126 SECOidData *oidData;
michael@0 127 CMMFChallenge *challenge;
michael@0 128 SECAlgorithmID *algId;
michael@0 129 PLArenaPool *poolp;
michael@0 130 SECStatus rv;
michael@0 131
michael@0 132 oidData = SECOID_FindOIDByTag(SEC_OID_SHA1);
michael@0 133 if (oidData == NULL) {
michael@0 134 return SECFailure;
michael@0 135 }
michael@0 136 poolp = challContent->poolp;
michael@0 137 challenge = PORT_ArenaZNew(poolp, CMMFChallenge);
michael@0 138 if (challenge == NULL) {
michael@0 139 return SECFailure;
michael@0 140 }
michael@0 141 algId = challenge->owf = PORT_ArenaZNew(poolp, SECAlgorithmID);
michael@0 142 if (algId == NULL) {
michael@0 143 return SECFailure;
michael@0 144 }
michael@0 145 rv = SECITEM_CopyItem(poolp, &algId->algorithm, &oidData->oid);
michael@0 146 if (rv != SECSuccess) {
michael@0 147 return SECFailure;
michael@0 148 }
michael@0 149 rv = cmmf_create_witness_and_challenge(poolp, challenge, inRandom,
michael@0 150 senderDER, inPubKey, passwdArg);
michael@0 151 challContent->challenges[0] = (rv == SECSuccess) ? challenge : NULL;
michael@0 152 challContent->numChallenges++;
michael@0 153 return rv ;
michael@0 154 }
michael@0 155
michael@0 156 CMMFPOPODecKeyChallContent*
michael@0 157 CMMF_CreatePOPODecKeyChallContent (void)
michael@0 158 {
michael@0 159 PLArenaPool *poolp;
michael@0 160 CMMFPOPODecKeyChallContent *challContent;
michael@0 161
michael@0 162 poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
michael@0 163 if (poolp == NULL) {
michael@0 164 return NULL;
michael@0 165 }
michael@0 166 challContent = PORT_ArenaZNew(poolp, CMMFPOPODecKeyChallContent);
michael@0 167 if (challContent == NULL) {
michael@0 168 PORT_FreeArena(poolp, PR_FALSE);
michael@0 169 return NULL;
michael@0 170 }
michael@0 171 challContent->poolp = poolp;
michael@0 172 return challContent;
michael@0 173 }
michael@0 174
michael@0 175 SECStatus
michael@0 176 CMMF_POPODecKeyChallContentSetNextChallenge
michael@0 177 (CMMFPOPODecKeyChallContent *inDecKeyChall,
michael@0 178 long inRandom,
michael@0 179 CERTGeneralName *inSender,
michael@0 180 SECKEYPublicKey *inPubKey,
michael@0 181 void *passwdArg)
michael@0 182 {
michael@0 183 CMMFChallenge *curChallenge;
michael@0 184 PLArenaPool *genNamePool = NULL, *poolp;
michael@0 185 SECStatus rv;
michael@0 186 SECItem *genNameDER;
michael@0 187 void *mark;
michael@0 188
michael@0 189 PORT_Assert (inDecKeyChall != NULL &&
michael@0 190 inSender != NULL &&
michael@0 191 inPubKey != NULL);
michael@0 192
michael@0 193 if (inDecKeyChall == NULL ||
michael@0 194 inSender == NULL || inPubKey == NULL) {
michael@0 195 return SECFailure;
michael@0 196 }
michael@0 197 poolp = inDecKeyChall->poolp;
michael@0 198 mark = PORT_ArenaMark(poolp);
michael@0 199
michael@0 200 genNamePool = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE);
michael@0 201 genNameDER = CERT_EncodeGeneralName(inSender, NULL, genNamePool);
michael@0 202 if (genNameDER == NULL) {
michael@0 203 rv = SECFailure;
michael@0 204 goto loser;
michael@0 205 }
michael@0 206 if (inDecKeyChall->challenges == NULL) {
michael@0 207 inDecKeyChall->challenges =
michael@0 208 PORT_ArenaZNewArray(poolp, CMMFChallenge*,(CMMF_MAX_CHALLENGES+1));
michael@0 209 inDecKeyChall->numAllocated = CMMF_MAX_CHALLENGES;
michael@0 210 }
michael@0 211
michael@0 212 if (inDecKeyChall->numChallenges >= inDecKeyChall->numAllocated) {
michael@0 213 rv = SECFailure;
michael@0 214 goto loser;
michael@0 215 }
michael@0 216
michael@0 217 if (inDecKeyChall->numChallenges == 0) {
michael@0 218 rv = cmmf_create_first_challenge(inDecKeyChall, inRandom,
michael@0 219 genNameDER, inPubKey, passwdArg);
michael@0 220 } else {
michael@0 221 curChallenge = PORT_ArenaZNew(poolp, CMMFChallenge);
michael@0 222 if (curChallenge == NULL) {
michael@0 223 rv = SECFailure;
michael@0 224 goto loser;
michael@0 225 }
michael@0 226 rv = cmmf_create_witness_and_challenge(poolp, curChallenge, inRandom,
michael@0 227 genNameDER, inPubKey,
michael@0 228 passwdArg);
michael@0 229 if (rv == SECSuccess) {
michael@0 230 inDecKeyChall->challenges[inDecKeyChall->numChallenges] =
michael@0 231 curChallenge;
michael@0 232 inDecKeyChall->numChallenges++;
michael@0 233 }
michael@0 234 }
michael@0 235 if (rv != SECSuccess) {
michael@0 236 goto loser;
michael@0 237 }
michael@0 238 PORT_ArenaUnmark(poolp, mark);
michael@0 239 PORT_FreeArena(genNamePool, PR_FALSE);
michael@0 240 return SECSuccess;
michael@0 241
michael@0 242 loser:
michael@0 243 PORT_ArenaRelease(poolp, mark);
michael@0 244 if (genNamePool != NULL) {
michael@0 245 PORT_FreeArena(genNamePool, PR_FALSE);
michael@0 246 }
michael@0 247 PORT_Assert(rv != SECSuccess);
michael@0 248 return rv;
michael@0 249 }
michael@0 250
michael@0 251 SECStatus
michael@0 252 CMMF_DestroyPOPODecKeyRespContent(CMMFPOPODecKeyRespContent *inDecKeyResp)
michael@0 253 {
michael@0 254 PORT_Assert(inDecKeyResp != NULL);
michael@0 255 if (inDecKeyResp != NULL && inDecKeyResp->poolp != NULL) {
michael@0 256 PORT_FreeArena(inDecKeyResp->poolp, PR_FALSE);
michael@0 257 }
michael@0 258 return SECSuccess;
michael@0 259 }
michael@0 260
michael@0 261 int
michael@0 262 CMMF_POPODecKeyRespContentGetNumResponses(CMMFPOPODecKeyRespContent *inRespCont)
michael@0 263 {
michael@0 264 int numResponses = 0;
michael@0 265
michael@0 266 PORT_Assert(inRespCont != NULL);
michael@0 267 if (inRespCont == NULL) {
michael@0 268 return 0;
michael@0 269 }
michael@0 270
michael@0 271 while (inRespCont->responses[numResponses] != NULL) {
michael@0 272 numResponses ++;
michael@0 273 }
michael@0 274 return numResponses;
michael@0 275 }
michael@0 276
michael@0 277 SECStatus
michael@0 278 CMMF_POPODecKeyRespContentGetResponse (CMMFPOPODecKeyRespContent *inRespCont,
michael@0 279 int inIndex,
michael@0 280 long *inDest)
michael@0 281 {
michael@0 282 PORT_Assert(inRespCont != NULL);
michael@0 283
michael@0 284 if (inRespCont == NULL || inIndex < 0 ||
michael@0 285 inIndex >= CMMF_POPODecKeyRespContentGetNumResponses(inRespCont)) {
michael@0 286 return SECFailure;
michael@0 287 }
michael@0 288 *inDest = DER_GetInteger(inRespCont->responses[inIndex]);
michael@0 289 return (*inDest == -1) ? SECFailure : SECSuccess;
michael@0 290 }

mercurial