OLD | NEW |
| (Empty) |
1 /* This Source Code Form is subject to the terms of the Mozilla Public | |
2 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
4 /* | |
5 * This file manages Netscape specific PKCS #11 objects (CRLs, Trust objects, | |
6 * etc). | |
7 */ | |
8 | |
9 #include "secport.h" | |
10 #include "seccomon.h" | |
11 #include "secmod.h" | |
12 #include "secmodi.h" | |
13 #include "secmodti.h" | |
14 #include "pkcs11.h" | |
15 #include "pk11func.h" | |
16 #include "cert.h" | |
17 #include "certi.h" | |
18 #include "secitem.h" | |
19 #include "sechash.h" | |
20 #include "secoid.h" | |
21 | |
22 #include "certdb.h" | |
23 #include "secerr.h" | |
24 | |
25 #include "pki3hack.h" | |
26 #include "dev3hack.h" | |
27 | |
28 #include "devm.h" | |
29 #include "pki.h" | |
30 #include "pkim.h" | |
31 | |
32 extern const NSSError NSS_ERROR_NOT_FOUND; | |
33 | |
34 CK_TRUST | |
35 pk11_GetTrustField(PK11SlotInfo *slot, PLArenaPool *arena, | |
36 CK_OBJECT_HANDLE id, CK_ATTRIBUTE_TYPE type) | |
37 { | |
38 CK_TRUST rv = 0; | |
39 SECItem item; | |
40 | |
41 item.data = NULL; | |
42 item.len = 0; | |
43 | |
44 if( SECSuccess == PK11_ReadAttribute(slot, id, type, arena, &item) ) { | |
45 PORT_Assert(item.len == sizeof(CK_TRUST)); | |
46 PORT_Memcpy(&rv, item.data, sizeof(CK_TRUST)); | |
47 /* Damn, is there an endian problem here? */ | |
48 return rv; | |
49 } | |
50 | |
51 return 0; | |
52 } | |
53 | |
54 PRBool | |
55 pk11_HandleTrustObject(PK11SlotInfo *slot, CERTCertificate *cert, CERTCertTrust
*trust) | |
56 { | |
57 PLArenaPool *arena; | |
58 | |
59 CK_ATTRIBUTE tobjTemplate[] = { | |
60 { CKA_CLASS, NULL, 0 }, | |
61 { CKA_CERT_SHA1_HASH, NULL, 0 }, | |
62 }; | |
63 | |
64 CK_OBJECT_CLASS tobjc = CKO_NETSCAPE_TRUST; | |
65 CK_OBJECT_HANDLE tobjID; | |
66 unsigned char sha1_hash[SHA1_LENGTH]; | |
67 | |
68 CK_TRUST serverAuth, codeSigning, emailProtection, clientAuth; | |
69 | |
70 PK11_HashBuf(SEC_OID_SHA1, sha1_hash, cert->derCert.data, cert->derCert.len); | |
71 | |
72 PK11_SETATTRS(&tobjTemplate[0], CKA_CLASS, &tobjc, sizeof(tobjc)); | |
73 PK11_SETATTRS(&tobjTemplate[1], CKA_CERT_SHA1_HASH, sha1_hash, | |
74 SHA1_LENGTH); | |
75 | |
76 tobjID = pk11_FindObjectByTemplate(slot, tobjTemplate, | |
77 sizeof(tobjTemplate)/sizeof(tobjTemplate[0]
)); | |
78 if( CK_INVALID_HANDLE == tobjID ) { | |
79 return PR_FALSE; | |
80 } | |
81 | |
82 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); | |
83 if( NULL == arena ) return PR_FALSE; | |
84 | |
85 /* Unfortunately, it seems that PK11_GetAttributes doesn't deal | |
86 * well with nonexistent attributes. I guess we have to check | |
87 * the trust info fields one at a time. | |
88 */ | |
89 | |
90 /* We could verify CKA_CERT_HASH here */ | |
91 | |
92 /* We could verify CKA_EXPIRES here */ | |
93 | |
94 | |
95 /* "Purpose" trust information */ | |
96 serverAuth = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_SERVER_AUTH); | |
97 clientAuth = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_CLIENT_AUTH); | |
98 codeSigning = pk11_GetTrustField(slot, arena, tobjID, CKA_TRUST_CODE_SIGNING); | |
99 emailProtection = pk11_GetTrustField(slot, arena, tobjID, | |
100 CKA_TRUST_EMAIL_PROTECTION); | |
101 /* Here's where the fun logic happens. We have to map back from the | |
102 * key usage, extended key usage, purpose, and possibly other trust values | |
103 * into the old trust-flags bits. */ | |
104 | |
105 /* First implementation: keep it simple for testing. We can study what other | |
106 * mappings would be appropriate and add them later.. fgmr 20000724 */ | |
107 | |
108 if ( serverAuth == CKT_NSS_TRUSTED ) { | |
109 trust->sslFlags |= CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED; | |
110 } | |
111 | |
112 if ( serverAuth == CKT_NSS_TRUSTED_DELEGATOR ) { | |
113 trust->sslFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA | | |
114 CERTDB_NS_TRUSTED_CA; | |
115 } | |
116 if ( clientAuth == CKT_NSS_TRUSTED_DELEGATOR ) { | |
117 trust->sslFlags |= CERTDB_TRUSTED_CLIENT_CA ; | |
118 } | |
119 | |
120 if ( emailProtection == CKT_NSS_TRUSTED ) { | |
121 trust->emailFlags |= CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED; | |
122 } | |
123 | |
124 if ( emailProtection == CKT_NSS_TRUSTED_DELEGATOR ) { | |
125 trust->emailFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_NS_TRUSTED
_CA; | |
126 } | |
127 | |
128 if( codeSigning == CKT_NSS_TRUSTED ) { | |
129 trust->objectSigningFlags |= CERTDB_TERMINAL_RECORD | CERTDB_TRUSTED; | |
130 } | |
131 | |
132 if( codeSigning == CKT_NSS_TRUSTED_DELEGATOR ) { | |
133 trust->objectSigningFlags |= CERTDB_VALID_CA | CERTDB_TRUSTED_CA | CERTDB_NS
_TRUSTED_CA; | |
134 } | |
135 | |
136 /* There's certainly a lot more logic that can go here.. */ | |
137 | |
138 PORT_FreeArena(arena, PR_FALSE); | |
139 | |
140 return PR_TRUE; | |
141 } | |
142 | |
143 static SECStatus | |
144 pk11_CollectCrls(PK11SlotInfo *slot, CK_OBJECT_HANDLE crlID, void *arg) | |
145 { | |
146 SECItem derCrl; | |
147 CERTCrlHeadNode *head = (CERTCrlHeadNode *) arg; | |
148 CERTCrlNode *new_node = NULL; | |
149 CK_ATTRIBUTE fetchCrl[3] = { | |
150 { CKA_VALUE, NULL, 0}, | |
151 { CKA_NETSCAPE_KRL, NULL, 0}, | |
152 { CKA_NETSCAPE_URL, NULL, 0}, | |
153 }; | |
154 const int fetchCrlSize = sizeof(fetchCrl)/sizeof(fetchCrl[2]); | |
155 CK_RV crv; | |
156 SECStatus rv = SECFailure; | |
157 | |
158 crv = PK11_GetAttributes(head->arena,slot,crlID,fetchCrl,fetchCrlSize); | |
159 if (CKR_OK != crv) { | |
160 PORT_SetError(PK11_MapError(crv)); | |
161 goto loser; | |
162 } | |
163 | |
164 if (!fetchCrl[1].pValue) { | |
165 PORT_SetError(SEC_ERROR_CRL_INVALID); | |
166 goto loser; | |
167 } | |
168 | |
169 new_node = (CERTCrlNode *)PORT_ArenaAlloc(head->arena, sizeof(CERTCrlNode)); | |
170 if (new_node == NULL) { | |
171 goto loser; | |
172 } | |
173 | |
174 if (*((CK_BBOOL *)fetchCrl[1].pValue)) | |
175 new_node->type = SEC_KRL_TYPE; | |
176 else | |
177 new_node->type = SEC_CRL_TYPE; | |
178 | |
179 derCrl.type = siBuffer; | |
180 derCrl.data = (unsigned char *)fetchCrl[0].pValue; | |
181 derCrl.len = fetchCrl[0].ulValueLen; | |
182 new_node->crl=CERT_DecodeDERCrl(head->arena,&derCrl,new_node->type); | |
183 if (new_node->crl == NULL) { | |
184 goto loser; | |
185 } | |
186 | |
187 if (fetchCrl[2].pValue) { | |
188 int nnlen = fetchCrl[2].ulValueLen; | |
189 new_node->crl->url = (char *)PORT_ArenaAlloc(head->arena, nnlen+1); | |
190 if ( !new_node->crl->url ) { | |
191 goto loser; | |
192 } | |
193 PORT_Memcpy(new_node->crl->url, fetchCrl[2].pValue, nnlen); | |
194 new_node->crl->url[nnlen] = 0; | |
195 } else { | |
196 new_node->crl->url = NULL; | |
197 } | |
198 | |
199 | |
200 new_node->next = NULL; | |
201 if (head->last) { | |
202 head->last->next = new_node; | |
203 head->last = new_node; | |
204 } else { | |
205 head->first = head->last = new_node; | |
206 } | |
207 rv = SECSuccess; | |
208 | |
209 loser: | |
210 return(rv); | |
211 } | |
212 | |
213 /* | |
214 * Return a list of all the CRLs . | |
215 * CRLs are allocated in the list's arena. | |
216 */ | |
217 SECStatus | |
218 PK11_LookupCrls(CERTCrlHeadNode *nodes, int type, void *wincx) { | |
219 pk11TraverseSlot creater; | |
220 CK_ATTRIBUTE theTemplate[2]; | |
221 CK_ATTRIBUTE *attrs; | |
222 CK_OBJECT_CLASS certClass = CKO_NETSCAPE_CRL; | |
223 CK_BBOOL isKrl = CK_FALSE; | |
224 | |
225 attrs = theTemplate; | |
226 PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass)); attrs++; | |
227 if (type != -1) { | |
228 isKrl = (CK_BBOOL) (type == SEC_KRL_TYPE); | |
229 PK11_SETATTRS(attrs, CKA_NETSCAPE_KRL, &isKrl, sizeof(isKrl)); attrs++; | |
230 } | |
231 | |
232 creater.callback = pk11_CollectCrls; | |
233 creater.callbackArg = (void *) nodes; | |
234 creater.findTemplate = theTemplate; | |
235 creater.templateCount = (attrs - theTemplate); | |
236 | |
237 return pk11_TraverseAllSlots(PK11_TraverseSlot, &creater, PR_FALSE, wincx); | |
238 } | |
239 | |
240 struct crlOptionsStr { | |
241 CERTCrlHeadNode* head; | |
242 PRInt32 decodeOptions; | |
243 }; | |
244 | |
245 typedef struct crlOptionsStr crlOptions; | |
246 | |
247 static SECStatus | |
248 pk11_RetrieveCrlsCallback(PK11SlotInfo *slot, CK_OBJECT_HANDLE crlID, | |
249 void *arg) | |
250 { | |
251 SECItem* derCrl = NULL; | |
252 crlOptions* options = (crlOptions*) arg; | |
253 CERTCrlHeadNode *head = options->head; | |
254 CERTCrlNode *new_node = NULL; | |
255 CK_ATTRIBUTE fetchCrl[3] = { | |
256 { CKA_VALUE, NULL, 0}, | |
257 { CKA_NETSCAPE_KRL, NULL, 0}, | |
258 { CKA_NETSCAPE_URL, NULL, 0}, | |
259 }; | |
260 const int fetchCrlSize = sizeof(fetchCrl)/sizeof(fetchCrl[2]); | |
261 CK_RV crv; | |
262 SECStatus rv = SECFailure; | |
263 PRBool adopted = PR_FALSE; /* whether the CRL adopted the DER memory | |
264 successfully */ | |
265 int i; | |
266 | |
267 crv = PK11_GetAttributes(NULL,slot,crlID,fetchCrl,fetchCrlSize); | |
268 if (CKR_OK != crv) { | |
269 PORT_SetError(PK11_MapError(crv)); | |
270 goto loser; | |
271 } | |
272 | |
273 if (!fetchCrl[1].pValue) { | |
274 /* reject KRLs */ | |
275 PORT_SetError(SEC_ERROR_CRL_INVALID); | |
276 goto loser; | |
277 } | |
278 | |
279 new_node = (CERTCrlNode *)PORT_ArenaAlloc(head->arena, | |
280 sizeof(CERTCrlNode)); | |
281 if (new_node == NULL) { | |
282 goto loser; | |
283 } | |
284 | |
285 new_node->type = SEC_CRL_TYPE; | |
286 | |
287 derCrl = SECITEM_AllocItem(NULL, NULL, 0); | |
288 if (!derCrl) { | |
289 goto loser; | |
290 } | |
291 derCrl->type = siBuffer; | |
292 derCrl->data = (unsigned char *)fetchCrl[0].pValue; | |
293 derCrl->len = fetchCrl[0].ulValueLen; | |
294 new_node->crl = CERT_DecodeDERCrlWithFlags(NULL, derCrl,new_node->type, | |
295 options->decodeOptions); | |
296 if (new_node->crl == NULL) { | |
297 goto loser; | |
298 } | |
299 adopted = PR_TRUE; /* now that the CRL has adopted the DER memory, | |
300 we won't need to free it upon exit */ | |
301 | |
302 if (fetchCrl[2].pValue && fetchCrl[2].ulValueLen) { | |
303 /* copy the URL if there is one */ | |
304 int nnlen = fetchCrl[2].ulValueLen; | |
305 new_node->crl->url = (char *)PORT_ArenaAlloc(new_node->crl->arena, | |
306 nnlen+1); | |
307 if ( !new_node->crl->url ) { | |
308 goto loser; | |
309 } | |
310 PORT_Memcpy(new_node->crl->url, fetchCrl[2].pValue, nnlen); | |
311 new_node->crl->url[nnlen] = 0; | |
312 } else { | |
313 new_node->crl->url = NULL; | |
314 } | |
315 | |
316 new_node->next = NULL; | |
317 if (head->last) { | |
318 head->last->next = new_node; | |
319 head->last = new_node; | |
320 } else { | |
321 head->first = head->last = new_node; | |
322 } | |
323 rv = SECSuccess; | |
324 new_node->crl->slot = PK11_ReferenceSlot(slot); | |
325 new_node->crl->pkcs11ID = crlID; | |
326 | |
327 loser: | |
328 /* free attributes that weren't adopted by the CRL */ | |
329 for (i=1;i<fetchCrlSize;i++) { | |
330 if (fetchCrl[i].pValue) { | |
331 PORT_Free(fetchCrl[i].pValue); | |
332 } | |
333 } | |
334 /* free the DER if the CRL object didn't adopt it */ | |
335 if (fetchCrl[0].pValue && PR_FALSE == adopted) { | |
336 PORT_Free(fetchCrl[0].pValue); | |
337 } | |
338 if (derCrl && !adopted) { | |
339 /* clear the data fields, which we already took care of above */ | |
340 derCrl->data = NULL; | |
341 derCrl->len = 0; | |
342 /* free the memory for the SECItem structure itself */ | |
343 SECITEM_FreeItem(derCrl, PR_TRUE); | |
344 } | |
345 return(rv); | |
346 } | |
347 | |
348 /* | |
349 * Return a list of CRLs matching specified issuer and type | |
350 * CRLs are not allocated in the list's arena, but rather in their own, | |
351 * arena, so that they can be used individually in the CRL cache . | |
352 * CRLs are always partially decoded for efficiency. | |
353 */ | |
354 SECStatus pk11_RetrieveCrls(CERTCrlHeadNode *nodes, SECItem* issuer, | |
355 void *wincx) | |
356 { | |
357 pk11TraverseSlot creater; | |
358 CK_ATTRIBUTE theTemplate[2]; | |
359 CK_ATTRIBUTE *attrs; | |
360 CK_OBJECT_CLASS crlClass = CKO_NETSCAPE_CRL; | |
361 crlOptions options; | |
362 | |
363 attrs = theTemplate; | |
364 PK11_SETATTRS(attrs, CKA_CLASS, &crlClass, sizeof(crlClass)); attrs++; | |
365 | |
366 options.head = nodes; | |
367 | |
368 /* - do a partial decoding - we don't need to decode the entries while | |
369 fetching | |
370 - don't copy the DER for optimal performance - CRL can be very large | |
371 - have the CRL objects adopt the DER, so SEC_DestroyCrl will free it | |
372 - keep bad CRL objects. The CRL cache is interested in them, for | |
373 security purposes. Bad CRL objects are a sign of something amiss. | |
374 */ | |
375 | |
376 options.decodeOptions = CRL_DECODE_SKIP_ENTRIES | CRL_DECODE_DONT_COPY_DER | | |
377 CRL_DECODE_ADOPT_HEAP_DER | CRL_DECODE_KEEP_BAD_CRL; | |
378 if (issuer) | |
379 { | |
380 PK11_SETATTRS(attrs, CKA_SUBJECT, issuer->data, issuer->len); attrs++; | |
381 } | |
382 | |
383 creater.callback = pk11_RetrieveCrlsCallback; | |
384 creater.callbackArg = (void *) &options; | |
385 creater.findTemplate = theTemplate; | |
386 creater.templateCount = (attrs - theTemplate); | |
387 | |
388 return pk11_TraverseAllSlots(PK11_TraverseSlot, &creater, PR_FALSE, wincx); | |
389 } | |
390 | |
391 /* | |
392 * return the crl associated with a derSubjectName | |
393 */ | |
394 SECItem * | |
395 PK11_FindCrlByName(PK11SlotInfo **slot, CK_OBJECT_HANDLE *crlHandle, | |
396 SECItem *name, int type, char **pUrl) | |
397 { | |
398 NSSCRL **crls, **crlp, *crl = NULL; | |
399 NSSDER subject; | |
400 SECItem *rvItem; | |
401 NSSTrustDomain *td = STAN_GetDefaultTrustDomain(); | |
402 char * url = NULL; | |
403 | |
404 PORT_SetError(0); | |
405 NSSITEM_FROM_SECITEM(&subject, name); | |
406 if (*slot) { | |
407 nssCryptokiObject **instances; | |
408 nssPKIObjectCollection *collection; | |
409 nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly; | |
410 NSSToken *token = PK11Slot_GetNSSToken(*slot); | |
411 collection = nssCRLCollection_Create(td, NULL); | |
412 if (!collection) { | |
413 goto loser; | |
414 } | |
415 instances = nssToken_FindCRLsBySubject(token, NULL, &subject, | |
416 tokenOnly, 0, NULL); | |
417 nssPKIObjectCollection_AddInstances(collection, instances, 0); | |
418 nss_ZFreeIf(instances); | |
419 crls = nssPKIObjectCollection_GetCRLs(collection, NULL, 0, NULL); | |
420 nssPKIObjectCollection_Destroy(collection); | |
421 } else { | |
422 crls = nssTrustDomain_FindCRLsBySubject(td, &subject); | |
423 } | |
424 if ((!crls) || (*crls == NULL)) { | |
425 if (crls) { | |
426 nssCRLArray_Destroy(crls); | |
427 } | |
428 if (NSS_GetError() == NSS_ERROR_NOT_FOUND) { | |
429 PORT_SetError(SEC_ERROR_CRL_NOT_FOUND); | |
430 } | |
431 goto loser; | |
432 } | |
433 for (crlp = crls; *crlp; crlp++) { | |
434 if ((!(*crlp)->isKRL && type == SEC_CRL_TYPE) || | |
435 ((*crlp)->isKRL && type != SEC_CRL_TYPE)) | |
436 { | |
437 crl = nssCRL_AddRef(*crlp); | |
438 break; | |
439 } | |
440 } | |
441 nssCRLArray_Destroy(crls); | |
442 if (!crl) { | |
443 /* CRL collection was found, but no interesting CRL's were on it. | |
444 * Not an error */ | |
445 PORT_SetError(SEC_ERROR_CRL_NOT_FOUND); | |
446 goto loser; | |
447 } | |
448 if (crl->url) { | |
449 url = PORT_Strdup(crl->url); | |
450 if (!url) { | |
451 goto loser; | |
452 } | |
453 } | |
454 rvItem = SECITEM_AllocItem(NULL, NULL, crl->encoding.size); | |
455 if (!rvItem) { | |
456 goto loser; | |
457 } | |
458 memcpy(rvItem->data, crl->encoding.data, crl->encoding.size); | |
459 *slot = PK11_ReferenceSlot(crl->object.instances[0]->token->pk11slot); | |
460 *crlHandle = crl->object.instances[0]->handle; | |
461 *pUrl = url; | |
462 nssCRL_Destroy(crl); | |
463 return rvItem; | |
464 | |
465 loser: | |
466 if (url) | |
467 PORT_Free(url); | |
468 if (crl) | |
469 nssCRL_Destroy(crl); | |
470 if (PORT_GetError() == 0) { | |
471 PORT_SetError(SEC_ERROR_CRL_NOT_FOUND); | |
472 } | |
473 return NULL; | |
474 } | |
475 | |
476 CK_OBJECT_HANDLE | |
477 PK11_PutCrl(PK11SlotInfo *slot, SECItem *crl, SECItem *name, | |
478 char *url, int type) | |
479 { | |
480 NSSItem derCRL, derSubject; | |
481 NSSToken *token = PK11Slot_GetNSSToken(slot); | |
482 nssCryptokiObject *object; | |
483 PRBool isKRL = (type == SEC_CRL_TYPE) ? PR_FALSE : PR_TRUE; | |
484 CK_OBJECT_HANDLE rvH; | |
485 | |
486 NSSITEM_FROM_SECITEM(&derSubject, name); | |
487 NSSITEM_FROM_SECITEM(&derCRL, crl); | |
488 | |
489 object = nssToken_ImportCRL(token, NULL, | |
490 &derSubject, &derCRL, isKRL, url, PR_TRUE); | |
491 | |
492 if (object) { | |
493 rvH = object->handle; | |
494 nssCryptokiObject_Destroy(object); | |
495 } else { | |
496 rvH = CK_INVALID_HANDLE; | |
497 PORT_SetError(SEC_ERROR_CRL_IMPORT_FAILED); | |
498 } | |
499 return rvH; | |
500 } | |
501 | |
502 | |
503 /* | |
504 * delete a crl. | |
505 */ | |
506 SECStatus | |
507 SEC_DeletePermCRL(CERTSignedCrl *crl) | |
508 { | |
509 PRStatus status; | |
510 NSSToken *token; | |
511 nssCryptokiObject *object; | |
512 PK11SlotInfo *slot = crl->slot; | |
513 | |
514 if (slot == NULL) { | |
515 PORT_Assert(slot); | |
516 /* shouldn't happen */ | |
517 PORT_SetError( SEC_ERROR_CRL_INVALID); | |
518 return SECFailure; | |
519 } | |
520 token = PK11Slot_GetNSSToken(slot); | |
521 | |
522 object = nss_ZNEW(NULL, nssCryptokiObject); | |
523 if (!object) { | |
524 return SECFailure; | |
525 } | |
526 object->token = nssToken_AddRef(token); | |
527 object->handle = crl->pkcs11ID; | |
528 object->isTokenObject = PR_TRUE; | |
529 | |
530 status = nssToken_DeleteStoredObject(object); | |
531 | |
532 nssCryptokiObject_Destroy(object); | |
533 return (status == PR_SUCCESS) ? SECSuccess : SECFailure; | |
534 } | |
535 | |
536 /* | |
537 * return the certificate associated with a derCert | |
538 */ | |
539 SECItem * | |
540 PK11_FindSMimeProfile(PK11SlotInfo **slot, char *emailAddr, | |
541 SECItem *name, SECItem **profileTime) | |
542 { | |
543 CK_OBJECT_CLASS smimeClass = CKO_NETSCAPE_SMIME; | |
544 CK_ATTRIBUTE theTemplate[] = { | |
545 { CKA_SUBJECT, NULL, 0 }, | |
546 { CKA_CLASS, NULL, 0 }, | |
547 { CKA_NETSCAPE_EMAIL, NULL, 0 }, | |
548 }; | |
549 CK_ATTRIBUTE smimeData[] = { | |
550 { CKA_SUBJECT, NULL, 0 }, | |
551 { CKA_VALUE, NULL, 0 }, | |
552 }; | |
553 /* if you change the array, change the variable below as well */ | |
554 int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); | |
555 CK_OBJECT_HANDLE smimeh = CK_INVALID_HANDLE; | |
556 CK_ATTRIBUTE *attrs = theTemplate; | |
557 CK_RV crv; | |
558 SECItem *emailProfile = NULL; | |
559 | |
560 if (!emailAddr || !emailAddr[0]) { | |
561 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
562 return NULL; | |
563 } | |
564 | |
565 PK11_SETATTRS(attrs, CKA_SUBJECT, name->data, name->len); attrs++; | |
566 PK11_SETATTRS(attrs, CKA_CLASS, &smimeClass, sizeof(smimeClass)); attrs++; | |
567 PK11_SETATTRS(attrs, CKA_NETSCAPE_EMAIL, emailAddr, strlen(emailAddr)); | |
568 attrs++; | |
569 | |
570 if (*slot) { | |
571 smimeh = pk11_FindObjectByTemplate(*slot,theTemplate,tsize); | |
572 } else { | |
573 PK11SlotList *list = PK11_GetAllTokens(CKM_INVALID_MECHANISM, | |
574 PR_FALSE,PR_TRUE,NULL); | |
575 PK11SlotListElement *le; | |
576 | |
577 if (!list) { | |
578 return NULL; | |
579 } | |
580 /* loop through all the slots */ | |
581 for (le = list->head; le; le = le->next) { | |
582 smimeh = pk11_FindObjectByTemplate(le->slot,theTemplate,tsize); | |
583 if (smimeh != CK_INVALID_HANDLE) { | |
584 *slot = PK11_ReferenceSlot(le->slot); | |
585 break; | |
586 } | |
587 } | |
588 PK11_FreeSlotList(list); | |
589 } | |
590 | |
591 if (smimeh == CK_INVALID_HANDLE) { | |
592 PORT_SetError(SEC_ERROR_NO_KRL); | |
593 return NULL; | |
594 } | |
595 | |
596 if (profileTime) { | |
597 PK11_SETATTRS(smimeData, CKA_NETSCAPE_SMIME_TIMESTAMP, NULL, 0); | |
598 } | |
599 | |
600 crv = PK11_GetAttributes(NULL,*slot,smimeh,smimeData,2); | |
601 if (crv != CKR_OK) { | |
602 PORT_SetError(PK11_MapError (crv)); | |
603 goto loser; | |
604 } | |
605 | |
606 if (!profileTime) { | |
607 SECItem profileSubject; | |
608 | |
609 profileSubject.data = (unsigned char*) smimeData[0].pValue; | |
610 profileSubject.len = smimeData[0].ulValueLen; | |
611 if (!SECITEM_ItemsAreEqual(&profileSubject,name)) { | |
612 goto loser; | |
613 } | |
614 } | |
615 | |
616 emailProfile = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); | |
617 if (emailProfile == NULL) { | |
618 goto loser; | |
619 } | |
620 | |
621 emailProfile->data = (unsigned char*) smimeData[1].pValue; | |
622 emailProfile->len = smimeData[1].ulValueLen; | |
623 | |
624 if (profileTime) { | |
625 *profileTime = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); | |
626 if (*profileTime) { | |
627 (*profileTime)->data = (unsigned char*) smimeData[0].pValue; | |
628 (*profileTime)->len = smimeData[0].ulValueLen; | |
629 } | |
630 } | |
631 | |
632 loser: | |
633 if (emailProfile == NULL) { | |
634 if (smimeData[1].pValue) { | |
635 PORT_Free(smimeData[1].pValue); | |
636 } | |
637 } | |
638 if (profileTime == NULL || *profileTime == NULL) { | |
639 if (smimeData[0].pValue) { | |
640 PORT_Free(smimeData[0].pValue); | |
641 } | |
642 } | |
643 return emailProfile; | |
644 } | |
645 | |
646 | |
647 SECStatus | |
648 PK11_SaveSMimeProfile(PK11SlotInfo *slot, char *emailAddr, SECItem *derSubj, | |
649 SECItem *emailProfile, SECItem *profileTime) | |
650 { | |
651 CK_OBJECT_CLASS smimeClass = CKO_NETSCAPE_SMIME; | |
652 CK_BBOOL ck_true = CK_TRUE; | |
653 CK_ATTRIBUTE theTemplate[] = { | |
654 { CKA_CLASS, NULL, 0 }, | |
655 { CKA_TOKEN, NULL, 0 }, | |
656 { CKA_SUBJECT, NULL, 0 }, | |
657 { CKA_NETSCAPE_EMAIL, NULL, 0 }, | |
658 { CKA_NETSCAPE_SMIME_TIMESTAMP, NULL, 0 }, | |
659 { CKA_VALUE, NULL, 0 } | |
660 }; | |
661 /* if you change the array, change the variable below as well */ | |
662 int realSize = 0; | |
663 CK_OBJECT_HANDLE smimeh = CK_INVALID_HANDLE; | |
664 CK_ATTRIBUTE *attrs = theTemplate; | |
665 CK_SESSION_HANDLE rwsession; | |
666 PK11SlotInfo *free_slot = NULL; | |
667 CK_RV crv; | |
668 #ifdef DEBUG | |
669 int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); | |
670 #endif | |
671 | |
672 PK11_SETATTRS(attrs, CKA_CLASS, &smimeClass, sizeof(smimeClass)); attrs++; | |
673 PK11_SETATTRS(attrs, CKA_TOKEN, &ck_true, sizeof(ck_true)); attrs++; | |
674 PK11_SETATTRS(attrs, CKA_SUBJECT, derSubj->data, derSubj->len); attrs++; | |
675 PK11_SETATTRS(attrs, CKA_NETSCAPE_EMAIL, | |
676 emailAddr, PORT_Strlen(emailAddr)+1); attrs++; | |
677 if (profileTime) { | |
678 PK11_SETATTRS(attrs, CKA_NETSCAPE_SMIME_TIMESTAMP, profileTime->data, | |
679 profileTime->len); attrs++; | |
680 PK11_SETATTRS(attrs, CKA_VALUE,emailProfile->data, | |
681 emailProfile->len); attrs++; | |
682 } | |
683 realSize = attrs - theTemplate; | |
684 PORT_Assert (realSize <= tsize); | |
685 | |
686 if (slot == NULL) { | |
687 free_slot = slot = PK11_GetInternalKeySlot(); | |
688 /* we need to free the key slot in the end!!! */ | |
689 } | |
690 | |
691 rwsession = PK11_GetRWSession(slot); | |
692 if (rwsession == CK_INVALID_SESSION) { | |
693 PORT_SetError(SEC_ERROR_READ_ONLY); | |
694 if (free_slot) { | |
695 PK11_FreeSlot(free_slot); | |
696 } | |
697 return SECFailure; | |
698 } | |
699 | |
700 crv = PK11_GETTAB(slot)-> | |
701 C_CreateObject(rwsession,theTemplate,realSize,&smimeh); | |
702 if (crv != CKR_OK) { | |
703 PORT_SetError( PK11_MapError(crv) ); | |
704 } | |
705 | |
706 PK11_RestoreROSession(slot,rwsession); | |
707 | |
708 if (free_slot) { | |
709 PK11_FreeSlot(free_slot); | |
710 } | |
711 return SECSuccess; | |
712 } | |
713 | |
714 | |
715 CERTSignedCrl * crl_storeCRL (PK11SlotInfo *slot,char *url, | |
716 CERTSignedCrl *newCrl, SECItem *derCrl, int type); | |
717 | |
718 /* import the CRL into the token */ | |
719 | |
720 CERTSignedCrl* PK11_ImportCRL(PK11SlotInfo * slot, SECItem *derCRL, char *url, | |
721 int type, void *wincx, PRInt32 importOptions, PLArenaPool* arena, | |
722 PRInt32 decodeoptions) | |
723 { | |
724 CERTSignedCrl *newCrl, *crl; | |
725 SECStatus rv; | |
726 CERTCertificate *caCert = NULL; | |
727 | |
728 newCrl = crl = NULL; | |
729 | |
730 do { | |
731 newCrl = CERT_DecodeDERCrlWithFlags(arena, derCRL, type, | |
732 decodeoptions); | |
733 if (newCrl == NULL) { | |
734 if (type == SEC_CRL_TYPE) { | |
735 /* only promote error when the error code is too generic */ | |
736 if (PORT_GetError () == SEC_ERROR_BAD_DER) | |
737 PORT_SetError(SEC_ERROR_CRL_INVALID); | |
738 } else { | |
739 PORT_SetError(SEC_ERROR_KRL_INVALID); | |
740 } | |
741 break; | |
742 } | |
743 | |
744 if (0 == (importOptions & CRL_IMPORT_BYPASS_CHECKS)){ | |
745 CERTCertDBHandle* handle = CERT_GetDefaultCertDB(); | |
746 PR_ASSERT(handle != NULL); | |
747 caCert = CERT_FindCertByName (handle, | |
748 &newCrl->crl.derName); | |
749 if (caCert == NULL) { | |
750 PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER); | |
751 break; | |
752 } | |
753 | |
754 /* If caCert is a v3 certificate, make sure that it can be used for | |
755 crl signing purpose */ | |
756 rv = CERT_CheckCertUsage (caCert, KU_CRL_SIGN); | |
757 if (rv != SECSuccess) { | |
758 break; | |
759 } | |
760 | |
761 rv = CERT_VerifySignedData(&newCrl->signatureWrap, caCert, | |
762 PR_Now(), wincx); | |
763 if (rv != SECSuccess) { | |
764 if (type == SEC_CRL_TYPE) { | |
765 PORT_SetError(SEC_ERROR_CRL_BAD_SIGNATURE); | |
766 } else { | |
767 PORT_SetError(SEC_ERROR_KRL_BAD_SIGNATURE); | |
768 } | |
769 break; | |
770 } | |
771 } | |
772 | |
773 crl = crl_storeCRL(slot, url, newCrl, derCRL, type); | |
774 | |
775 } while (0); | |
776 | |
777 if (crl == NULL) { | |
778 SEC_DestroyCrl (newCrl); | |
779 } | |
780 if (caCert) { | |
781 CERT_DestroyCertificate(caCert); | |
782 } | |
783 return (crl); | |
784 } | |
OLD | NEW |