challcli.c (7412B)
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 "secitem.h" 9 #include "pk11func.h" 10 #include "secder.h" 11 #include "sechash.h" 12 13 CMMFPOPODecKeyChallContent * 14 CMMF_CreatePOPODecKeyChallContentFromDER(const char *buf, long len) 15 { 16 PLArenaPool *poolp; 17 CMMFPOPODecKeyChallContent *challContent; 18 SECStatus rv; 19 20 poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE); 21 if (poolp == NULL) { 22 return NULL; 23 } 24 challContent = PORT_ArenaZNew(poolp, CMMFPOPODecKeyChallContent); 25 if (challContent == NULL) { 26 goto loser; 27 } 28 challContent->poolp = poolp; 29 rv = SEC_ASN1Decode(poolp, challContent, 30 CMMFPOPODecKeyChallContentTemplate, buf, len); 31 if (rv != SECSuccess) { 32 goto loser; 33 } 34 if (challContent->challenges) { 35 while (challContent->challenges[challContent->numChallenges] != NULL) { 36 challContent->numChallenges++; 37 } 38 challContent->numAllocated = challContent->numChallenges; 39 } 40 return challContent; 41 loser: 42 if (poolp != NULL) { 43 PORT_FreeArena(poolp, PR_FALSE); 44 } 45 return NULL; 46 } 47 48 int 49 CMMF_POPODecKeyChallContentGetNumChallenges(CMMFPOPODecKeyChallContent *inKeyChallCont) 50 { 51 PORT_Assert(inKeyChallCont != NULL); 52 if (inKeyChallCont == NULL) { 53 return 0; 54 } 55 return inKeyChallCont->numChallenges; 56 } 57 58 SECItem * 59 CMMF_POPODecKeyChallContentGetPublicValue(CMMFPOPODecKeyChallContent *inKeyChallCont, 60 int inIndex) 61 { 62 PORT_Assert(inKeyChallCont != NULL); 63 if (inKeyChallCont == NULL || (inIndex > inKeyChallCont->numChallenges - 1) || 64 inIndex < 0) { 65 return NULL; 66 } 67 return SECITEM_DupItem(&inKeyChallCont->challenges[inIndex]->key); 68 } 69 70 static SECAlgorithmID * 71 cmmf_get_owf(CMMFPOPODecKeyChallContent *inChalCont, 72 int inIndex) 73 { 74 int i; 75 76 for (i = inIndex; i >= 0; i--) { 77 if (inChalCont->challenges[i]->owf != NULL) { 78 return inChalCont->challenges[i]->owf; 79 } 80 } 81 return NULL; 82 } 83 84 SECStatus 85 CMMF_POPODecKeyChallContDecryptChallenge(CMMFPOPODecKeyChallContent *inChalCont, 86 int inIndex, 87 SECKEYPrivateKey *inPrivKey) 88 { 89 CMMFChallenge *challenge; 90 SECItem *decryptedRand = NULL; 91 PLArenaPool *poolp = NULL; 92 SECAlgorithmID *owf; 93 SECStatus rv = SECFailure; 94 SECOidTag tag; 95 CMMFRand randStr; 96 SECItem hashItem; 97 unsigned char hash[HASH_LENGTH_MAX]; 98 99 PORT_Assert(inChalCont != NULL && inPrivKey != NULL); 100 if (inChalCont == NULL || inIndex < 0 || inIndex > inChalCont->numChallenges || 101 inPrivKey == NULL) { 102 return SECFailure; 103 } 104 105 poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE); 106 if (poolp == NULL) { 107 goto loser; 108 } 109 110 challenge = inChalCont->challenges[inIndex]; 111 decryptedRand = SECITEM_AllocItem(poolp, NULL, challenge->challenge.len); 112 if (decryptedRand == NULL) { 113 goto loser; 114 } 115 rv = PK11_PrivDecryptPKCS1(inPrivKey, decryptedRand->data, 116 &decryptedRand->len, decryptedRand->len, 117 challenge->challenge.data, challenge->challenge.len); 118 if (rv != SECSuccess) { 119 goto loser; 120 } 121 122 rv = SEC_ASN1DecodeItem(poolp, &randStr, CMMFRandTemplate, 123 decryptedRand); 124 if (rv != SECSuccess) { 125 goto loser; 126 } 127 rv = SECFailure; /* Just so that when we do go to loser, 128 * I won't have to set it again. 129 */ 130 owf = cmmf_get_owf(inChalCont, inIndex); 131 if (owf == NULL) { 132 /* No hashing algorithm came with the challenges. Can't verify */ 133 goto loser; 134 } 135 /* Verify the hashes in the challenge */ 136 tag = SECOID_FindOIDTag(&owf->algorithm); 137 hashItem.len = HASH_ResultLenByOidTag(tag); 138 if (!hashItem.len) 139 goto loser; /* error code has been set */ 140 141 rv = PK11_HashBuf(tag, hash, randStr.integer.data, randStr.integer.len); 142 if (rv != SECSuccess) { 143 goto loser; 144 } 145 hashItem.data = hash; 146 if (SECITEM_CompareItem(&hashItem, &challenge->witness) != SECEqual) { 147 /* The hash for the data we decrypted doesn't match the hash provided 148 * in the challenge. Bail out. 149 */ 150 PORT_SetError(SEC_ERROR_BAD_DATA); 151 rv = SECFailure; 152 goto loser; 153 } 154 rv = PK11_HashBuf(tag, hash, challenge->senderDER.data, 155 challenge->senderDER.len); 156 if (rv != SECSuccess) { 157 goto loser; 158 } 159 if (SECITEM_CompareItem(&hashItem, &randStr.senderHash) != SECEqual) { 160 /* The hash for the data we decrypted doesn't match the hash provided 161 * in the challenge. Bail out. 162 */ 163 PORT_SetError(SEC_ERROR_BAD_DATA); 164 rv = SECFailure; 165 goto loser; 166 } 167 /* All of the hashes have verified, so we can now store the integer away.*/ 168 rv = SECITEM_CopyItem(inChalCont->poolp, &challenge->randomNumber, 169 &randStr.integer); 170 loser: 171 if (poolp) { 172 PORT_FreeArena(poolp, PR_FALSE); 173 } 174 return rv; 175 } 176 177 SECStatus 178 CMMF_POPODecKeyChallContentGetRandomNumber(CMMFPOPODecKeyChallContent *inKeyChallCont, 179 int inIndex, 180 long *inDest) 181 { 182 CMMFChallenge *challenge; 183 184 PORT_Assert(inKeyChallCont != NULL); 185 if (inKeyChallCont == NULL || inIndex > 0 || inIndex >= inKeyChallCont->numChallenges) { 186 return SECFailure; 187 } 188 challenge = inKeyChallCont->challenges[inIndex]; 189 if (challenge->randomNumber.data == NULL) { 190 /* There is no random number here, nothing to see. */ 191 return SECFailure; 192 } 193 *inDest = DER_GetInteger(&challenge->randomNumber); 194 return (*inDest == -1) ? SECFailure : SECSuccess; 195 } 196 197 SECStatus 198 CMMF_EncodePOPODecKeyRespContent(long *inDecodedRand, 199 int inNumRand, 200 CRMFEncoderOutputCallback inCallback, 201 void *inArg) 202 { 203 PLArenaPool *poolp; 204 CMMFPOPODecKeyRespContent *response; 205 SECItem *currItem; 206 SECStatus rv = SECFailure; 207 int i; 208 209 poolp = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE); 210 if (poolp == NULL) { 211 return SECFailure; 212 } 213 response = PORT_ArenaZNew(poolp, CMMFPOPODecKeyRespContent); 214 if (response == NULL) { 215 goto loser; 216 } 217 response->responses = PORT_ArenaZNewArray(poolp, SECItem *, inNumRand + 1); 218 if (response->responses == NULL) { 219 goto loser; 220 } 221 for (i = 0; i < inNumRand; i++) { 222 currItem = response->responses[i] = PORT_ArenaZNew(poolp, SECItem); 223 if (currItem == NULL) { 224 goto loser; 225 } 226 currItem = SEC_ASN1EncodeInteger(poolp, currItem, inDecodedRand[i]); 227 if (currItem == NULL) { 228 goto loser; 229 } 230 } 231 rv = cmmf_user_encode(response, inCallback, inArg, 232 CMMFPOPODecKeyRespContentTemplate); 233 loser: 234 if (poolp != NULL) { 235 PORT_FreeArena(poolp, PR_FALSE); 236 } 237 return rv; 238 }