Coverage Report

Created: 2018-09-25 14:53

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