Coverage Report

Created: 2018-09-25 14:53

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