Coverage Report

Created: 2025-06-24 06:49

/src/nss/lib/smime/cmsrecinfo.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 recipientInfo methods.
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 "smime.h"
19
20
PRBool
21
nss_cmsrecipientinfo_usessubjectkeyid(NSSCMSRecipientInfo *ri)
22
6.23k
{
23
6.23k
    if (ri->recipientInfoType == NSSCMSRecipientInfoID_KeyTrans) {
24
6.13k
        NSSCMSRecipientIdentifier *rid;
25
6.13k
        rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier;
26
6.13k
        if (rid->identifierType == NSSCMSRecipientID_SubjectKeyID) {
27
2.61k
            return PR_TRUE;
28
2.61k
        }
29
6.13k
    }
30
3.62k
    return PR_FALSE;
31
6.23k
}
32
33
/*
34
 * NOTE: fakeContent marks CMSMessage structure which is only used as a carrier
35
 * of pwfn_arg and arena pools. In an ideal world, NSSCMSMessage would not have
36
 * been exported, and we would have added an ordinary enum to handle this
37
 * check. Unfortunatly wo don't have that luxury so we are overloading the
38
 * contentTypeTag field. NO code should every try to interpret this content tag
39
 * as a real OID tag, or use any fields other than pwfn_arg or poolp of this
40
 * CMSMessage for that matter */
41
static const SECOidData fakeContent;
42
NSSCMSRecipientInfo *
43
nss_cmsrecipientinfo_create(NSSCMSMessage *cmsg,
44
                            NSSCMSRecipientIDSelector type,
45
                            CERTCertificate *cert,
46
                            SECKEYPublicKey *pubKey,
47
                            SECItem *subjKeyID,
48
                            void *pwfn_arg,
49
                            SECItem *DERinput)
50
0
{
51
0
    NSSCMSRecipientInfo *ri;
52
0
    void *mark;
53
0
    SECOidTag certalgtag;
54
0
    SECStatus rv = SECSuccess;
55
0
    NSSCMSRecipientEncryptedKey *rek;
56
0
    NSSCMSOriginatorIdentifierOrKey *oiok;
57
0
    unsigned long version;
58
0
    SECItem *dummy;
59
0
    PLArenaPool *poolp;
60
0
    CERTSubjectPublicKeyInfo *spki, *freeSpki = NULL;
61
0
    NSSCMSRecipientIdentifier *rid;
62
0
    extern const SEC_ASN1Template NSSCMSRecipientInfoTemplate[];
63
64
0
    if (!cmsg) {
65
        /* a CMSMessage wasn't supplied, create a fake one to hold the pwfunc
66
         * and a private arena pool */
67
0
        cmsg = NSS_CMSMessage_Create(NULL);
68
0
        cmsg->pwfn_arg = pwfn_arg;
69
        /* mark it as a special cms message */
70
0
        cmsg->contentInfo.contentTypeTag = (SECOidData *)&fakeContent;
71
0
    }
72
73
0
    poolp = cmsg->poolp;
74
75
0
    mark = PORT_ArenaMark(poolp);
76
77
0
    ri = (NSSCMSRecipientInfo *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSRecipientInfo));
78
0
    if (ri == NULL)
79
0
        goto loser;
80
81
0
    ri->cmsg = cmsg;
82
83
0
    if (DERinput) {
84
        /* decode everything from DER */
85
0
        SECItem newinput;
86
0
        rv = SECITEM_CopyItem(poolp, &newinput, DERinput);
87
0
        if (SECSuccess != rv)
88
0
            goto loser;
89
0
        rv = SEC_QuickDERDecodeItem(poolp, ri, NSSCMSRecipientInfoTemplate, &newinput);
90
0
        if (SECSuccess != rv)
91
0
            goto loser;
92
0
    }
