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
cmmf_create_witness_and_challenge(PLArenaPool * poolp,CMMFChallenge * challenge,long inRandom,SECItem * senderDER,SECKEYPublicKey * inPubKey,void * passwdArg)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
cmmf_create_first_challenge(CMMFPOPODecKeyChallContent * challContent,long inRandom,SECItem * senderDER,SECKEYPublicKey * inPubKey,void * passwdArg)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 *
CMMF_CreatePOPODecKeyChallContent(void)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
CMMF_POPODecKeyChallContentSetNextChallenge(CMMFPOPODecKeyChallContent * inDecKeyChall,long inRandom,CERTGeneralName * inSender,SECKEYPublicKey * inPubKey,void * passwdArg)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
CMMF_DestroyPOPODecKeyRespContent(CMMFPOPODecKeyRespContent * inDecKeyResp)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
CMMF_POPODecKeyRespContentGetNumResponses(CMMFPOPODecKeyRespContent * inRespCont)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
CMMF_POPODecKeyRespContentGetResponse(CMMFPOPODecKeyRespContent * inRespCont,int inIndex,long * inDest)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 }
290