security/nss/lib/smime/cmsudf.c

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:568e1404f886
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 /*
6 * CMS User Define Types
7 */
8
9 #include "cmslocal.h"
10
11 #include "prinit.h"
12 #include "pk11func.h"
13 #include "secitem.h"
14 #include "secoid.h"
15 #include "secerr.h"
16 #include "nss.h"
17
18 typedef struct nsscmstypeInfoStr nsscmstypeInfo;
19 struct nsscmstypeInfoStr {
20 SECOidTag type;
21 SEC_ASN1Template *template;
22 size_t size;
23 PRBool isData;
24 NSSCMSGenericWrapperDataDestroy destroy;
25 NSSCMSGenericWrapperDataCallback decode_before;
26 NSSCMSGenericWrapperDataCallback decode_after;
27 NSSCMSGenericWrapperDataCallback decode_end;
28 NSSCMSGenericWrapperDataCallback encode_start;
29 NSSCMSGenericWrapperDataCallback encode_before;
30 NSSCMSGenericWrapperDataCallback encode_after;
31 };
32
33 /* make sure the global tables are only initialized once */
34 static PRCallOnceType nsscmstypeOnce;
35 static PRCallOnceType nsscmstypeClearOnce;
36 /* lock for adding a new entry */
37 static PRLock *nsscmstypeAddLock;
38 /* lock for the hash table */
39 static PRLock *nsscmstypeHashLock;
40 /* the hash table itself */
41 static PLHashTable *nsscmstypeHash;
42 /* arena to hold all the hash table data */
43 static PLArenaPool *nsscmstypeArena;
44
45 /*
46 * clean up our global tables
47 */
48 SECStatus
49 nss_cmstype_shutdown(void *appData, void *reserved)
50 {
51 if (nsscmstypeHashLock) {
52 PR_Lock(nsscmstypeHashLock);
53 }
54 if (nsscmstypeHash) {
55 PL_HashTableDestroy(nsscmstypeHash);
56 nsscmstypeHash = NULL;
57 }
58 if (nsscmstypeArena) {
59 PORT_FreeArena(nsscmstypeArena, PR_FALSE);
60 nsscmstypeArena = NULL;
61 }
62 if (nsscmstypeAddLock) {
63 PR_DestroyLock(nsscmstypeAddLock);
64 }
65 if (nsscmstypeHashLock) {
66 PRLock *oldLock = nsscmstypeHashLock;
67 nsscmstypeHashLock = NULL;
68 PR_Unlock(oldLock);
69 PR_DestroyLock(oldLock);
70 }
71
72 /* don't clear out the PR_ONCE data if we failed our inital call */
73 if (appData == NULL) {
74 nsscmstypeOnce = nsscmstypeClearOnce;
75 }
76 return SECSuccess;
77 }
78
79 static PLHashNumber
80 nss_cmstype_hash_key(const void *key)
81 {
82 return (PLHashNumber) key;
83 }
84
85 static PRIntn
86 nss_cmstype_compare_keys(const void *v1, const void *v2)
87 {
88 PLHashNumber value1 = (PLHashNumber) v1;
89 PLHashNumber value2 = (PLHashNumber) v2;
90
91 return (value1 == value2);
92 }
93
94 /*
95 * initialize our hash tables, called once on the first attemat to register
96 * a new SMIME type.
97 */
98 static PRStatus
99 nss_cmstype_init(void)
100 {
101 SECStatus rv;
102
103 nsscmstypeHashLock = PR_NewLock();
104 if (nsscmstypeHashLock == NULL) {
105 return PR_FAILURE;
106 }
107 nsscmstypeAddLock = PR_NewLock();
108 if (nsscmstypeHashLock == NULL) {
109 goto fail;
110 }
111 nsscmstypeHash = PL_NewHashTable(64, nss_cmstype_hash_key,
112 nss_cmstype_compare_keys, PL_CompareValues, NULL, NULL);
113 if (nsscmstypeHash == NULL) {
114 goto fail;
115 }
116 nsscmstypeArena = PORT_NewArena(2048);
117 if (nsscmstypeArena == NULL) {
118 goto fail;
119 }
120 rv = NSS_RegisterShutdown(nss_cmstype_shutdown, NULL);
121 if (rv != SECSuccess) {
122 goto fail;
123 }
124 return PR_SUCCESS;
125
126 fail:
127 nss_cmstype_shutdown(&nsscmstypeOnce, NULL);
128 return PR_FAILURE;
129 }
130
131
132 /*
133 * look up and registered SIME type
134 */
135 static const nsscmstypeInfo *
136 nss_cmstype_lookup(SECOidTag type)
137 {
138 nsscmstypeInfo *typeInfo = NULL;;
139 if (!nsscmstypeHash) {
140 return NULL;
141 }
142 PR_Lock(nsscmstypeHashLock);
143 if (nsscmstypeHash) {
144 typeInfo = PL_HashTableLookupConst(nsscmstypeHash, (void *)type);
145 }
146 PR_Unlock(nsscmstypeHashLock);
147 return typeInfo;
148 }
149
150 /*
151 * add a new type to the SMIME type table
152 */
153 static SECStatus
154 nss_cmstype_add(SECOidTag type, nsscmstypeInfo *typeinfo)
155 {
156 PLHashEntry *entry;
157
158 if (!nsscmstypeHash) {
159 /* assert? this shouldn't happen */
160 return SECFailure;
161 }
162 PR_Lock(nsscmstypeHashLock);
163 /* this is really paranoia. If we really are racing nsscmstypeHash, we'll
164 * also be racing nsscmstypeHashLock... */
165 if (!nsscmstypeHash) {
166 PR_Unlock(nsscmstypeHashLock);
167 return SECFailure;
168 }
169 entry = PL_HashTableAdd(nsscmstypeHash, (void *)type, typeinfo);
170 PR_Unlock(nsscmstypeHashLock);
171 return entry ? SECSuccess : SECFailure;
172 }
173
174
175 /* helper functions to manage new content types
176 */
177
178 PRBool
179 NSS_CMSType_IsWrapper(SECOidTag type)
180 {
181 const nsscmstypeInfo *typeInfo = NULL;
182
183 switch (type) {
184 case SEC_OID_PKCS7_SIGNED_DATA:
185 case SEC_OID_PKCS7_ENVELOPED_DATA:
186 case SEC_OID_PKCS7_DIGESTED_DATA:
187 case SEC_OID_PKCS7_ENCRYPTED_DATA:
188 return PR_TRUE;
189 default:
190 typeInfo = nss_cmstype_lookup(type);
191 if (typeInfo && !typeInfo->isData) {
192 return PR_TRUE;
193 }
194 }
195 return PR_FALSE;
196 }
197
198 PRBool
199 NSS_CMSType_IsData(SECOidTag type)
200 {
201 const nsscmstypeInfo *typeInfo = NULL;
202
203 switch (type) {
204 case SEC_OID_PKCS7_DATA:
205 return PR_TRUE;
206 default:
207 typeInfo = nss_cmstype_lookup(type);
208 if (typeInfo && typeInfo->isData) {
209 return PR_TRUE;
210 }
211 }
212 return PR_FALSE;
213 }
214
215 const SEC_ASN1Template *
216 NSS_CMSType_GetTemplate(SECOidTag type)
217 {
218 const nsscmstypeInfo *typeInfo = nss_cmstype_lookup(type);
219
220 if (typeInfo && typeInfo->template) {
221 return typeInfo->template;
222 }
223 return SEC_ASN1_GET(SEC_PointerToOctetStringTemplate);
224 }
225
226 size_t
227 NSS_CMSType_GetContentSize(SECOidTag type)
228 {
229 const nsscmstypeInfo *typeInfo = nss_cmstype_lookup(type);
230
231 if (typeInfo) {
232 return typeInfo->size;
233 }
234 return sizeof(SECItem *);
235
236 }
237
238 void
239 NSS_CMSGenericWrapperData_Destroy(SECOidTag type, NSSCMSGenericWrapperData *gd)
240 {
241 const nsscmstypeInfo *typeInfo = nss_cmstype_lookup(type);
242
243 if (typeInfo && typeInfo->destroy) {
244 (*typeInfo->destroy)(gd);
245 }
246
247 }
248
249
250 SECStatus
251 NSS_CMSGenericWrapperData_Decode_BeforeData(SECOidTag type,
252 NSSCMSGenericWrapperData *gd)
253 {
254 const nsscmstypeInfo *typeInfo;
255
256 /* short cut common case */
257 if (type == SEC_OID_PKCS7_DATA) {
258 return SECSuccess;
259 }
260
261 typeInfo = nss_cmstype_lookup(type);
262 if (typeInfo) {
263 if (typeInfo->decode_before) {
264 return (*typeInfo->decode_before)(gd);
265 }
266 /* decoder ops optional for data tags */
267 if (typeInfo->isData) {
268 return SECSuccess;
269 }
270 }
271 /* expected a function, but none existed */
272 return SECFailure;
273
274 }
275
276 SECStatus
277 NSS_CMSGenericWrapperData_Decode_AfterData(SECOidTag type,
278 NSSCMSGenericWrapperData *gd)
279 {
280 const nsscmstypeInfo *typeInfo;
281
282 /* short cut common case */
283 if (type == SEC_OID_PKCS7_DATA) {
284 return SECSuccess;
285 }
286
287 typeInfo = nss_cmstype_lookup(type);
288 if (typeInfo) {
289 if (typeInfo->decode_after) {
290 return (*typeInfo->decode_after)(gd);
291 }
292 /* decoder ops optional for data tags */
293 if (typeInfo->isData) {
294 return SECSuccess;
295 }
296 }
297 /* expected a function, but none existed */
298 return SECFailure;
299 }
300
301 SECStatus
302 NSS_CMSGenericWrapperData_Decode_AfterEnd(SECOidTag type,
303 NSSCMSGenericWrapperData *gd)
304 {
305 const nsscmstypeInfo *typeInfo;
306
307 /* short cut common case */
308 if (type == SEC_OID_PKCS7_DATA) {
309 return SECSuccess;
310 }
311
312 typeInfo = nss_cmstype_lookup(type);
313 if (typeInfo) {
314 if (typeInfo->decode_end) {
315 return (*typeInfo->decode_end)(gd);
316 }
317 /* decoder ops optional for data tags */
318 if (typeInfo->isData) {
319 return SECSuccess;
320 }
321 }
322 /* expected a function, but none existed */
323 return SECFailure;
324 }
325
326 SECStatus
327 NSS_CMSGenericWrapperData_Encode_BeforeStart(SECOidTag type,
328 NSSCMSGenericWrapperData *gd)
329 {
330 const nsscmstypeInfo *typeInfo;
331
332 /* short cut common case */
333 if (type == SEC_OID_PKCS7_DATA) {
334 return SECSuccess;
335 }
336
337 typeInfo = nss_cmstype_lookup(type);
338 if (typeInfo) {
339 if (typeInfo->encode_start) {
340 return (*typeInfo->encode_start)(gd);
341 }
342 /* decoder ops optional for data tags */
343 if (typeInfo->isData) {
344 return SECSuccess;
345 }
346 }
347 /* expected a function, but none existed */
348 return SECFailure;
349 }
350
351 SECStatus
352 NSS_CMSGenericWrapperData_Encode_BeforeData(SECOidTag type,
353 NSSCMSGenericWrapperData *gd)
354 {
355 const nsscmstypeInfo *typeInfo;
356
357 /* short cut common case */
358 if (type == SEC_OID_PKCS7_DATA) {
359 return SECSuccess;
360 }
361
362 typeInfo = nss_cmstype_lookup(type);
363 if (typeInfo) {
364 if (typeInfo->encode_before) {
365 return (*typeInfo->encode_before)(gd);
366 }
367 /* decoder ops optional for data tags */
368 if (typeInfo->isData) {
369 return SECSuccess;
370 }
371 }
372 /* expected a function, but none existed */
373 return SECFailure;
374 }
375
376 SECStatus
377 NSS_CMSGenericWrapperData_Encode_AfterData(SECOidTag type,
378 NSSCMSGenericWrapperData *gd)
379 {
380 const nsscmstypeInfo *typeInfo;
381
382 /* short cut common case */
383 if (type == SEC_OID_PKCS7_DATA) {
384 return SECSuccess;
385 }
386
387 typeInfo = nss_cmstype_lookup(type);
388 if (typeInfo) {
389 if (typeInfo->encode_after) {
390 return (*typeInfo->encode_after)(gd);
391 }
392 /* decoder ops optional for data tags */
393 if (typeInfo->isData) {
394 return SECSuccess;
395 }
396 }
397 /* expected a function, but none existed */
398 return SECFailure;
399 }
400
401
402 SECStatus
403 NSS_CMSType_RegisterContentType(SECOidTag type,
404 SEC_ASN1Template *asn1Template, size_t size,
405 NSSCMSGenericWrapperDataDestroy destroy,
406 NSSCMSGenericWrapperDataCallback decode_before,
407 NSSCMSGenericWrapperDataCallback decode_after,
408 NSSCMSGenericWrapperDataCallback decode_end,
409 NSSCMSGenericWrapperDataCallback encode_start,
410 NSSCMSGenericWrapperDataCallback encode_before,
411 NSSCMSGenericWrapperDataCallback encode_after,
412 PRBool isData)
413 {
414 PRStatus rc;
415 SECStatus rv;
416 nsscmstypeInfo *typeInfo;
417 const nsscmstypeInfo *exists;
418
419 rc = PR_CallOnce( &nsscmstypeOnce, nss_cmstype_init);
420 if (rc == PR_FAILURE) {
421 return SECFailure;
422 }
423 PR_Lock(nsscmstypeAddLock);
424 exists = nss_cmstype_lookup(type);
425 if (exists) {
426 PR_Unlock(nsscmstypeAddLock);
427 /* already added */
428 return SECSuccess;
429 }
430 typeInfo = PORT_ArenaNew(nsscmstypeArena, nsscmstypeInfo);
431 typeInfo->type = type;
432 typeInfo->size = size;
433 typeInfo->isData = isData;
434 typeInfo->template = asn1Template;
435 typeInfo->destroy = destroy;
436 typeInfo->decode_before = decode_before;
437 typeInfo->decode_after = decode_after;
438 typeInfo->decode_end = decode_end;
439 typeInfo->encode_start = encode_start;
440 typeInfo->encode_before = encode_before;
441 typeInfo->encode_after = encode_after;
442 rv = nss_cmstype_add(type, typeInfo);
443 PR_Unlock(nsscmstypeAddLock);
444 return rv;
445 }
446

mercurial