93
94
0
    switch (type) {
95
0
        case NSSCMSRecipientID_IssuerSN: {
96
0
            ri->cert = CERT_DupCertificate(cert);
97
0
            if (NULL == ri->cert)
98
0
                goto loser;
99
0
            spki = &(cert->subjectPublicKeyInfo);
100
0
            break;
101
0
        }
102
103
0
        case NSSCMSRecipientID_SubjectKeyID: {
104
0
            PORT_Assert(pubKey);
105
0
            spki = freeSpki = SECKEY_CreateSubjectPublicKeyInfo(pubKey);
106
0
            break;
107
0
        }
108
109
0
        case NSSCMSRecipientID_BrandNew:
110
0
            goto done;
111
0
            break;
112
113
0
        default:
114
            /* unkown type */
115
0
            goto loser;
116
0
            break;
117
0
    }
118
119
0
    certalgtag = SECOID_GetAlgorithmTag(&(spki->algorithm));
120
121
0
    rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier;
122
123
    // This switch must match the switch in NSS_CMSRecipient_IsSupported.
124
0
    switch (certalgtag) {
125
0
        case SEC_OID_PKCS1_RSA_ENCRYPTION:
126
0
            ri->recipientInfoType = NSSCMSRecipientInfoID_KeyTrans;
127
0
            rid->identifierType = type;
128
0
            if (type == NSSCMSRecipientID_IssuerSN) {
129
0
                rid->id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert);
130
0
                if (rid->id.issuerAndSN == NULL) {
131
0
                    break;
132
0
                }
133
0
            } else if (type == NSSCMSRecipientID_SubjectKeyID) {
134
0
                NSSCMSKeyTransRecipientInfoEx *riExtra;
135
136
0
                rid->id.subjectKeyID = PORT_ArenaNew(poolp, SECItem);
137
0
                if (rid->id.subjectKeyID == NULL) {
138
0
                    rv = SECFailure;
139
0
                    PORT_SetError(SEC_ERROR_NO_MEMORY);
140
0
                    break;
141
0
                }
142
0
                rv = SECITEM_CopyItem(poolp, rid->id.subjectKeyID, subjKeyID);
143
0
                if (rv != SECSuccess || rid->id.subjectKeyID->data == NULL) {
144
0
                    rv = SECFailure;
145
0
                    PORT_SetError(SEC_ERROR_NO_MEMORY);
146
0
                    break;
147
0
                }
148
0
                riExtra = &ri->ri.keyTransRecipientInfoEx;
149
0
                riExtra->version = 0;
150
0
                riExtra->pubKey = SECKEY_CopyPublicKey(pubKey);
151
0
                if (riExtra->pubKey == NULL) {
152
0
                    rv = SECFailure;
153
0
                    PORT_SetError(SEC_ERROR_NO_MEMORY);
154
0
                    break;
155
0
                }
156
0
            } else {
157
0
                PORT_SetError(SEC_ERROR_INVALID_ARGS);
158
0
                rv = SECFailure;
159
0
            }
160
0
            break;
161
0
        case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
162
0
            PORT_Assert(type == NSSCMSRecipientID_IssuerSN);
163
0
            if (type != NSSCMSRecipientID_IssuerSN) {
164
0
                rv = SECFailure;
165
0
                break;
166
0
            }
167
            /* a key agreement op */
168
0
            ri->recipientInfoType = NSSCMSRecipientInfoID_KeyAgree;
169
170
            /* we do not support the case where multiple recipients
171
             * share the same KeyAgreeRecipientInfo and have multiple RecipientEncryptedKeys
172
             * in this case, we would need to walk all the recipientInfos, take the
173
             * ones that do KeyAgreement algorithms and join them, algorithm by algorithm
174
             * Then, we'd generate ONE ukm and OriginatorIdentifierOrKey */
175
176
            /* only epheremal-static Diffie-Hellman is supported for now
177
             * this is the only form of key agreement that provides potential anonymity
178
             * of the sender, plus we do not have to include certs in the message */
179
180
            /* force single recipientEncryptedKey for now */
181
0
            if ((rek = NSS_CMSRecipientEncryptedKey_Create(poolp)) == NULL) {
182
0
                rv = SECFailure;
183
0
                break;
184
0
            }
185
186
            /* hardcoded IssuerSN choice for now */
187
0
            rek->recipientIdentifier.identifierType = NSSCMSKeyAgreeRecipientID_IssuerSN;
188
0
            if ((rek->recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL) {
189
0
                rv = SECFailure;
190
0
                break;
191
0
            }
192
193
0
            oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey);
