Coverage Report

Created: 2025-07-04 06:19

/src/nss/lib/smime/cmsencdata.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 encryptedData methods.
7
 */
8
9
#include "cmslocal.h"
10
11
#include "keyhi.h"
12
#include "secasn1.h"
13
#include "secitem.h"
14
#include "secoid.h"
15
#include "pk11func.h"
16
#include "prtime.h"
17
#include "secerr.h"
18
#include "secpkcs5.h"
19
#include "smime.h"
20
21
/*
22
 * NSS_CMSEncryptedData_Create - create an empty encryptedData object.
23
 *
24
 * "algorithm" specifies the bulk encryption algorithm to use.
25
 * "keysize" is the key size.
26
 *
27
 * An error results in a return value of NULL and an error set.
28
 * (Retrieve specific errors via PORT_GetError()/XP_GetError().)
29
 */
30
NSSCMSEncryptedData *
31
NSS_CMSEncryptedData_Create(NSSCMSMessage *cmsg, SECOidTag algorithm,
32
                            int keysize)
33
0
{
34
0
    void *mark;
35
0
    NSSCMSEncryptedData *encd;
36
0
    PLArenaPool *poolp;
37
0
    SECAlgorithmID *pbe_algid;
38
0
    SECStatus rv;
39
40
0
    poolp = cmsg->poolp;
41
42
0
    mark = PORT_ArenaMark(poolp);
43
44
0
    encd = PORT_ArenaZNew(poolp, NSSCMSEncryptedData);
45
0
    if (encd == NULL)
46
0
        goto loser;
47
48
0
    encd->cmsg = cmsg;
49
50
    /* version is set in NSS_CMSEncryptedData_Encode_BeforeStart() */
51
52
0
    if (!SEC_PKCS5IsAlgorithmPBEAlgTag(algorithm)) {
53
0
        rv = NSS_CMSContentInfo_SetContentEncAlg(poolp, &(encd->contentInfo),
54
0
                                                 algorithm, NULL, keysize);
55
0
    } else {
56
        /* Assume password-based-encryption.
57
         * Note: we can't generate pkcs5v2 from this interface.
58
         * PK11_CreateBPEAlgorithmID generates pkcs5v2 by accepting
59
         * non-PBE oids and assuming that they are pkcs5v2 oids, but
60
         * NSS_CMSEncryptedData_Create accepts non-PBE oids as regular
61
         * CMS encrypted data, so we can't tell NSS_CMS_EncryptedData_Create
62
         * to create pkcs5v2 PBEs */
63
0
        pbe_algid = PK11_CreatePBEAlgorithmID(algorithm, 1, NULL);
64
0
        if (pbe_algid == NULL) {
65
0
            rv = SECFailure;
66
0
        } else {
67
0
            rv = NSS_CMSContentInfo_SetContentEncAlgID(poolp,
68
0
                                                       &(encd->contentInfo),
69
0
                                                       pbe_algid, keysize);
70
0
            SECOID_DestroyAlgorithmID(pbe_algid, PR_TRUE);
71
0
        }
72
0
    }
73
0
    if (rv != SECSuccess)
74
0
        goto loser;
75
76
0
    PORT_ArenaUnmark(poolp, mark);
77
0
    return encd;
78
79
0
loser:
80
0
    PORT_ArenaRelease(poolp, mark);
81
0
    return NULL;
82
0
}
83
84
/*
85
 * NSS_CMSEncryptedData_Destroy - destroy an encryptedData object
86
 */
87
void
88
NSS_CMSEncryptedData_Destroy(NSSCMSEncryptedData *encd)
89
19
{
90
    /* everything's in a pool, so don't worry about the storage */
91
19
    if (encd != NULL) {
92
16
        NSS_CMSContentInfo_Destroy(&(encd->contentInfo));
93
16
    }
94
19
    return;
95
19
}
96
97
/*
98
 * NSS_CMSEncryptedData_GetContentInfo - return pointer to encryptedData object's contentInfo
99
 */
