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