194
195
            /* see RFC2630 12.3.1.1 */
196
0
            oiok->identifierType = NSSCMSOriginatorIDOrKey_OriginatorPublicKey;
197
198
0
            rv = NSS_CMSArray_Add(poolp, (void ***)&ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys,
199
0
                                  (void *)rek);
200
201
0
            break;
202
0
        default:
203
            /* other algorithms not supported yet */
204
            /* NOTE that we do not support any KEK algorithm */
205
0
            PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
206
0
            rv = SECFailure;
207
0
            break;
208
0
    }
209
210
0
    if (rv == SECFailure)
211
0
        goto loser;
212
213
    /* set version */
214
0
    switch (ri->recipientInfoType) {
215
0
        case NSSCMSRecipientInfoID_KeyTrans:
216
0
            if (ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType == NSSCMSRecipientID_IssuerSN)
217
0
                version = NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_ISSUERSN;
218
0
            else
219
0
                version = NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_SUBJKEY;
220
0
            dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyTransRecipientInfo.version), version);
221
0
            if (dummy == NULL)
222
0
                goto loser;
223
0
            break;
224
0
        case NSSCMSRecipientInfoID_KeyAgree:
225
0
            dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyAgreeRecipientInfo.version),
226
0
                                          NSS_CMS_KEYAGREE_RECIPIENT_INFO_VERSION);
227
0
            if (dummy == NULL)
228
0
                goto loser;
229
0
            break;
230
0
        case NSSCMSRecipientInfoID_KEK:
231
            /* NOTE: this cannot happen as long as we do not support any KEK algorithm */
232
0
            dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.kekRecipientInfo.version),
233
0
                                          NSS_CMS_KEK_RECIPIENT_INFO_VERSION);
234
0
            if (dummy == NULL)
235
0
                goto loser;
236
0
            break;
237
0
    }
238
239
0
done:
240
0
    PORT_ArenaUnmark(poolp, mark);
241
0
    if (freeSpki)
242
0
        SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
243
0
    return ri;
244
245
0
loser:
246
0
    if (ri && ri->cert) {
247
0
        CERT_DestroyCertificate(ri->cert);
248
0
    }
249
0
    if (freeSpki) {
250
0
        SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
251
0
    }
252
0
    PORT_ArenaRelease(poolp, mark);
253
0
    if (cmsg->contentInfo.contentTypeTag == &fakeContent) {
254
0
        NSS_CMSMessage_Destroy(cmsg);
255
0
    }
256
0
    return NULL;
257
0
}
258
259
/*
260
 * NSS_CMSRecipient_IsSupported - checks for a support certificate
261
 *
262
 * Use this function to confirm that the given certificate will be
263
 * accepted by NSS_CMSRecipientInfo_Create, which means that the
264
 * certificate can be used with a supported encryption algorithm.
265
 */
266
PRBool
267
NSS_CMSRecipient_IsSupported(CERTCertificate *cert)
268
0
{
269
0
    CERTSubjectPublicKeyInfo *spki = &(cert->subjectPublicKeyInfo);
270
0
    SECOidTag certalgtag = SECOID_GetAlgorithmTag(&(spki->algorithm));
271
272
0
    switch (certalgtag) {
273
0
        case SEC_OID_PKCS1_RSA_ENCRYPTION:
274
0
        case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
275
0
            return PR_TRUE;
276
0
        default:
277
0
            return PR_FALSE;
278
0
    }
279
0
}
280
281
/*
282
 * NSS_CMSRecipientInfo_Create - create a recipientinfo
283
 *
284
 * we currently do not create KeyAgreement recipientinfos with multiple
285
 * recipientEncryptedKeys the certificate is supposed to have been
286
 * verified by the caller
287
 */