100
NSSCMSContentInfo *
101
NSS_CMSEncryptedData_GetContentInfo(NSSCMSEncryptedData *encd)
102
0
{
103
0
    return &(encd->contentInfo);
104
0
}
105
106
/*
107
 * NSS_CMSEncryptedData_Encode_BeforeStart - do all the necessary things to a EncryptedData
108
 *     before encoding begins.
109
 *
110
 * In particular:
111
 *  - set the correct version value.
112
 *  - get the encryption key
113
 */
114
SECStatus
115
NSS_CMSEncryptedData_Encode_BeforeStart(NSSCMSEncryptedData *encd)
116
0
{
117
0
    int version;
118
0
    PK11SymKey *bulkkey = NULL;
119
0
    SECItem *dummy;
120
0
    NSSCMSContentInfo *cinfo = &(encd->contentInfo);
121
0
    SECAlgorithmID *algid = NULL;
122
123
0
    if (NSS_CMSArray_IsEmpty((void **)encd->unprotectedAttr))
124
0
        version = NSS_CMS_ENCRYPTED_DATA_VERSION;
125
0
    else
126
0
        version = NSS_CMS_ENCRYPTED_DATA_VERSION_UPATTR;
127
128
0
    dummy = SEC_ASN1EncodeInteger(encd->cmsg->poolp, &(encd->version), version);
129
0
    if (dummy == NULL)
130
0
        return SECFailure;
131
132
    /* now get content encryption key (bulk key) by using our cmsg callback */
133
0
    if (encd->cmsg->decrypt_key_cb) {
134
0
        algid = NSS_CMSContentInfo_GetContentEncAlg(cinfo);
135
0
        bulkkey = (*encd->cmsg->decrypt_key_cb)(encd->cmsg->decrypt_key_cb_arg, algid);
136
0
    }
137
0
    if ((bulkkey == NULL) || (algid == NULL))
138
0
        return SECFailure;
139
140
    /* store the bulk key in the contentInfo so that the encoder can find it */
141
0
    NSS_CMSContentInfo_SetBulkKey(cinfo, bulkkey);
142
0
    PK11_FreeSymKey(bulkkey);
143
144
0
    return SECSuccess;
145
0
}
146
147
/*
148
 * NSS_CMSEncryptedData_Encode_BeforeData - set up encryption
149
 */
150
SECStatus
151
NSS_CMSEncryptedData_Encode_BeforeData(NSSCMSEncryptedData *encd)
152
0
{
153
0
    NSSCMSContentInfo *cinfo;
154
0
    PK11SymKey *bulkkey = NULL;
155
0
    SECAlgorithmID *algid;
156
0
    SECStatus rv = SECFailure;
157
158
0
    cinfo = &(encd->contentInfo);
159
160
    /* find bulkkey and algorithm - must have been set by NSS_CMSEncryptedData_Encode_BeforeStart */
161
0
    bulkkey = NSS_CMSContentInfo_GetBulkKey(cinfo);
162
0
    if (bulkkey == NULL) {
163
0
        goto loser;
164
0
    }
165
166
0
    algid = NSS_CMSContentInfo_GetContentEncAlg(cinfo);
167
0
    if (algid == NULL) {
168
0
        goto loser;
169
0
    }
170
171
0
    rv = NSS_CMSContentInfo_Private_Init(cinfo);
172
0
    if (rv != SECSuccess) {
173
0
        goto loser;
174
0
    }
175
176
0
    if (!NSS_SMIMEUtil_EncryptionAllowed(algid, bulkkey)) {
177
0
        goto loser;
178
0
    }
179
180
    /* this may modify algid (with IVs generated in a token).
181
     * it is therefore essential that algid is a pointer to the "real" contentEncAlg,
182
     * not just to a copy */
183
0
    cinfo->privateInfo->ciphcx = NSS_CMSCipherContext_StartEncrypt(encd->cmsg->poolp,
184
0
                                                                   bulkkey, algid);
185
0
    if (cinfo->privateInfo->ciphcx == NULL)
186
0
        goto loser;
187
188
0
    rv = SECSuccess;
189
190
0
loser:
191
0
    if (bulkkey) {
192
0
        PK11_FreeSymKey(bulkkey);
193
0
    }
194
0
    return rv;
195
0
}
196
197
/*
198
 * NSS_CMSEncryptedData_Encode_AfterData - finalize this encryptedData for encoding
199
 */
