Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/security/nss/lib/smime/cmsdigest.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 digesting.
7
 */
8
9
#include "cmslocal.h"
10
11
#include "cert.h"
12
#include "keyhi.h"
13
#include "secitem.h"
14
#include "secoid.h"
15
#include "pk11func.h"
16
#include "prtime.h"
17
#include "secerr.h"
18
19
/*  #define CMS_FIND_LEAK_MULTIPLE 1 */
20
#ifdef CMS_FIND_LEAK_MULTIPLE
21
static int stop_on_err = 1;
22
static int global_num_digests = 0;
23
#endif
24
25
struct digestPairStr {
26
    const SECHashObject *digobj;
27
    void *digcx;
28
};
29
typedef struct digestPairStr digestPair;
30
31
struct NSSCMSDigestContextStr {
32
    PRBool saw_contents;
33
    PLArenaPool *pool;
34
    int digcnt;
35
    digestPair *digPairs;
36
};
37
38
/*
39
 * NSS_CMSDigestContext_StartMultiple - start digest calculation using all the
40
 *  digest algorithms in "digestalgs" in parallel.
41
 */
42
NSSCMSDigestContext *
43
NSS_CMSDigestContext_StartMultiple(SECAlgorithmID **digestalgs)
44
0
{
45
0
    PLArenaPool *pool;
46
0
    NSSCMSDigestContext *cmsdigcx;
47
0
    int digcnt;
48
0
    int i;
49
0
50
#ifdef CMS_FIND_LEAK_MULTIPLE
51
    PORT_Assert(global_num_digests == 0 || !stop_on_err);
52
#endif
53
54
0
    digcnt = (digestalgs == NULL) ? 0 : NSS_CMSArray_Count((void **)digestalgs);
55
0
    /* It's OK if digcnt is zero.  We have to allow this for "certs only"
56
0
    ** messages.
57
0
    */
58
0
    pool = PORT_NewArena(2048);
59
0
    if (!pool)
60
0
        return NULL;
61
0
62
0
    cmsdigcx = PORT_ArenaNew(pool, NSSCMSDigestContext);
63
0
    if (cmsdigcx == NULL)
64
0
        goto loser;
65
0
66
0
    cmsdigcx->saw_contents = PR_FALSE;
67
0
    cmsdigcx->pool = pool;
68
0
    cmsdigcx->digcnt = digcnt;
69
0
70
0
    cmsdigcx->digPairs = PORT_ArenaZNewArray(pool, digestPair, digcnt);
71
0
    if (cmsdigcx->digPairs == NULL) {
72
0
        goto loser;
73
0
    }
74
0
75
0
    /*
76
0
     * Create a digest object context for each algorithm.
77
0
     */
78
0
    for (i = 0; i < digcnt; i++) {
79
0
        const SECHashObject *digobj;
80
0
        void *digcx;
81
0
82
0
        digobj = NSS_CMSUtil_GetHashObjByAlgID(digestalgs[i]);
83
0
        /*
84
0
         * Skip any algorithm we do not even recognize; obviously,
85
0
         * this could be a problem, but if it is critical then the
86
0
         * result will just be that the signature does not verify.
87
0
         * We do not necessarily want to error out here, because
88
0
         * the particular algorithm may not actually be important,
89
0
         * but we cannot know that until later.
90
0
         */
91
0
        if (digobj == NULL)
92
0
            continue;
93
0
94
0
        digcx = (*digobj->create)();
95
0
        if (digcx != NULL) {
96
0
            (*digobj->begin)(digcx);
97
0
            cmsdigcx->digPairs[i].digobj = digobj;
98
0
            cmsdigcx->digPairs[i].digcx = digcx;
99
#ifdef CMS_FIND_LEAK_MULTIPLE
100
            global_num_digests++;
101
#endif
102
        }
103
0
    }
104
0
    return cmsdigcx;
105
0
106
0
loser:
107
0
    /* no digest objects have been created, or need to be destroyed. */
108
0
    if (pool) {
109
0
        PORT_FreeArena(pool, PR_FALSE);
110
0
    }
111
0
    return NULL;
112
0
}
113
114
/*
115
 * NSS_CMSDigestContext_StartSingle - same as
116
 * NSS_CMSDigestContext_StartMultiple, but only one algorithm.
117
 */
118
NSSCMSDigestContext *
119
NSS_CMSDigestContext_StartSingle(SECAlgorithmID *digestalg)
120
0
{
121
0
    SECAlgorithmID *digestalgs[] = { NULL, NULL }; /* fake array */
122
0
123
0
    digestalgs[0] = digestalg;
124
0
    return NSS_CMSDigestContext_StartMultiple(digestalgs);
125
0
}
126
127
/*
128
 * NSS_CMSDigestContext_Update - feed more data into the digest machine
129
 */
130
void
131
NSS_CMSDigestContext_Update(NSSCMSDigestContext *cmsdigcx,
132
                            const unsigned char *data, int len)