288
NSSCMSRecipientInfo *
289
NSS_CMSRecipientInfo_Create(NSSCMSMessage *cmsg, CERTCertificate *cert)
290
0
{
291
0
    return nss_cmsrecipientinfo_create(cmsg, NSSCMSRecipientID_IssuerSN, cert,
292
0
                                       NULL, NULL, NULL, NULL);
293
0
}
294
295
NSSCMSRecipientInfo *
296
NSS_CMSRecipientInfo_CreateNew(void *pwfn_arg)
297
0
{
298
0
    return nss_cmsrecipientinfo_create(NULL, NSSCMSRecipientID_BrandNew, NULL,
299
0
                                       NULL, NULL, pwfn_arg, NULL);
300
0
}
301
302
NSSCMSRecipientInfo *
303
NSS_CMSRecipientInfo_CreateFromDER(SECItem *input, void *pwfn_arg)
304
0
{
305
0
    return nss_cmsrecipientinfo_create(NULL, NSSCMSRecipientID_BrandNew, NULL,
306
0
                                       NULL, NULL, pwfn_arg, input);
307
0
}
308
309
NSSCMSRecipientInfo *
310
NSS_CMSRecipientInfo_CreateWithSubjKeyID(NSSCMSMessage *cmsg,
311
                                         SECItem *subjKeyID,
312
                                         SECKEYPublicKey *pubKey)
313
0
{
314
0
    return nss_cmsrecipientinfo_create(cmsg, NSSCMSRecipientID_SubjectKeyID,
315
0
                                       NULL, pubKey, subjKeyID, NULL, NULL);
316
0
}
317
318
NSSCMSRecipientInfo *
319
NSS_CMSRecipientInfo_CreateWithSubjKeyIDFromCert(NSSCMSMessage *cmsg,
320
                                                 CERTCertificate *cert)
321
0
{
322
0
    SECKEYPublicKey *pubKey = NULL;
323
0
    SECItem subjKeyID = { siBuffer, NULL, 0 };
324
0
    NSSCMSRecipientInfo *retVal = NULL;
325
326
0
    if (!cmsg || !cert) {
327
0
        return NULL;
328
0
    }
329
0
    pubKey = CERT_ExtractPublicKey(cert);
330
0
    if (!pubKey) {
331
0
        goto done;
332
0
    }
333
0
    if (CERT_FindSubjectKeyIDExtension(cert, &subjKeyID) != SECSuccess ||
334
0
        subjKeyID.data == NULL) {
335
0
        goto done;
336
0
    }
337
0
    retVal = NSS_CMSRecipientInfo_CreateWithSubjKeyID(cmsg, &subjKeyID, pubKey);
338
0
done:
339
0
    if (pubKey)
340
0
        SECKEY_DestroyPublicKey(pubKey);
341
342
0
    if (subjKeyID.data)
343
0
        SECITEM_FreeItem(&subjKeyID, PR_FALSE);
344
345
0
    return retVal;
346
0
}
347
348
void
349
NSS_CMSRecipientInfo_Destroy(NSSCMSRecipientInfo *ri)
350
6.23k
{
351
6.23k
    if (!ri) {
352
0
        return;
353
0
    }
354
    /* version was allocated on the pool, so no need to destroy it */
355
    /* issuerAndSN was allocated on the pool, so no need to destroy it */
356
6.23k
    if (ri->cert != NULL)
357
0
        CERT_DestroyCertificate(ri->cert);
358
359
6.23k
    if (nss_cmsrecipientinfo_usessubjectkeyid(ri)) {
360
2.61k
        NSSCMSKeyTransRecipientInfoEx *extra;
361
2.61k
        extra = &ri->ri.keyTransRecipientInfoEx;
362
2.61k
        if (extra->pubKey)
363
0
            SECKEY_DestroyPublicKey(extra->pubKey);
364
2.61k
    }
365
6.23k
    if (ri->cmsg && ri->cmsg->contentInfo.contentTypeTag == &fakeContent) {
366
0
        NSS_CMSMessage_Destroy(ri->cmsg);
367
0
    }
368
369
    /* we're done. */
370
6.23k
}
371
372
int
373
NSS_CMSRecipientInfo_GetVersion(NSSCMSRecipientInfo *ri)
374
0
{
375
0
    unsigned long version;
376
0
    SECItem *versionitem = NULL;
377
378
0
    switch (ri->recipientInfoType) {
379
0
        case NSSCMSRecipientInfoID_KeyTrans:
380
            /* ignore subIndex */
381
0
            versionitem = &(ri->ri.keyTransRecipientInfo.version);
382
0
            break;
383
0
        case NSSCMSRecipientInfoID_KEK:
384
            /* ignore subIndex */
385
0
            versionitem = &(ri->ri.kekRecipientInfo.version);
386
0
            break;
387
0
        case NSSCMSRecipientInfoID_KeyAgree:
388
0
            versionitem = &(ri->ri.keyAgreeRecipientInfo.version);
389
0
            break;
390
0
    }
391
392
0
    PORT_Assert(versionitem);
393
0
    if (versionitem == NULL)
394
0
        return 0;
395
396
    /* always take apart the SECItem */
397
0
    if (SEC_ASN1DecodeInteger(versionitem, &version) != SECSuccess)
398
0
        return 0;
399
0
    else
400
0
        return (int)version;
401
0
}
402
403
SECItem *
404
NSS_CMSRecipientInfo_GetEncryptedKey(NSSCMSRecipientInfo *ri, int subIndex)
405
0
{
406
0
    SECItem *enckey = NULL;
407
408
0
    switch (ri->recipientInfoType) {
409
0
        case NSSCMSRecipientInfoID_KeyTrans:
410
            /* ignore subIndex */
411
0
            enckey = &(ri->ri.keyTransRecipientInfo.encKey);
412
0
            break;
413
0
        case NSSCMSRecipientInfoID_KEK:
414
            /* ignore subIndex */
415
0
            enckey = &(ri->ri.kekRecipientInfo.encKey);
416
0
            break;
417
0
        case NSSCMSRecipientInfoID_KeyAgree:
418
0
            enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey);
419
0
            break;
420
0
    }