200
SECStatus
201
NSS_CMSEncryptedData_Encode_AfterData(NSSCMSEncryptedData *encd)
202
0
{
203
0
    if (encd->contentInfo.privateInfo && encd->contentInfo.privateInfo->ciphcx) {
204
0
        NSS_CMSCipherContext_Destroy(encd->contentInfo.privateInfo->ciphcx);
205
0
        encd->contentInfo.privateInfo->ciphcx = NULL;
206
0
    }
207
208
    /* nothing to do after data */
209
0
    return SECSuccess;
210
0
}
211
212
/*
213
 * NSS_CMSEncryptedData_Decode_BeforeData - find bulk key & set up decryption
214
 */
215
SECStatus
216
NSS_CMSEncryptedData_Decode_BeforeData(NSSCMSEncryptedData *encd)
217
4
{
218
4
    PK11SymKey *bulkkey = NULL;
219
4
    NSSCMSContentInfo *cinfo;
220
4
    SECAlgorithmID *bulkalg;
221
4
    SECStatus rv = SECFailure;
222
223
4
    cinfo = &(encd->contentInfo);
224
225
4
    bulkalg = NSS_CMSContentInfo_GetContentEncAlg(cinfo);
226
227
4
    if (encd->cmsg->decrypt_key_cb == NULL) /* no callback? no key../ */
228
4
        goto loser;
229
230
0
    bulkkey = (*encd->cmsg->decrypt_key_cb)(encd->cmsg->decrypt_key_cb_arg, bulkalg);
231
0
    if (bulkkey == NULL)
232
        /* no success finding a bulk key */
233
0
        goto loser;
234
235
0
    NSS_CMSContentInfo_SetBulkKey(cinfo, bulkkey);
236
237
0
    rv = NSS_CMSContentInfo_Private_Init(cinfo);
238
0
    if (rv != SECSuccess) {
239
0
        goto loser;
240
0
    }
241
0
    rv = SECFailure;
242
243
0
    if (!NSS_SMIMEUtil_DecryptionAllowed(bulkalg, bulkkey)) {
244
0
        goto loser;
245
0
    }
246
247
0
    cinfo->privateInfo->ciphcx = NSS_CMSCipherContext_StartDecrypt(bulkkey, bulkalg);
248
0
    if (cinfo->privateInfo->ciphcx == NULL)
249
0
        goto loser; /* error has been set by NSS_CMSCipherContext_StartDecrypt */
250
0
    rv = SECSuccess;
251
252
4
loser:
253
4
    if (bulkkey) {
254
0
        PK11_FreeSymKey(bulkkey);
255
0
    }
256
4
    return rv;
257
0
}
258
259
/*
260
 * NSS_CMSEncryptedData_Decode_AfterData - finish decrypting this encryptedData's content
261
 */
262
SECStatus
263
NSS_CMSEncryptedData_Decode_AfterData(NSSCMSEncryptedData *encd)
264
3
{
265
3
    if (encd->contentInfo.privateInfo && encd->contentInfo.privateInfo->ciphcx) {
266
0
        NSS_CMSCipherContext_Destroy(encd->contentInfo.privateInfo->ciphcx);
267
0
        encd->contentInfo.privateInfo->ciphcx = NULL;
268
0
    }
269
270
3
    return SECSuccess;
271
3
}
272
273
/*
274
 * NSS_CMSEncryptedData_Decode_AfterEnd - finish decoding this encryptedData
275
 */
276
SECStatus
277
NSS_CMSEncryptedData_Decode_AfterEnd(NSSCMSEncryptedData *encd)
278
2
{
279
    /* apply final touches */
280
2
    return SECSuccess;
281
2
}