Coverage Report

Created: 2018-09-25 14:53

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