421
0
    return enckey;
422
0
}
423
424
SECOidTag
425
NSS_CMSRecipientInfo_GetKeyEncryptionAlgorithmTag(NSSCMSRecipientInfo *ri)
426
0
{
427
0
    SECOidTag encalgtag = SEC_OID_UNKNOWN; /* an invalid encryption alg */
428
429
0
    switch (ri->recipientInfoType) {
430
0
        case NSSCMSRecipientInfoID_KeyTrans:
431
0
            encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyTransRecipientInfo.keyEncAlg));
432
0
            break;
433
0
        case NSSCMSRecipientInfoID_KeyAgree:
434
0
            encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg));
435
0
            break;
436
0
        case NSSCMSRecipientInfoID_KEK:
437
0
            encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.kekRecipientInfo.keyEncAlg));
438
0
            break;
439
0
    }
440
0
    return encalgtag;
441
0
}
442
443
SECStatus
444
NSS_CMSRecipientInfo_WrapBulkKey(NSSCMSRecipientInfo *ri, PK11SymKey *bulkkey,
445
                                 SECOidTag bulkalgtag)
446
0
{
447
0
    CERTCertificate *cert;
448
0
    SECOidTag certalgtag;
449
0
    SECStatus rv = SECSuccess;
450
0
    NSSCMSRecipientEncryptedKey *rek;
451
0
    NSSCMSOriginatorIdentifierOrKey *oiok;
452
0
    CERTSubjectPublicKeyInfo *spki, *freeSpki = NULL;
453
0
    PLArenaPool *poolp;
454
0
    NSSCMSKeyTransRecipientInfoEx *extra = NULL;
455
0
    PRBool usesSubjKeyID;
456
0
    void *wincx = NULL;
457
458
0
    poolp = ri->cmsg->poolp;
459
0
    cert = ri->cert;
460
0
    usesSubjKeyID = nss_cmsrecipientinfo_usessubjectkeyid(ri);
461
0
    if (cert) {
462
0
        spki = &cert->subjectPublicKeyInfo;
463
0
    } else if (usesSubjKeyID) {
464
0
        extra = &ri->ri.keyTransRecipientInfoEx;
465
        /* sanity check */
466
0
        PORT_Assert(extra->pubKey);
467
0
        if (!extra->pubKey) {
468
0
            PORT_SetError(SEC_ERROR_INVALID_ARGS);
469
0
            return SECFailure;
470
0
        }
471
0
        spki = freeSpki = SECKEY_CreateSubjectPublicKeyInfo(extra->pubKey);
472
0
    } else {
473
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
474
0
        return SECFailure;
475
0
    }
476
477
    /* XXX set ri->recipientInfoType to the proper value here */
478
    /* or should we look if it's been set already ? */
479
480
0
    certalgtag = SECOID_GetAlgorithmTag(&spki->algorithm);
481
0
    if (!NSS_SMIMEUtil_KeyEncodingAllowed(&spki->algorithm, cert, extra ? extra->pubKey : NULL)) {
482
0
        PORT_SetError(SEC_ERROR_BAD_EXPORT_ALGORITHM);
483
0
        rv = SECFailure;
484
0
        goto loser;
485
0
    }
486
0
    switch (certalgtag) {
487
0
        case SEC_OID_PKCS1_RSA_ENCRYPTION:
488
            /* wrap the symkey */
489
0
            if (cert) {
490
0
                rv = NSS_CMSUtil_EncryptSymKey_RSA(poolp, cert, bulkkey,
491
0
                                                   &ri->ri.keyTransRecipientInfo.encKey);
492
0
                if (rv != SECSuccess)
493
0
                    break;
494
0
            } else if (usesSubjKeyID) {
495
0
                PORT_Assert(extra != NULL);
496
0
                rv = NSS_CMSUtil_EncryptSymKey_RSAPubKey(poolp, extra->pubKey,
497
0
                                                         bulkkey, &ri->ri.keyTransRecipientInfo.encKey);
498
0
                if (rv != SECSuccess)
499
0
                    break;
500
0
            }
501
502
0
            rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, NULL);
503
0
            break;
504
0
        case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
505
0
            rek = ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[0];
506
0
            if (rek == NULL) {
507
0
                rv = SECFailure;
508
0
                break;
509
0
            }
510
511
0
            oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey);