133
0
{
134
0
    int i;
135
0
    digestPair *pair = cmsdigcx->digPairs;
136
0
137
0
    cmsdigcx->saw_contents = PR_TRUE;
138
0
139
0
    for (i = 0; i < cmsdigcx->digcnt; i++, pair++) {
140
0
        if (pair->digcx) {
141
0
            (*pair->digobj->update)(pair->digcx, data, len);
142
0
        }
143
0
    }
144
0
}
145
146
/*
147
 * NSS_CMSDigestContext_Cancel - cancel digesting operation
148
 */
149
void
150
NSS_CMSDigestContext_Cancel(NSSCMSDigestContext *cmsdigcx)
151
0
{
152
0
    int i;
153
0
    digestPair *pair = cmsdigcx->digPairs;
154
0
155
0
    for (i = 0; i < cmsdigcx->digcnt; i++, pair++) {
156
0
        if (pair->digcx) {
157
0
            (*pair->digobj->destroy)(pair->digcx, PR_TRUE);
158
#ifdef CMS_FIND_LEAK_MULTIPLE
159
            --global_num_digests;
160
#endif
161
        }
162
0
    }
163
#ifdef CMS_FIND_LEAK_MULTIPLE
164
    PORT_Assert(global_num_digests == 0 || !stop_on_err);
165
#endif
166
0
    PORT_FreeArena(cmsdigcx->pool, PR_FALSE);
167
0
}
168
169
/*
170
 * NSS_CMSDigestContext_FinishMultiple - finish the digests and put them
171
 *  into an array of SECItems (allocated on poolp)
172
 */
173
SECStatus
174
NSS_CMSDigestContext_FinishMultiple(NSSCMSDigestContext *cmsdigcx,
175
                                    PLArenaPool *poolp,
176
                                    SECItem ***digestsp)
177
0
{
178
0
    SECItem **digests = NULL;
179
0
    digestPair *pair;
180
0
    void *mark;
181
0
    int i;
182
0
    SECStatus rv;
183
0
184
0
    /* no contents? do not finish digests */
185
0
    if (digestsp == NULL || !cmsdigcx->saw_contents) {
186
0
        rv = SECSuccess;
187
0
        goto cleanup;
188
0
    }
189
0
190
0
    mark = PORT_ArenaMark(poolp);
191
0
192
0
    /* allocate digest array & SECItems on arena */
193
0
    digests = PORT_ArenaNewArray(poolp, SECItem *, cmsdigcx->digcnt + 1);
194
0
195
0
    rv = ((digests == NULL) ? SECFailure : SECSuccess);
196
0
    pair = cmsdigcx->digPairs;
197
0
    for (i = 0; rv == SECSuccess && i < cmsdigcx->digcnt; i++, pair++) {
198
0
        SECItem digest;
199
0
        unsigned char hash[HASH_LENGTH_MAX];
200
0
201
0
        if (!pair->digcx) {
202
0
            digests[i] = NULL;
203
0
            continue;
204
0
        }
205
0
206
0
        digest.type = siBuffer;
207
0
        digest.data = hash;
208
0
        digest.len = pair->digobj->length;
209
0
        (*pair->digobj->end)(pair->digcx, hash, &digest.len, digest.len);
210
0
        digests[i] = SECITEM_ArenaDupItem(poolp, &digest);
211
0
        if (!digests[i]) {
212
0
            rv = SECFailure;
213
0
        }
214
0
    }
215
0
    digests[i] = NULL;
216
0
    if (rv == SECSuccess) {
217
0
        PORT_ArenaUnmark(poolp, mark);
218
0
    } else
219
0
        PORT_ArenaRelease(poolp, mark);
220
0
221
0
cleanup:
222
0
    NSS_CMSDigestContext_Cancel(cmsdigcx);
223
0
    /* Don't change the caller's digests pointer if we have no digests.
224
0
    **  NSS_CMSSignedData_Encode_AfterData depends on this behavior.
225
0
    */
226
0
    if (rv == SECSuccess && digestsp && digests) {
227
0
        *digestsp = digests;
228
0
    }
229
0
    return rv;
230
0
}
231
232
/*
233
 * NSS_CMSDigestContext_FinishSingle - same as
234
 * NSS_CMSDigestContext_FinishMultiple, but for one digest.
235
 */
236
SECStatus
237
NSS_CMSDigestContext_FinishSingle(NSSCMSDigestContext *cmsdigcx,
238
                                  PLArenaPool *poolp,
239
                                  SECItem *digest)
240
0
{
241
0
    SECStatus rv = SECFailure;
242
0
    SECItem **dp;
243
0
    PLArenaPool *arena = NULL;
244
0
245
0
    if ((arena = PORT_NewArena(1024)) == NULL)
246
0
        goto loser;
247
0
248
0
    /* get the digests into arena, then copy the first digest into poolp */
249
0
    rv = NSS_CMSDigestContext_FinishMultiple(cmsdigcx, arena, &dp);
250
0
    if (rv == SECSuccess) {
251
0
        /* now copy it into poolp */
252
0
        rv = SECITEM_CopyItem(poolp, digest, dp[0]);
253
0
    }
254
0
loser:
255
0
    if (arena)
256
0
        PORT_FreeArena(arena, PR_FALSE);
257
0
258
0
    return rv;
259
0
}