Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/security/nss/lib/smime/cmsutil.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 miscellaneous utility functions.
7
 */
8
9
#include "cmslocal.h"
10
11
#include "cert.h"
12
#include "keyhi.h"
13
#include "secasn1.h"
14
#include "secitem.h"
15
#include "secoid.h"
16
#include "pk11func.h"
17
#include "secerr.h"
18
#include "sechash.h"
19
20
/*
21
 * NSS_CMSArray_SortByDER - sort array of objects by objects' DER encoding
22
 *
23
 * make sure that the order of the objects guarantees valid DER (which must be
24
 * in lexigraphically ascending order for a SET OF); if reordering is necessary it
25
 * will be done in place (in objs).
26
 */
27
SECStatus
28
NSS_CMSArray_SortByDER(void **objs, const SEC_ASN1Template *objtemplate, void **objs2)
29
0
{
30
0
    PLArenaPool *poolp;
31
0
    int num_objs;
32
0
    SECItem **enc_objs;
33
0
    SECStatus rv = SECFailure;
34
0
    int i;
35
0
36
0
    if (objs == NULL) /* already sorted */
37
0
        return SECSuccess;
38
0
39
0
    num_objs = NSS_CMSArray_Count((void **)objs);
40
0
    if (num_objs == 0 || num_objs == 1) /* already sorted. */
41
0
        return SECSuccess;
42
0
43
0
    poolp = PORT_NewArena(1024); /* arena for temporaries */
44
0
    if (poolp == NULL)
45
0
        return SECFailure; /* no memory; nothing we can do... */
46
0
47
0
    /*
48
0
     * Allocate arrays to hold the individual encodings which we will use
49
0
     * for comparisons and the reordered attributes as they are sorted.
50
0
     */
51
0
    enc_objs = (SECItem **)PORT_ArenaZAlloc(poolp, (num_objs + 1) * sizeof(SECItem *));
52
0
    if (enc_objs == NULL)
53
0
        goto loser;
54
0
55
0
    /* DER encode each individual object. */
56
0
    for (i = 0; i < num_objs; i++) {
57
0
        enc_objs[i] = SEC_ASN1EncodeItem(poolp, NULL, objs[i], objtemplate);
58
0
        if (enc_objs[i] == NULL)
59
0
            goto loser;
60
0
    }
61
0
    enc_objs[num_objs] = NULL;
62
0
63
0
    /* now compare and sort objs by the order of enc_objs */
64
0
    NSS_CMSArray_Sort((void **)enc_objs, NSS_CMSUtil_DERCompare, objs, objs2);
65
0
66
0
    rv = SECSuccess;
67
0
68
0
loser:
69
0
    PORT_FreeArena(poolp, PR_FALSE);
70
0
    return rv;
71
0
}
72
73
/*
74
 * NSS_CMSUtil_DERCompare - for use with NSS_CMSArray_Sort to
75
 *  sort arrays of SECItems containing DER
76
 */
77
int
78
NSS_CMSUtil_DERCompare(void *a, void *b)
79
0
{
80
0
    SECItem *der1 = (SECItem *)a;
81
0
    SECItem *der2 = (SECItem *)b;
82
0
    unsigned int j;
83
0
84
0
    /*
85
0
     * Find the lowest (lexigraphically) encoding.  One that is
86
0
     * shorter than all the rest is known to be "less" because each
87
0
     * attribute is of the same type (a SEQUENCE) and so thus the
88
0
     * first octet of each is the same, and the second octet is
89
0
     * the length (or the length of the length with the high bit
90
0
     * set, followed by the length, which also works out to always
91
0
     * order the shorter first).  Two (or more) that have the
92
0
     * same length need to be compared byte by byte until a mismatch
93
0
     * is found.
94
0
     */
95
0
    if (der1->len != der2->len)
96
0
        return (der1->len < der2->len) ? -1 : 1;
97
0
98
0
    for (j = 0; j < der1->len; j++) {
99
0
        if (der1->data[j] == der2->data[j])
100
0
            continue;
101
0
        return (der1->data[j] < der2->data[j]) ? -1 : 1;
102
0
    }
103
0
    return 0;
104
0
}
105
106
/*
107
 * NSS_CMSAlgArray_GetIndexByAlgID - find a specific algorithm in an array of
108
 * algorithms.
109
 *
110
 * algorithmArray - array of algorithm IDs
111
 * algid - algorithmid of algorithm to pick
112
 *
113
 * Returns:
114
 *  An integer containing the index of the algorithm in the array or -1 if
115
 *  algorithm was not found.
116
 */