512
0
            PORT_Assert(oiok->identifierType == NSSCMSOriginatorIDOrKey_OriginatorPublicKey);
513
514
            /* see RFC2630 12.3.1.1 */
515
0
            if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier,
516
0
                                      certalgtag, NULL) != SECSuccess) {
517
0
                rv = SECFailure;
518
0
                break;
519
0
            }
520
521
            /* this will generate a key pair, compute the shared secret, */
522
            /* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */
523
            /* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */
524
0
            switch (certalgtag) {
525
0
                case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
526
0
                    if (ri->cmsg) {
527
0
                        wincx = ri->cmsg->pwfn_arg;
528
0
                    } else {
529
0
                        wincx = PK11_GetWindow(bulkkey);
530
0
                    }
531
0
                    rv = NSS_CMSUtil_EncryptSymKey_ESECDH(poolp, cert, bulkkey,
532
0
                                                          &rek->encKey,
533
0
                                                          PR_TRUE,
534
0
                                                          &ri->ri.keyAgreeRecipientInfo.ukm,
535
0
                                                          &ri->ri.keyAgreeRecipientInfo.keyEncAlg,
536
0
                                                          &oiok->id.originatorPublicKey.publicKey,
537
0
                                                          wincx);
538
0
                    break;
539
540
0
                default:
541
                    /* Not reached. Added to silence enum warnings. */
542
0
                    PORT_Assert(0);
543
0
                    break;
544
0
            }
545
0
            break;
546
0
        default:
547
            /* other algorithms not supported yet */
548
            /* NOTE that we do not support any KEK algorithm */
549
0
            PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
550
0
            rv = SECFailure;
551
0
    }
552
0
loser:
553
0
    if (freeSpki)
554
0
        SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
555
556
0
    return rv;
557
0
}
558
559
PK11SymKey *
560
NSS_CMSRecipientInfo_UnwrapBulkKey(NSSCMSRecipientInfo *ri, int subIndex,
561
                                   CERTCertificate *cert, SECKEYPrivateKey *privkey, SECOidTag bulkalgtag)
