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