117
int
118
NSS_CMSAlgArray_GetIndexByAlgID(SECAlgorithmID **algorithmArray, SECAlgorithmID *algid)
119
0
{
120
0
    int i;
121
0
122
0
    if (algorithmArray == NULL || algorithmArray[0] == NULL)
123
0
        return -1;
124
0
125
0
    for (i = 0; algorithmArray[i] != NULL; i++) {
126
0
        if (SECOID_CompareAlgorithmID(algorithmArray[i], algid) == SECEqual)
127
0
            break; /* bingo */
128
0
    }
129
0
130
0
    if (algorithmArray[i] == NULL)
131
0
        return -1; /* not found */
132
0
133
0
    return i;
134
0
}
135
136
/*
137
 * NSS_CMSAlgArray_GetIndexByAlgTag - find a specific algorithm in an array of
138
 * algorithms.
139
 *
140
 * algorithmArray - array of algorithm IDs
141
 * algtag - algorithm tag of algorithm to pick
142
 *
143
 * Returns:
144
 *  An integer containing the index of the algorithm in the array or -1 if
145
 *  algorithm was not found.
146
 */
147
int
148
NSS_CMSAlgArray_GetIndexByAlgTag(SECAlgorithmID **algorithmArray,
149
                                 SECOidTag algtag)
150
0
{
151
0
    SECOidData *algid;
152
0
    int i = -1;
153
0
154
0
    if (algorithmArray == NULL || algorithmArray[0] == NULL)
155
0
        return i;
156
0
157
#ifdef ORDER_N_SQUARED
158
    for (i = 0; algorithmArray[i] != NULL; i++) {
159
        algid = SECOID_FindOID(&(algorithmArray[i]->algorithm));
160
        if (algid->offset == algtag)
161
            break; /* bingo */
162
    }
163
#else
164
0
    algid = SECOID_FindOIDByTag(algtag);
165
0
    if (!algid)
166
0
        return i;
167
0
    for (i = 0; algorithmArray[i] != NULL; i++) {
168
0
        if (SECITEM_ItemsAreEqual(&algorithmArray[i]->algorithm, &algid->oid))
169
0
            break; /* bingo */
170
0
    }
171
0
#endif
172
0
173
0
    if (algorithmArray[i] == NULL)
174
0
        return -1; /* not found */
175
0
176
0
    return i;
177
0
}
178
179
/*
180
 * Map a sign algorithm to a digest algorithm.
181
 * This is used to handle incorrectly formatted packages sent to us
182
 * from Windows 2003.
183
 */