562
0
{
563
0
    PK11SymKey *bulkkey = NULL;
564
0
    SECAlgorithmID *algid;
565
0
    SECOidTag encalgtag;
566
0
    SECItem *enckey = NULL, *ukm = NULL, *parameters = NULL;
567
0
    NSSCMSOriginatorIdentifierOrKey *oiok = NULL;
568
0
    int error;
569
0
    void *wincx = NULL;
570
571
0
    ri->cert = CERT_DupCertificate(cert);
572
    /* mark the recipientInfo so we can find it later */
573
574
0
    switch (ri->recipientInfoType) {
575
0
        case NSSCMSRecipientInfoID_KeyTrans:
576
0
            algid = &(ri->ri.keyTransRecipientInfo.keyEncAlg);
577
0
            parameters = &(ri->ri.keyTransRecipientInfo.keyEncAlg.parameters);
578
0
            enckey = &(ri->ri.keyTransRecipientInfo.encKey); /* ignore subIndex */
579
0
            break;
580
0
        case NSSCMSRecipientInfoID_KeyAgree:
581
0
            algid = &(ri->ri.keyAgreeRecipientInfo.keyEncAlg);
582
0
            parameters = &(ri->ri.keyAgreeRecipientInfo.keyEncAlg.parameters);
583
0
            enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey);
584
0
            oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey);
585
0
            ukm = &(ri->ri.keyAgreeRecipientInfo.ukm);
586
0
            break;
587
0
        case NSSCMSRecipientInfoID_KEK:
588
0
            algid = &(ri->ri.kekRecipientInfo.keyEncAlg);
589
0
            parameters = &(ri->ri.kekRecipientInfo.keyEncAlg.parameters);
590
0
            enckey = &(ri->ri.kekRecipientInfo.encKey);
591
            /* not supported yet */
592
0
        default:
593
0
            error = SEC_ERROR_UNSUPPORTED_KEYALG;
594
0
            goto loser;
595
0
            break;
596
0
    }
597
0
    if (!NSS_SMIMEUtil_KeyDecodingAllowed(algid, privkey)) {
598
0
        error = SEC_ERROR_BAD_EXPORT_ALGORITHM;
599
0
        goto loser;
600
0
    }
601
0
    encalgtag = SECOID_GetAlgorithmTag(algid);
602
0
    switch (encalgtag) {
603
0
        case SEC_OID_PKCS1_RSA_ENCRYPTION:
604
            /* RSA encryption algorithm: */
605
0
            if (ri->recipientInfoType != NSSCMSRecipientInfoID_KeyTrans) {
606
0
                error = SEC_ERROR_UNSUPPORTED_KEYALG;
607
0
                goto loser;
608
0
            }
609
            /* get the symmetric (bulk) key by unwrapping it using our private key */
610
0
            bulkkey = NSS_CMSUtil_DecryptSymKey_RSA(privkey, enckey, bulkalgtag);
611
0
            break;
612
0
        case SEC_OID_PKCS1_RSA_OAEP_ENCRYPTION:
613
            /* RSA OAEP encryption algorithm: */
614
0
            if (ri->recipientInfoType != NSSCMSRecipientInfoID_KeyTrans) {
615
0
                error = SEC_ERROR_UNSUPPORTED_KEYALG;
616
0
                goto loser;
617
0
            }
618
            /* get the symmetric (bulk) key by unwrapping it using our private key */
619
0
            bulkkey = NSS_CMSUtil_DecryptSymKey_RSA_OAEP(privkey, parameters, enckey,
620
0
                                                         bulkalgtag);
621
0
            break;
622
0
        case SEC_OID_DHSINGLEPASS_STDDH_SHA1KDF_SCHEME:
623
0
        case SEC_OID_DHSINGLEPASS_STDDH_SHA224KDF_SCHEME:
624
0
        case SEC_OID_DHSINGLEPASS_STDDH_SHA256KDF_SCHEME:
625
0
        case SEC_OID_DHSINGLEPASS_STDDH_SHA384KDF_SCHEME:
626
0
        case SEC_OID_DHSINGLEPASS_STDDH_SHA512KDF_SCHEME:
627
0
        case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA1KDF_SCHEME:
628
0
        case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA224KDF_SCHEME:
629
0
        case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA256KDF_SCHEME:
630
0
        case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA384KDF_SCHEME:
631
0
        case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA512KDF_SCHEME:
632
0
            if (ri->recipientInfoType != NSSCMSRecipientInfoID_KeyAgree) {
633
0
                error = SEC_ERROR_UNSUPPORTED_KEYALG;
634
0
                goto loser;
635
0
            }
636
0
            if (ri->cmsg) {
637
0
                wincx = ri->cmsg->pwfn_arg;
638
0
            }
639
0
            bulkkey = NSS_CMSUtil_DecryptSymKey_ECDH(privkey, enckey, algid,
640
0
                                                     bulkalgtag, ukm, oiok, wincx);
641
0
            break;
642
0
        default:
643
0
            error = SEC_ERROR_UNSUPPORTED_KEYALG;
644
0
            goto loser;
645
0
    }
