|
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 CK_OBJECT_HANDLE id; |
|
34 CERTSubjectPublicKeyInfo *spki = NULL; |
|
35 |
|
36 |
|
37 encodedRandNum = SEC_ASN1EncodeInteger(poolp, &challenge->randomNumber, |
|
38 inRandom); |
|
39 encodedRandNum = &challenge->randomNumber; |
|
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 id = 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 |
|
177 (CMMFPOPODecKeyChallContent *inDecKeyChall, |
|
178 long inRandom, |
|
179 CERTGeneralName *inSender, |
|
180 SECKEYPublicKey *inPubKey, |
|
181 void *passwdArg) |
|
182 { |
|
183 CMMFChallenge *curChallenge; |
|
184 PLArenaPool *genNamePool = NULL, *poolp; |
|
185 SECStatus rv; |
|
186 SECItem *genNameDER; |
|
187 void *mark; |
|
188 |
|
189 PORT_Assert (inDecKeyChall != NULL && |
|
190 inSender != NULL && |
|
191 inPubKey != NULL); |
|
192 |
|
193 if (inDecKeyChall == NULL || |
|
194 inSender == NULL || inPubKey == NULL) { |
|
195 return SECFailure; |
|
196 } |
|
197 poolp = inDecKeyChall->poolp; |
|
198 mark = PORT_ArenaMark(poolp); |
|
199 |
|
200 genNamePool = PORT_NewArena(CRMF_DEFAULT_ARENA_SIZE); |
|
201 genNameDER = CERT_EncodeGeneralName(inSender, NULL, genNamePool); |
|
202 if (genNameDER == NULL) { |
|
203 rv = SECFailure; |
|
204 goto loser; |
|
205 } |
|
206 if (inDecKeyChall->challenges == NULL) { |
|
207 inDecKeyChall->challenges = |
|
208 PORT_ArenaZNewArray(poolp, CMMFChallenge*,(CMMF_MAX_CHALLENGES+1)); |
|
209 inDecKeyChall->numAllocated = CMMF_MAX_CHALLENGES; |
|
210 } |
|
211 |
|
212 if (inDecKeyChall->numChallenges >= inDecKeyChall->numAllocated) { |
|
213 rv = SECFailure; |
|
214 goto loser; |
|
215 } |
|
216 |
|
217 if (inDecKeyChall->numChallenges == 0) { |
|
218 rv = cmmf_create_first_challenge(inDecKeyChall, inRandom, |
|
219 genNameDER, inPubKey, passwdArg); |
|
220 } else { |
|
221 curChallenge = PORT_ArenaZNew(poolp, CMMFChallenge); |
|
222 if (curChallenge == NULL) { |
|
223 rv = SECFailure; |
|
224 goto loser; |
|
225 } |
|
226 rv = cmmf_create_witness_and_challenge(poolp, curChallenge, inRandom, |
|
227 genNameDER, inPubKey, |
|
228 passwdArg); |
|
229 if (rv == SECSuccess) { |
|
230 inDecKeyChall->challenges[inDecKeyChall->numChallenges] = |
|
231 curChallenge; |
|
232 inDecKeyChall->numChallenges++; |
|
233 } |
|
234 } |
|
235 if (rv != SECSuccess) { |
|
236 goto loser; |
|
237 } |
|
238 PORT_ArenaUnmark(poolp, mark); |
|
239 PORT_FreeArena(genNamePool, PR_FALSE); |
|
240 return SECSuccess; |
|
241 |
|
242 loser: |
|
243 PORT_ArenaRelease(poolp, mark); |
|
244 if (genNamePool != NULL) { |
|
245 PORT_FreeArena(genNamePool, PR_FALSE); |
|
246 } |
|
247 PORT_Assert(rv != SECSuccess); |
|
248 return rv; |
|
249 } |
|
250 |
|
251 SECStatus |
|
252 CMMF_DestroyPOPODecKeyRespContent(CMMFPOPODecKeyRespContent *inDecKeyResp) |
|
253 { |
|
254 PORT_Assert(inDecKeyResp != NULL); |
|
255 if (inDecKeyResp != NULL && inDecKeyResp->poolp != NULL) { |
|
256 PORT_FreeArena(inDecKeyResp->poolp, PR_FALSE); |
|
257 } |
|
258 return SECSuccess; |
|
259 } |
|
260 |
|
261 int |
|
262 CMMF_POPODecKeyRespContentGetNumResponses(CMMFPOPODecKeyRespContent *inRespCont) |
|
263 { |
|
264 int numResponses = 0; |
|
265 |
|
266 PORT_Assert(inRespCont != NULL); |
|
267 if (inRespCont == NULL) { |
|
268 return 0; |
|
269 } |
|
270 |
|
271 while (inRespCont->responses[numResponses] != NULL) { |
|
272 numResponses ++; |
|
273 } |
|
274 return numResponses; |
|
275 } |
|
276 |
|
277 SECStatus |
|
278 CMMF_POPODecKeyRespContentGetResponse (CMMFPOPODecKeyRespContent *inRespCont, |
|
279 int inIndex, |
|
280 long *inDest) |
|
281 { |
|
282 PORT_Assert(inRespCont != NULL); |
|
283 |
|
284 if (inRespCont == NULL || inIndex < 0 || |
|
285 inIndex >= CMMF_POPODecKeyRespContentGetNumResponses(inRespCont)) { |
|
286 return SECFailure; |
|
287 } |
|
288 *inDest = DER_GetInteger(inRespCont->responses[inIndex]); |
|
289 return (*inDest == -1) ? SECFailure : SECSuccess; |
|
290 } |