184
SECOidTag
185
NSS_CMSUtil_MapSignAlgs(SECOidTag signAlg)
186
0
{
187
0
    switch (signAlg) {
188
0
        case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
189
0
            return SEC_OID_MD2;
190
0
            break;
191
0
        case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
192
0
            return SEC_OID_MD5;
193
0
            break;
194
0
        case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
195
0
        case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE:
196
0
        case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST:
197
0
            return SEC_OID_SHA1;
198
0
            break;
199
0
        case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
200
0
        case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE:
201
0
            return SEC_OID_SHA256;
202
0
            break;
203
0
        case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION:
204
0
        case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE:
205
0
            return SEC_OID_SHA384;
206
0
            break;
207
0
        case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
208
0
        case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE:
209
0
            return SEC_OID_SHA512;
210
0
            break;
211
0
        default:
212
0
            break;
213
0
    }
214
0
    /* not one of the algtags incorrectly sent to us*/
215
0
    return signAlg;
216
0
}
217
218
const SECHashObject *
219
NSS_CMSUtil_GetHashObjByAlgID(SECAlgorithmID *algid)
220
0
{
221
0
    SECOidTag oidTag = SECOID_FindOIDTag(&(algid->algorithm));
222
0
    const SECHashObject *digobj = HASH_GetHashObjectByOidTag(oidTag);
223
0
224
0
    return digobj;
225
0
}
226
227
const SEC_ASN1Template *
228
NSS_CMSUtil_GetTemplateByTypeTag(SECOidTag type)
229
0
{
230
0
    const SEC_ASN1Template *template;
231
0
    extern const SEC_ASN1Template NSSCMSSignedDataTemplate[];
232
0
    extern const SEC_ASN1Template NSSCMSEnvelopedDataTemplate[];
233
0
    extern const SEC_ASN1Template NSSCMSEncryptedDataTemplate[];
234
0
    extern const SEC_ASN1Template NSSCMSDigestedDataTemplate[];
235
0
236
0
    switch (type) {
237
0
        case SEC_OID_PKCS7_SIGNED_DATA:
238
0
            template = NSSCMSSignedDataTemplate;
239
0
            break;
240
0
        case SEC_OID_PKCS7_ENVELOPED_DATA:
241
0
            template = NSSCMSEnvelopedDataTemplate;
242
0
            break;
243
0
        case SEC_OID_PKCS7_ENCRYPTED_DATA:
244
0
            template = NSSCMSEncryptedDataTemplate;
245
0
            break;
246
0
        case SEC_OID_PKCS7_DIGESTED_DATA:
247
0
            template = NSSCMSDigestedDataTemplate;
248
0
            break;
249
0
        default:
250
0
            template = NSS_CMSType_GetTemplate(type);
251
0
            break;
252
0
    }
253
0
    return template;
254
0
}
255
256
size_t
257
NSS_CMSUtil_GetSizeByTypeTag(SECOidTag type)
258
0
{
259
0
    size_t size;
260
0
261
0
    switch (type) {
262
0
        case SEC_OID_PKCS7_SIGNED_DATA:
263
0
            size = sizeof(NSSCMSSignedData);
264
0
            break;
265
0
        case SEC_OID_PKCS7_ENVELOPED_DATA:
266
0
            size = sizeof(NSSCMSEnvelopedData);
267
0
            break;
268
0
        case SEC_OID_PKCS7_ENCRYPTED_DATA:
269
0
            size = sizeof(NSSCMSEncryptedData);
270
0
            break;
271
0
        case SEC_OID_PKCS7_DIGESTED_DATA:
272
0
            size = sizeof(NSSCMSDigestedData);
273
0
            break;
274
0
        default:
275
0
            size = NSS_CMSType_GetContentSize(type);
276
0
            break;
277
0
    }
278
0
    return size;
279
0
}
280
281
NSSCMSContentInfo *
282
NSS_CMSContent_GetContentInfo(void *msg, SECOidTag type)
283
0
{
284
0
    NSSCMSContent c;
285
0
    NSSCMSContentInfo *cinfo = NULL;
286
0
287
0
    if (!msg)
288
0
        return cinfo;
289
0
    c.pointer = msg;
290
0
    switch (type) {
291
0
        case SEC_OID_PKCS7_SIGNED_DATA:
292
0
            cinfo = &(c.signedData->contentInfo);
293
0
            break;
294
0
        case SEC_OID_PKCS7_ENVELOPED_DATA:
295
0
            cinfo = &(c.envelopedData->contentInfo);
296
0
            break;
297
0
        case SEC_OID_PKCS7_ENCRYPTED_DATA:
298
0
            cinfo = &(c.encryptedData->contentInfo);
299
0
            break;
300
0
        case SEC_OID_PKCS7_DIGESTED_DATA:
301
0
            cinfo = &(c.digestedData->contentInfo);
302
0
            break;
303
0
        default:
304
0
            cinfo = NULL;
305
0
            if (NSS_CMSType_IsWrapper(type)) {
306
0
                cinfo = &(c.genericData->contentInfo);
307
0
            }
308
0
    }
309
0
    return cinfo;
310
0
}
311
312
const char *
313
NSS_CMSUtil_VerificationStatusToString(NSSCMSVerificationStatus vs)
314
{
315
    switch (vs) {
316
        case NSSCMSVS_Unverified:
317
            return "Unverified";
318
        case NSSCMSVS_GoodSignature:
319
            return "GoodSignature";
320
        case NSSCMSVS_BadSignature:
321
            return "BadSignature";
322
        case NSSCMSVS_DigestMismatch:
323
            return "DigestMismatch";
324
        case NSSCMSVS_SigningCertNotFound:
325
            return "SigningCertNotFound";
326
        case NSSCMSVS_SigningCertNotTrusted:
327
            return "SigningCertNotTrusted";
328
        case NSSCMSVS_SignatureAlgorithmUnknown:
329
            return "SignatureAlgorithmUnknown";
330
        case NSSCMSVS_SignatureAlgorithmUnsupported:
331
            return "SignatureAlgorithmUnsupported";
332
        case NSSCMSVS_MalformedSignature:
333
            return "MalformedSignature";
334
        case NSSCMSVS_ProcessingError:
335
            return "ProcessingError";
336
        default:
337
            return "Unknown";
338
    }
339
}
340
341
SECStatus
342
NSS_CMSDEREncode(NSSCMSMessage *cmsg, SECItem *input, SECItem *derOut,
343
                 PLArenaPool *arena)
344
0
{
345
0
    NSSCMSEncoderContext *ecx;
346
0
    SECStatus rv = SECSuccess;
347
0
    if (!cmsg || !derOut || !arena) {
348
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
349
0
        return SECFailure;
350
0
    }
351
0
    ecx = NSS_CMSEncoder_Start(cmsg, 0, 0, derOut, arena, 0, 0, 0, 0, 0, 0);
352
0
    if (!ecx) {
353
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
354
0
        return SECFailure;
355
0
    }
356
0
    if (input) {
357
0
        rv = NSS_CMSEncoder_Update(ecx, (const char *)input->data, input->len);
358
0
        if (rv) {
359
0
            PORT_SetError(SEC_ERROR_BAD_DATA);
360
0
        }
361
0
    }
362
0
    rv |= NSS_CMSEncoder_Finish(ecx);
363
0
    if (rv) {
364
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
365
0
    }
366
0
    return rv;
367
0
}