646
    /* XXXX continue here */
647
0
    return bulkkey;
648
649
0
loser:
650
0
    PORT_SetError(error);
651
0
    return NULL;
652
0
}
653
654
SECStatus
655
NSS_CMSRecipientInfo_GetCertAndKey(NSSCMSRecipientInfo *ri,
656
                                   CERTCertificate **retcert,
657
                                   SECKEYPrivateKey **retkey)
658
0
{
659
0
    CERTCertificate *cert = NULL;
660
0
    NSSCMSRecipient **recipients = NULL;
661
0
    NSSCMSRecipientInfo *recipientInfos[2];
662
0
    SECStatus rv = SECSuccess;
663
0
    SECKEYPrivateKey *key = NULL;
664
665
0
    if (!ri)
666
0
        return SECFailure;
667
668
0
    if (!retcert && !retkey) {
669
        /* nothing requested, nothing found, success */
670
0
        return SECSuccess;
671
0
    }
672
673
0
    if (retcert) {
674
0
        *retcert = NULL;
675
0
    }
676
0
    if (retkey) {
677
0
        *retkey = NULL;
678
0
    }
679
680
0
    if (ri->cert) {
681
0
        cert = CERT_DupCertificate(ri->cert);
682
0
        if (!cert) {
683
0
            rv = SECFailure;
684
0
        }
685
0
    }
686
0
    if (SECSuccess == rv && !cert) {
687
        /* we don't have the cert, we have to look for it */
688
        /* first build an NSS_CMSRecipient */
689
0
        recipientInfos[0] = ri;
690
0
        recipientInfos[1] = NULL;
691
692
0
        recipients = nss_cms_recipient_list_create(recipientInfos);
693
0
        if (recipients) {
694
            /* now look for the cert and key */
695
0
            if (0 == PK11_FindCertAndKeyByRecipientListNew(recipients,
696
0
                                                           ri->cmsg->pwfn_arg)) {
697
0
                cert = CERT_DupCertificate(recipients[0]->cert);
698
0
                key = SECKEY_CopyPrivateKey(recipients[0]->privkey);
699
0
            } else {
700
0
                rv = SECFailure;
701
0
            }
702
703
0
            nss_cms_recipient_list_destroy(recipients);
704
0
        } else {
705
0
            rv = SECFailure;
706
0
        }
707
0
    } else if (SECSuccess == rv && cert && retkey) {
708
        /* we have the cert, we just need the key now */
709
0
        key = PK11_FindPrivateKeyFromCert(cert->slot, cert, ri->cmsg->pwfn_arg);
710
0
    }
711
0
    if (retcert) {
712
0
        *retcert = cert;
713
0
    } else {
714
0
        if (cert) {
715
0
            CERT_DestroyCertificate(cert);
716
0
        }
717
0
    }
718
0
    if (retkey) {
719
0
        *retkey = key;
720
0
    } else {
721
0
        if (key) {
722
0
            SECKEY_DestroyPrivateKey(key);
723
0
        }
724
0
    }
725
726
0
    return rv;
727
0
}
728
729
SECStatus
730
NSS_CMSRecipientInfo_Encode(PLArenaPool *poolp,
731
                            const NSSCMSRecipientInfo *src,
732
                            SECItem *returned)
733
0
{
734
0
    extern const SEC_ASN1Template NSSCMSRecipientInfoTemplate[];
735
0
    SECStatus rv = SECFailure;
736
0
    if (!src || !returned) {
737
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
738
0
    } else if (SEC_ASN1EncodeItem(poolp, returned, src,
739
0
                                  NSSCMSRecipientInfoTemplate)) {
740
0
        rv = SECSuccess;
741
0
    }
742
0
    return rv;
743
0
}