~ubuntu-branches/ubuntu/quantal/nss/quantal-updates

« back to all changes in this revision

Viewing changes to mozilla/security/nss/lib/smime/cmssiginfo.c

  • Committer: Package Import Robot
  • Author(s): Marc Deslauriers
  • Date: 2013-11-14 14:58:07 UTC
  • mfrom: (1.1.19)
  • Revision ID: package-import@ubuntu.com-20131114145807-vj6v4erz8xj6kwz3
Tags: 3.15.3-0ubuntu0.12.10.1
* SECURITY UPDATE: New upstream release to fix multiple security issues
  and add TLSv1.2 support.
  - CVE-2013-1739
  - CVE-2013-1741
  - CVE-2013-5605
  - CVE-2013-5606
* Adjusted packaging for 3.15.3:
  - debian/patches/*: refreshed.
  - debian/patches/lower-dhe-priority.patch: removed, no longer needed,
    was a workaround for an old version of firefox.
  - debian/libnss3.symbols: added new symbols.
  - debian/rules: updated for new source layout.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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 signerInfo methods.
7
 
 *
8
 
 * $Id: cmssiginfo.c,v 1.37 2012/04/25 14:50:09 gerv%gerv.net Exp $
9
 
 */
10
 
 
11
 
#include "cmslocal.h"
12
 
 
13
 
#include "cert.h"
14
 
#include "key.h"
15
 
#include "secasn1.h"
16
 
#include "secitem.h"
17
 
#include "secoid.h"
18
 
#include "pk11func.h"
19
 
#include "prtime.h"
20
 
#include "secerr.h"
21
 
#include "secder.h"
22
 
#include "cryptohi.h"
23
 
 
24
 
#include "smime.h"
25
 
 
26
 
/* =============================================================================
27
 
 * SIGNERINFO
28
 
 */
29
 
NSSCMSSignerInfo *
30
 
nss_cmssignerinfo_create(NSSCMSMessage *cmsg, NSSCMSSignerIDSelector type, 
31
 
        CERTCertificate *cert, SECItem *subjKeyID, SECKEYPublicKey *pubKey, 
32
 
        SECKEYPrivateKey *signingKey, SECOidTag digestalgtag);
33
 
 
34
 
NSSCMSSignerInfo *
35
 
NSS_CMSSignerInfo_CreateWithSubjKeyID(NSSCMSMessage *cmsg, SECItem *subjKeyID, 
36
 
        SECKEYPublicKey *pubKey, SECKEYPrivateKey *signingKey, SECOidTag digestalgtag)
37
 
{
38
 
    return nss_cmssignerinfo_create(cmsg, NSSCMSSignerID_SubjectKeyID, NULL, subjKeyID, pubKey, signingKey, digestalgtag); 
39
 
}
40
 
 
41
 
NSSCMSSignerInfo *
42
 
NSS_CMSSignerInfo_Create(NSSCMSMessage *cmsg, CERTCertificate *cert, SECOidTag digestalgtag)
43
 
{
44
 
    return nss_cmssignerinfo_create(cmsg, NSSCMSSignerID_IssuerSN, cert, NULL, NULL, NULL, digestalgtag); 
45
 
}
46
 
 
47
 
NSSCMSSignerInfo *
48
 
nss_cmssignerinfo_create(NSSCMSMessage *cmsg, NSSCMSSignerIDSelector type, 
49
 
        CERTCertificate *cert, SECItem *subjKeyID, SECKEYPublicKey *pubKey, 
50
 
        SECKEYPrivateKey *signingKey, SECOidTag digestalgtag)
51
 
{
52
 
    void *mark;
53
 
    NSSCMSSignerInfo *signerinfo;
54
 
    int version;
55
 
    PLArenaPool *poolp;
56
 
 
57
 
    poolp = cmsg->poolp;
58
 
 
59
 
    mark = PORT_ArenaMark(poolp);
60
 
 
61
 
    signerinfo = (NSSCMSSignerInfo *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSSignerInfo));
62
 
    if (signerinfo == NULL) {
63
 
        PORT_ArenaRelease(poolp, mark);
64
 
        return NULL;
65
 
    }
66
 
 
67
 
 
68
 
    signerinfo->cmsg = cmsg;
69
 
 
70
 
    switch(type) {
71
 
    case NSSCMSSignerID_IssuerSN:
72
 
        signerinfo->signerIdentifier.identifierType = NSSCMSSignerID_IssuerSN;
73
 
        if ((signerinfo->cert = CERT_DupCertificate(cert)) == NULL)
74
 
            goto loser;
75
 
        if ((signerinfo->signerIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL)
76
 
            goto loser;
77
 
        break;
78
 
    case NSSCMSSignerID_SubjectKeyID:
79
 
        signerinfo->signerIdentifier.identifierType = NSSCMSSignerID_SubjectKeyID;
80
 
        PORT_Assert(subjKeyID);
81
 
        if (!subjKeyID)
82
 
            goto loser;
83
 
 
84
 
        signerinfo->signerIdentifier.id.subjectKeyID = PORT_ArenaNew(poolp, SECItem);
85
 
        SECITEM_CopyItem(poolp, signerinfo->signerIdentifier.id.subjectKeyID,
86
 
                         subjKeyID);
87
 
        signerinfo->signingKey = SECKEY_CopyPrivateKey(signingKey);
88
 
        if (!signerinfo->signingKey)
89
 
            goto loser;
90
 
        signerinfo->pubKey = SECKEY_CopyPublicKey(pubKey);
91
 
        if (!signerinfo->pubKey)
92
 
            goto loser;
93
 
        break;
94
 
    default:
95
 
        goto loser;
96
 
    }
97
 
 
98
 
    /* set version right now */
99
 
    version = NSS_CMS_SIGNER_INFO_VERSION_ISSUERSN;
100
 
    /* RFC2630 5.3 "version is the syntax version number. If the .... " */
101
 
    if (signerinfo->signerIdentifier.identifierType == NSSCMSSignerID_SubjectKeyID)
102
 
        version = NSS_CMS_SIGNER_INFO_VERSION_SUBJKEY;
103
 
    (void)SEC_ASN1EncodeInteger(poolp, &(signerinfo->version), (long)version);
104
 
 
105
 
    if (SECOID_SetAlgorithmID(poolp, &signerinfo->digestAlg, digestalgtag, NULL) != SECSuccess)
106
 
        goto loser;
107
 
 
108
 
    PORT_ArenaUnmark(poolp, mark);
109
 
    return signerinfo;
110
 
 
111
 
loser:
112
 
    PORT_ArenaRelease(poolp, mark);
113
 
    return NULL;
114
 
}
115
 
 
116
 
/*
117
 
 * NSS_CMSSignerInfo_Destroy - destroy a SignerInfo data structure
118
 
 */
119
 
void
120
 
NSS_CMSSignerInfo_Destroy(NSSCMSSignerInfo *si)
121
 
{
122
 
    if (si->cert != NULL)
123
 
        CERT_DestroyCertificate(si->cert);
124
 
 
125
 
    if (si->certList != NULL) 
126
 
        CERT_DestroyCertificateList(si->certList);
127
 
 
128
 
    /* XXX storage ??? */
129
 
}
130
 
 
131
 
/*
132
 
 * NSS_CMSSignerInfo_Sign - sign something
133
 
 *
134
 
 */
135
 
SECStatus
136
 
NSS_CMSSignerInfo_Sign(NSSCMSSignerInfo *signerinfo, SECItem *digest, 
137
 
                       SECItem *contentType)
138
 
{
139
 
    CERTCertificate *cert;
140
 
    SECKEYPrivateKey *privkey = NULL;
141
 
    SECOidTag digestalgtag;
142
 
    SECOidTag pubkAlgTag;
143
 
    SECItem signature = { 0 };
144
 
    SECStatus rv;
145
 
    PLArenaPool *poolp, *tmppoolp = NULL;
146
 
    SECAlgorithmID *algID, freeAlgID;
147
 
    CERTSubjectPublicKeyInfo *spki;
148
 
 
149
 
    PORT_Assert (digest != NULL);
150
 
 
151
 
    poolp = signerinfo->cmsg->poolp;
152
 
 
153
 
    switch (signerinfo->signerIdentifier.identifierType) {
154
 
    case NSSCMSSignerID_IssuerSN:
155
 
        cert = signerinfo->cert;
156
 
 
157
 
        privkey = PK11_FindKeyByAnyCert(cert, signerinfo->cmsg->pwfn_arg);
158
 
        if (privkey == NULL)
159
 
            goto loser;
160
 
        algID = &cert->subjectPublicKeyInfo.algorithm;
161
 
        break;
162
 
    case NSSCMSSignerID_SubjectKeyID:
163
 
        privkey = signerinfo->signingKey;
164
 
        signerinfo->signingKey = NULL;
165
 
        spki = SECKEY_CreateSubjectPublicKeyInfo(signerinfo->pubKey);
166
 
        SECKEY_DestroyPublicKey(signerinfo->pubKey);
167
 
        signerinfo->pubKey = NULL;
168
 
        SECOID_CopyAlgorithmID(NULL, &freeAlgID, &spki->algorithm);
169
 
        SECKEY_DestroySubjectPublicKeyInfo(spki); 
170
 
        algID = &freeAlgID;
171
 
        break;
172
 
    default:
173
 
        goto loser;
174
 
    }
175
 
    digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo);
176
 
    /*
177
 
     * XXX I think there should be a cert-level interface for this,
178
 
     * so that I do not have to know about subjectPublicKeyInfo...
179
 
     */
180
 
    pubkAlgTag = SECOID_GetAlgorithmTag(algID);
181
 
    if (signerinfo->signerIdentifier.identifierType == NSSCMSSignerID_SubjectKeyID) {
182
 
      SECOID_DestroyAlgorithmID(&freeAlgID, PR_FALSE);
183
 
    }
184
 
 
185
 
    if (signerinfo->authAttr != NULL) {
186
 
        SECOidTag signAlgTag;
187
 
        SECItem encoded_attrs;
188
 
 
189
 
        /* find and fill in the message digest attribute. */
190
 
        rv = NSS_CMSAttributeArray_SetAttr(poolp, &(signerinfo->authAttr), 
191
 
                               SEC_OID_PKCS9_MESSAGE_DIGEST, digest, PR_FALSE);
192
 
        if (rv != SECSuccess)
193
 
            goto loser;
194
 
 
195
 
        if (contentType != NULL) {
196
 
            /* if the caller wants us to, find and fill in the content type attribute. */
197
 
            rv = NSS_CMSAttributeArray_SetAttr(poolp, &(signerinfo->authAttr), 
198
 
                            SEC_OID_PKCS9_CONTENT_TYPE, contentType, PR_FALSE);
199
 
            if (rv != SECSuccess)
200
 
                goto loser;
201
 
        }
202
 
 
203
 
        if ((tmppoolp = PORT_NewArena (1024)) == NULL) {
204
 
            PORT_SetError(SEC_ERROR_NO_MEMORY);
205
 
            goto loser;
206
 
        }
207
 
 
208
 
        /*
209
 
         * Before encoding, reorder the attributes so that when they
210
 
         * are encoded, they will be conforming DER, which is required
211
 
         * to have a specific order and that is what must be used for
212
 
         * the hash/signature.  We do this here, rather than building
213
 
         * it into EncodeAttributes, because we do not want to do
214
 
         * such reordering on incoming messages (which also uses
215
 
         * EncodeAttributes) or our old signatures (and other "broken"
216
 
         * implementations) will not verify.  So, we want to guarantee
217
 
         * that we send out good DER encodings of attributes, but not
218
 
         * to expect to receive them.
219
 
         */
220
 
        if (NSS_CMSAttributeArray_Reorder(signerinfo->authAttr) != SECSuccess)
221
 
            goto loser;
222
 
 
223
 
        encoded_attrs.data = NULL;
224
 
        encoded_attrs.len = 0;
225
 
        if (NSS_CMSAttributeArray_Encode(tmppoolp, &(signerinfo->authAttr), 
226
 
                        &encoded_attrs) == NULL)
227
 
            goto loser;
228
 
 
229
 
        signAlgTag = SEC_GetSignatureAlgorithmOidTag(privkey->keyType, 
230
 
                                                     digestalgtag);
231
 
        if (signAlgTag == SEC_OID_UNKNOWN) {
232
 
            PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
233
 
            goto loser;
234
 
        }
235
 
 
236
 
        rv = SEC_SignData(&signature, encoded_attrs.data, encoded_attrs.len, 
237
 
                          privkey, signAlgTag);
238
 
        PORT_FreeArena(tmppoolp, PR_FALSE); /* awkward memory management :-( */
239
 
        tmppoolp = 0;
240
 
    } else {
241
 
        rv = SGN_Digest(privkey, digestalgtag, &signature, digest);
242
 
    }
243
 
    SECKEY_DestroyPrivateKey(privkey);
244
 
    privkey = NULL;
245
 
 
246
 
    if (rv != SECSuccess)
247
 
        goto loser;
248
 
 
249
 
    if (SECITEM_CopyItem(poolp, &(signerinfo->encDigest), &signature) 
250
 
          != SECSuccess)
251
 
        goto loser;
252
 
 
253
 
    SECITEM_FreeItem(&signature, PR_FALSE);
254
 
 
255
 
    if (SECOID_SetAlgorithmID(poolp, &(signerinfo->digestEncAlg), pubkAlgTag, 
256
 
                              NULL) != SECSuccess)
257
 
        goto loser;
258
 
 
259
 
    return SECSuccess;
260
 
 
261
 
loser:
262
 
    if (signature.len != 0)
263
 
        SECITEM_FreeItem (&signature, PR_FALSE);
264
 
    if (privkey)
265
 
        SECKEY_DestroyPrivateKey(privkey);
266
 
    if (tmppoolp)
267
 
        PORT_FreeArena(tmppoolp, PR_FALSE);
268
 
    return SECFailure;
269
 
}
270
 
 
271
 
SECStatus
272
 
NSS_CMSSignerInfo_VerifyCertificate(NSSCMSSignerInfo *signerinfo, CERTCertDBHandle *certdb,
273
 
                            SECCertUsage certusage)
274
 
{
275
 
    CERTCertificate *cert;
276
 
    int64 stime;
277
 
 
278
 
    if ((cert = NSS_CMSSignerInfo_GetSigningCertificate(signerinfo, certdb)) == NULL) {
279
 
        signerinfo->verificationStatus = NSSCMSVS_SigningCertNotFound;
280
 
        return SECFailure;
281
 
    }
282
 
 
283
 
    /*
284
 
     * Get and convert the signing time; if available, it will be used
285
 
     * both on the cert verification and for importing the sender
286
 
     * email profile.
287
 
     */
288
 
    if (NSS_CMSSignerInfo_GetSigningTime (signerinfo, &stime) != SECSuccess)
289
 
        stime = PR_Now(); /* not found or conversion failed, so check against now */
290
 
    
291
 
    /*
292
 
     * XXX  This uses the signing time, if available.  Additionally, we
293
 
     * might want to, if there is no signing time, get the message time
294
 
     * from the mail header itself, and use that.  That would require
295
 
     * a change to our interface though, and for S/MIME callers to pass
296
 
     * in a time (and for non-S/MIME callers to pass in nothing, or
297
 
     * maybe make them pass in the current time, always?).
298
 
     */
299
 
    if (CERT_VerifyCert(certdb, cert, PR_TRUE, certusage, stime, 
300
 
                        signerinfo->cmsg->pwfn_arg, NULL) != SECSuccess) {
301
 
        signerinfo->verificationStatus = NSSCMSVS_SigningCertNotTrusted;
302
 
        return SECFailure;
303
 
    }
304
 
    return SECSuccess;
305
 
}
306
 
 
307
 
/*
308
 
 * NSS_CMSSignerInfo_Verify - verify the signature of a single SignerInfo
309
 
 *
310
 
 * Just verifies the signature. The assumption is that verification of 
311
 
 * the certificate is done already.
312
 
 */
313
 
SECStatus
314
 
NSS_CMSSignerInfo_Verify(NSSCMSSignerInfo *signerinfo, 
315
 
                         SECItem *digest,               /* may be NULL */
316
 
                         SECItem *contentType)          /* may be NULL */
317
 
{
318
 
    SECKEYPublicKey *publickey = NULL;
319
 
    NSSCMSAttribute *attr;
320
 
    SECItem encoded_attrs;
321
 
    CERTCertificate *cert;
322
 
    NSSCMSVerificationStatus vs = NSSCMSVS_Unverified;
323
 
    PLArenaPool *poolp;
324
 
    SECOidTag    digestalgtag;
325
 
    SECOidTag    pubkAlgTag;
326
 
 
327
 
    if (signerinfo == NULL)
328
 
        return SECFailure;
329
 
 
330
 
    /* NSS_CMSSignerInfo_GetSigningCertificate will fail if 2nd parm is NULL 
331
 
    ** and cert has not been verified 
332
 
    */
333
 
    cert = NSS_CMSSignerInfo_GetSigningCertificate(signerinfo, NULL);
334
 
    if (cert == NULL) {
335
 
        vs = NSSCMSVS_SigningCertNotFound;
336
 
        goto loser;
337
 
    }
338
 
 
339
 
    if ((publickey = CERT_ExtractPublicKey(cert)) == NULL) {
340
 
        vs = NSSCMSVS_ProcessingError;
341
 
        goto loser;
342
 
    }
343
 
 
344
 
    digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo);
345
 
    pubkAlgTag = SECOID_GetAlgorithmTag(&(signerinfo->digestEncAlg));
346
 
    if ((pubkAlgTag == SEC_OID_UNKNOWN) || (digestalgtag == SEC_OID_UNKNOWN)) {
347
 
        vs = NSSCMSVS_SignatureAlgorithmUnknown;
348
 
        goto loser;
349
 
    }
350
 
 
351
 
#ifndef NSS_ECC_MORE_THAN_SUITE_B
352
 
    if (pubkAlgTag == SEC_OID_ANSIX962_EC_PUBLIC_KEY) {
353
 
        vs = NSSCMSVS_SignatureAlgorithmUnknown;
354
 
        goto loser;
355
 
    }
356
 
#endif
357
 
 
358
 
    if (!NSS_CMSArray_IsEmpty((void **)signerinfo->authAttr)) {
359
 
        if (contentType) {
360
 
            /*
361
 
             * Check content type
362
 
             *
363
 
             * RFC2630 sez that if there are any authenticated attributes,
364
 
             * then there must be one for content type which matches the
365
 
             * content type of the content being signed, and there must
366
 
             * be one for message digest which matches our message digest.
367
 
             * So check these things first.
368
 
             */
369
 
            attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr,
370
 
                                        SEC_OID_PKCS9_CONTENT_TYPE, PR_TRUE);
371
 
            if (attr == NULL) {
372
 
                vs = NSSCMSVS_MalformedSignature;
373
 
                goto loser;
374
 
            }
375
 
                
376
 
            if (NSS_CMSAttribute_CompareValue(attr, contentType) == PR_FALSE) {
377
 
                vs = NSSCMSVS_MalformedSignature;
378
 
                goto loser;
379
 
            }
380
 
        }
381
 
 
382
 
        /*
383
 
         * Check digest
384
 
         */
385
 
        attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr, 
386
 
                                      SEC_OID_PKCS9_MESSAGE_DIGEST, PR_TRUE);
387
 
        if (attr == NULL) {
388
 
            vs = NSSCMSVS_MalformedSignature;
389
 
            goto loser;
390
 
        }
391
 
        if (!digest || 
392
 
            NSS_CMSAttribute_CompareValue(attr, digest) == PR_FALSE) {
393
 
            vs = NSSCMSVS_DigestMismatch;
394
 
            goto loser;
395
 
        }
396
 
 
397
 
        if ((poolp = PORT_NewArena (1024)) == NULL) {
398
 
            vs = NSSCMSVS_ProcessingError;
399
 
            goto loser;
400
 
        }
401
 
 
402
 
        /*
403
 
         * Check signature
404
 
         *
405
 
         * The signature is based on a digest of the DER-encoded authenticated
406
 
         * attributes.  So, first we encode and then we digest/verify.
407
 
         * we trust the decoder to have the attributes in the right (sorted) 
408
 
         * order
409
 
         */
410
 
        encoded_attrs.data = NULL;
411
 
        encoded_attrs.len = 0;
412
 
 
413
 
        if (NSS_CMSAttributeArray_Encode(poolp, &(signerinfo->authAttr), 
414
 
                                         &encoded_attrs) == NULL ||
415
 
                encoded_attrs.data == NULL || encoded_attrs.len == 0) {
416
 
            vs = NSSCMSVS_ProcessingError;
417
 
            goto loser;
418
 
        }
419
 
 
420
 
        vs = (VFY_VerifyDataDirect(encoded_attrs.data, encoded_attrs.len,
421
 
                publickey, &(signerinfo->encDigest), pubkAlgTag,
422
 
                digestalgtag, NULL, signerinfo->cmsg->pwfn_arg) != SECSuccess) 
423
 
                ? NSSCMSVS_BadSignature : NSSCMSVS_GoodSignature;
424
 
 
425
 
        PORT_FreeArena(poolp, PR_FALSE);  /* awkward memory management :-( */
426
 
 
427
 
    } else {
428
 
        SECItem *sig;
429
 
 
430
 
        /* No authenticated attributes. 
431
 
        ** The signature is based on the plain message digest. 
432
 
        */
433
 
        sig = &(signerinfo->encDigest);
434
 
        if (sig->len == 0)
435
 
            goto loser;
436
 
 
437
 
        vs = (!digest || 
438
 
              VFY_VerifyDigestDirect(digest, publickey, sig, pubkAlgTag,
439
 
                digestalgtag, signerinfo->cmsg->pwfn_arg) != SECSuccess) 
440
 
                ? NSSCMSVS_BadSignature : NSSCMSVS_GoodSignature;
441
 
    }
442
 
 
443
 
    if (vs == NSSCMSVS_BadSignature) {
444
 
        int error = PORT_GetError();
445
 
        /*
446
 
         * XXX Change the generic error into our specific one, because
447
 
         * in that case we get a better explanation out of the Security
448
 
         * Advisor.  This is really a bug in the PSM error strings (the
449
 
         * "generic" error has a lousy/wrong message associated with it
450
 
         * which assumes the signature verification was done for the
451
 
         * purposes of checking the issuer signature on a certificate)
452
 
         * but this is at least an easy workaround and/or in the
453
 
         * Security Advisor, which specifically checks for the error
454
 
         * SEC_ERROR_PKCS7_BAD_SIGNATURE and gives more explanation
455
 
         * in that case but does not similarly check for
456
 
         * SEC_ERROR_BAD_SIGNATURE.  It probably should, but then would
457
 
         * probably say the wrong thing in the case that it *was* the
458
 
         * certificate signature check that failed during the cert
459
 
         * verification done above.  Our error handling is really a mess.
460
 
         */
461
 
        if (error == SEC_ERROR_BAD_SIGNATURE)
462
 
            PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
463
 
        /*
464
 
         * map algorithm failures to NSSCMSVS values 
465
 
         */
466
 
        if ((error == SEC_ERROR_PKCS7_KEYALG_MISMATCH) ||
467
 
            (error == SEC_ERROR_INVALID_ALGORITHM)) {
468
 
            /* keep the same error code as 3.11 and before */
469
 
            PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
470
 
            vs = NSSCMSVS_SignatureAlgorithmUnsupported;
471
 
        }
472
 
    }
473
 
 
474
 
    if (publickey != NULL)
475
 
        SECKEY_DestroyPublicKey (publickey);
476
 
 
477
 
    signerinfo->verificationStatus = vs;
478
 
 
479
 
    return (vs == NSSCMSVS_GoodSignature) ? SECSuccess : SECFailure;
480
 
 
481
 
loser:
482
 
    if (publickey != NULL)
483
 
        SECKEY_DestroyPublicKey (publickey);
484
 
 
485
 
    signerinfo->verificationStatus = vs;
486
 
 
487
 
    PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
488
 
    return SECFailure;
489
 
}
490
 
 
491
 
NSSCMSVerificationStatus
492
 
NSS_CMSSignerInfo_GetVerificationStatus(NSSCMSSignerInfo *signerinfo)
493
 
{
494
 
    return signerinfo->verificationStatus;
495
 
}
496
 
 
497
 
SECOidData *
498
 
NSS_CMSSignerInfo_GetDigestAlg(NSSCMSSignerInfo *signerinfo)
499
 
{
500
 
    SECOidData *algdata;
501
 
    SECOidTag   algtag;
502
 
 
503
 
    algdata = SECOID_FindOID (&(signerinfo->digestAlg.algorithm));
504
 
    if (algdata == NULL) {
505
 
        return algdata;
506
 
    }
507
 
    /* Windows may have given us a signer algorithm oid instead of a digest 
508
 
     * algorithm oid. This call will map to a signer oid to a digest one, 
509
 
     * otherwise it leaves the oid alone and let the chips fall as they may
510
 
     * if it's not a digest oid.
511
 
     */
512
 
    algtag = NSS_CMSUtil_MapSignAlgs(algdata->offset);
513
 
    if (algtag != algdata->offset) {
514
 
        /* if the tags don't match, then we must have received a signer 
515
 
         * algorithID. Now we need to get the oid data for the digest
516
 
         * oid, which the rest of the code is expecting */
517
 
        algdata = SECOID_FindOIDByTag(algtag);
518
 
    }
519
 
 
520
 
    return algdata;
521
 
 
522
 
}
523
 
 
524
 
SECOidTag
525
 
NSS_CMSSignerInfo_GetDigestAlgTag(NSSCMSSignerInfo *signerinfo)
526
 
{
527
 
    SECOidData *algdata;
528
 
 
529
 
    if (!signerinfo) {
530
 
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
531
 
        return SEC_OID_UNKNOWN;
532
 
    }
533
 
 
534
 
    algdata = NSS_CMSSignerInfo_GetDigestAlg(signerinfo);
535
 
    if (algdata != NULL)
536
 
        return algdata->offset;
537
 
    else
538
 
        return SEC_OID_UNKNOWN;
539
 
}
540
 
 
541
 
CERTCertificateList *
542
 
NSS_CMSSignerInfo_GetCertList(NSSCMSSignerInfo *signerinfo)
543
 
{
544
 
    return signerinfo->certList;
545
 
}
546
 
 
547
 
int
548
 
NSS_CMSSignerInfo_GetVersion(NSSCMSSignerInfo *signerinfo)
549
 
{
550
 
    unsigned long version;
551
 
 
552
 
    /* always take apart the SECItem */
553
 
    if (SEC_ASN1DecodeInteger(&(signerinfo->version), &version) != SECSuccess)
554
 
        return 0;
555
 
    else
556
 
        return (int)version;
557
 
}
558
 
 
559
 
/*
560
 
 * NSS_CMSSignerInfo_GetSigningTime - return the signing time,
561
 
 *                                    in UTCTime or GeneralizedTime format,
562
 
 *                                    of a CMS signerInfo.
563
 
 *
564
 
 * sinfo - signerInfo data for this signer
565
 
 *
566
 
 * Returns a pointer to XXXX (what?)
567
 
 * A return value of NULL is an error.
568
 
 */
569
 
SECStatus
570
 
NSS_CMSSignerInfo_GetSigningTime(NSSCMSSignerInfo *sinfo, PRTime *stime)
571
 
{
572
 
    NSSCMSAttribute *attr;
573
 
    SECItem *value;
574
 
 
575
 
    if (sinfo == NULL)
576
 
        return SECFailure;
577
 
 
578
 
    if (sinfo->signingTime != 0) {
579
 
        *stime = sinfo->signingTime;    /* cached copy */
580
 
        return SECSuccess;
581
 
    }
582
 
 
583
 
    attr = NSS_CMSAttributeArray_FindAttrByOidTag(sinfo->authAttr, SEC_OID_PKCS9_SIGNING_TIME, PR_TRUE);
584
 
    /* XXXX multi-valued attributes NIH */
585
 
    if (attr == NULL || (value = NSS_CMSAttribute_GetValue(attr)) == NULL)
586
 
        return SECFailure;
587
 
    if (DER_DecodeTimeChoice(stime, value) != SECSuccess)
588
 
        return SECFailure;
589
 
    sinfo->signingTime = *stime;        /* make cached copy */
590
 
    return SECSuccess;
591
 
}
592
 
 
593
 
/*
594
 
 * Return the signing cert of a CMS signerInfo.
595
 
 *
596
 
 * the certs in the enclosing SignedData must have been imported already
597
 
 */
598
 
CERTCertificate *
599
 
NSS_CMSSignerInfo_GetSigningCertificate(NSSCMSSignerInfo *signerinfo, CERTCertDBHandle *certdb)
600
 
{
601
 
    CERTCertificate *cert;
602
 
    NSSCMSSignerIdentifier *sid;
603
 
 
604
 
    if (signerinfo->cert != NULL)
605
 
        return signerinfo->cert;
606
 
 
607
 
    /* no certdb, and cert hasn't been set yet? */
608
 
    if (certdb == NULL)
609
 
        return NULL;
610
 
 
611
 
    /*
612
 
     * This cert will also need to be freed, but since we save it
613
 
     * in signerinfo for later, we do not want to destroy it when
614
 
     * we leave this function -- we let the clean-up of the entire
615
 
     * cinfo structure later do the destroy of this cert.
616
 
     */
617
 
    sid = &signerinfo->signerIdentifier;
618
 
    switch (sid->identifierType) {
619
 
    case NSSCMSSignerID_IssuerSN:
620
 
        cert = CERT_FindCertByIssuerAndSN(certdb, sid->id.issuerAndSN);
621
 
        break;
622
 
    case NSSCMSSignerID_SubjectKeyID:
623
 
        cert = CERT_FindCertBySubjectKeyID(certdb, sid->id.subjectKeyID);
624
 
        break;
625
 
    default:
626
 
        cert = NULL;
627
 
        break;
628
 
    }
629
 
 
630
 
    /* cert can be NULL at that point */
631
 
    signerinfo->cert = cert;    /* earmark it */
632
 
 
633
 
    return cert;
634
 
}
635
 
 
636
 
/*
637
 
 * NSS_CMSSignerInfo_GetSignerCommonName - return the common name of the signer
638
 
 *
639
 
 * sinfo - signerInfo data for this signer
640
 
 *
641
 
 * Returns a pointer to allocated memory, which must be freed with PORT_Free.
642
 
 * A return value of NULL is an error.
643
 
 */
644
 
char *
645
 
NSS_CMSSignerInfo_GetSignerCommonName(NSSCMSSignerInfo *sinfo)
646
 
{
647
 
    CERTCertificate *signercert;
648
 
 
649
 
    /* will fail if cert is not verified */
650
 
    if ((signercert = NSS_CMSSignerInfo_GetSigningCertificate(sinfo, NULL)) == NULL)
651
 
        return NULL;
652
 
 
653
 
    return (CERT_GetCommonName(&signercert->subject));
654
 
}
655
 
 
656
 
/*
657
 
 * NSS_CMSSignerInfo_GetSignerEmailAddress - return the common name of the signer
658
 
 *
659
 
 * sinfo - signerInfo data for this signer
660
 
 *
661
 
 * Returns a pointer to allocated memory, which must be freed.
662
 
 * A return value of NULL is an error.
663
 
 */
664
 
char *
665
 
NSS_CMSSignerInfo_GetSignerEmailAddress(NSSCMSSignerInfo *sinfo)
666
 
{
667
 
    CERTCertificate *signercert;
668
 
 
669
 
    if ((signercert = NSS_CMSSignerInfo_GetSigningCertificate(sinfo, NULL)) == NULL)
670
 
        return NULL;
671
 
 
672
 
    if (!signercert->emailAddr || !signercert->emailAddr[0])
673
 
        return NULL;
674
 
 
675
 
    return (PORT_Strdup(signercert->emailAddr));
676
 
}
677
 
 
678
 
/*
679
 
 * NSS_CMSSignerInfo_AddAuthAttr - add an attribute to the
680
 
 * authenticated (i.e. signed) attributes of "signerinfo". 
681
 
 */
682
 
SECStatus
683
 
NSS_CMSSignerInfo_AddAuthAttr(NSSCMSSignerInfo *signerinfo, NSSCMSAttribute *attr)
684
 
{
685
 
    return NSS_CMSAttributeArray_AddAttr(signerinfo->cmsg->poolp, &(signerinfo->authAttr), attr);
686
 
}
687
 
 
688
 
/*
689
 
 * NSS_CMSSignerInfo_AddUnauthAttr - add an attribute to the
690
 
 * unauthenticated attributes of "signerinfo". 
691
 
 */
692
 
SECStatus
693
 
NSS_CMSSignerInfo_AddUnauthAttr(NSSCMSSignerInfo *signerinfo, NSSCMSAttribute *attr)
694
 
{
695
 
    return NSS_CMSAttributeArray_AddAttr(signerinfo->cmsg->poolp, &(signerinfo->unAuthAttr), attr);
696
 
}
697
 
 
698
 
/* 
699
 
 * NSS_CMSSignerInfo_AddSigningTime - add the signing time to the
700
 
 * authenticated (i.e. signed) attributes of "signerinfo". 
701
 
 *
702
 
 * This is expected to be included in outgoing signed
703
 
 * messages for email (S/MIME) but is likely useful in other situations.
704
 
 *
705
 
 * This should only be added once; a second call will do nothing.
706
 
 *
707
 
 * XXX This will probably just shove the current time into "signerinfo"
708
 
 * but it will not actually get signed until the entire item is
709
 
 * processed for encoding.  Is this (expected to be small) delay okay?
710
 
 */
711
 
SECStatus
712
 
NSS_CMSSignerInfo_AddSigningTime(NSSCMSSignerInfo *signerinfo, PRTime t)
713
 
{
714
 
    NSSCMSAttribute *attr;
715
 
    SECItem stime;
716
 
    void *mark;
717
 
    PLArenaPool *poolp;
718
 
 
719
 
    poolp = signerinfo->cmsg->poolp;
720
 
 
721
 
    mark = PORT_ArenaMark(poolp);
722
 
 
723
 
    /* create new signing time attribute */
724
 
    if (DER_EncodeTimeChoice(NULL, &stime, t) != SECSuccess)
725
 
        goto loser;
726
 
 
727
 
    if ((attr = NSS_CMSAttribute_Create(poolp, SEC_OID_PKCS9_SIGNING_TIME, &stime, PR_FALSE)) == NULL) {
728
 
        SECITEM_FreeItem (&stime, PR_FALSE);
729
 
        goto loser;
730
 
    }
731
 
 
732
 
    SECITEM_FreeItem (&stime, PR_FALSE);
733
 
 
734
 
    if (NSS_CMSSignerInfo_AddAuthAttr(signerinfo, attr) != SECSuccess)
735
 
        goto loser;
736
 
 
737
 
    PORT_ArenaUnmark (poolp, mark);
738
 
 
739
 
    return SECSuccess;
740
 
 
741
 
loser:
742
 
    PORT_ArenaRelease (poolp, mark);
743
 
    return SECFailure;
744
 
}
745
 
 
746
 
/* 
747
 
 * NSS_CMSSignerInfo_AddSMIMECaps - add a SMIMECapabilities attribute to the
748
 
 * authenticated (i.e. signed) attributes of "signerinfo". 
749
 
 *
750
 
 * This is expected to be included in outgoing signed
751
 
 * messages for email (S/MIME).
752
 
 */
753
 
SECStatus
754
 
NSS_CMSSignerInfo_AddSMIMECaps(NSSCMSSignerInfo *signerinfo)
755
 
{
756
 
    NSSCMSAttribute *attr;
757
 
    SECItem *smimecaps = NULL;
758
 
    void *mark;
759
 
    PLArenaPool *poolp;
760
 
 
761
 
    poolp = signerinfo->cmsg->poolp;
762
 
 
763
 
    mark = PORT_ArenaMark(poolp);
764
 
 
765
 
    smimecaps = SECITEM_AllocItem(poolp, NULL, 0);
766
 
    if (smimecaps == NULL)
767
 
        goto loser;
768
 
 
769
 
    /* create new signing time attribute */
770
 
    if (NSS_SMIMEUtil_CreateSMIMECapabilities(poolp, smimecaps) != SECSuccess)
771
 
        goto loser;
772
 
 
773
 
    if ((attr = NSS_CMSAttribute_Create(poolp, SEC_OID_PKCS9_SMIME_CAPABILITIES, smimecaps, PR_TRUE)) == NULL)
774
 
        goto loser;
775
 
 
776
 
    if (NSS_CMSSignerInfo_AddAuthAttr(signerinfo, attr) != SECSuccess)
777
 
        goto loser;
778
 
 
779
 
    PORT_ArenaUnmark (poolp, mark);
780
 
    return SECSuccess;
781
 
 
782
 
loser:
783
 
    PORT_ArenaRelease (poolp, mark);
784
 
    return SECFailure;
785
 
}
786
 
 
787
 
/* 
788
 
 * NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs - add a SMIMEEncryptionKeyPreferences attribute to the
789
 
 * authenticated (i.e. signed) attributes of "signerinfo". 
790
 
 *
791
 
 * This is expected to be included in outgoing signed messages for email (S/MIME).
792
 
 */
793
 
SECStatus
794
 
NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(NSSCMSSignerInfo *signerinfo, CERTCertificate *cert, CERTCertDBHandle *certdb)
795
 
{
796
 
    NSSCMSAttribute *attr;
797
 
    SECItem *smimeekp = NULL;
798
 
    void *mark;
799
 
    PLArenaPool *poolp;
800
 
 
801
 
    /* verify this cert for encryption */
802
 
    if (CERT_VerifyCert(certdb, cert, PR_TRUE, certUsageEmailRecipient, PR_Now(), signerinfo->cmsg->pwfn_arg, NULL) != SECSuccess) {
803
 
        return SECFailure;
804
 
    }
805
 
 
806
 
    poolp = signerinfo->cmsg->poolp;
807
 
    mark = PORT_ArenaMark(poolp);
808
 
 
809
 
    smimeekp = SECITEM_AllocItem(poolp, NULL, 0);
810
 
    if (smimeekp == NULL)
811
 
        goto loser;
812
 
 
813
 
    /* create new signing time attribute */
814
 
    if (NSS_SMIMEUtil_CreateSMIMEEncKeyPrefs(poolp, smimeekp, cert) != SECSuccess)
815
 
        goto loser;
816
 
 
817
 
    if ((attr = NSS_CMSAttribute_Create(poolp, SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE, smimeekp, PR_TRUE)) == NULL)
818
 
        goto loser;
819
 
 
820
 
    if (NSS_CMSSignerInfo_AddAuthAttr(signerinfo, attr) != SECSuccess)
821
 
        goto loser;
822
 
 
823
 
    PORT_ArenaUnmark (poolp, mark);
824
 
    return SECSuccess;
825
 
 
826
 
loser:
827
 
    PORT_ArenaRelease (poolp, mark);
828
 
    return SECFailure;
829
 
}
830
 
 
831
 
/* 
832
 
 * NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs - add a SMIMEEncryptionKeyPreferences attribute to the
833
 
 * authenticated (i.e. signed) attributes of "signerinfo", using the OID preferred by Microsoft.
834
 
 *
835
 
 * This is expected to be included in outgoing signed messages for email (S/MIME),
836
 
 * if compatibility with Microsoft mail clients is wanted.
837
 
 */
838
 
SECStatus
839
 
NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(NSSCMSSignerInfo *signerinfo, CERTCertificate *cert, CERTCertDBHandle *certdb)
840
 
{
841
 
    NSSCMSAttribute *attr;
842
 
    SECItem *smimeekp = NULL;
843
 
    void *mark;
844
 
    PLArenaPool *poolp;
845
 
 
846
 
    /* verify this cert for encryption */
847
 
    if (CERT_VerifyCert(certdb, cert, PR_TRUE, certUsageEmailRecipient, PR_Now(), signerinfo->cmsg->pwfn_arg, NULL) != SECSuccess) {
848
 
        return SECFailure;
849
 
    }
850
 
 
851
 
    poolp = signerinfo->cmsg->poolp;
852
 
    mark = PORT_ArenaMark(poolp);
853
 
 
854
 
    smimeekp = SECITEM_AllocItem(poolp, NULL, 0);
855
 
    if (smimeekp == NULL)
856
 
        goto loser;
857
 
 
858
 
    /* create new signing time attribute */
859
 
    if (NSS_SMIMEUtil_CreateMSSMIMEEncKeyPrefs(poolp, smimeekp, cert) != SECSuccess)
860
 
        goto loser;
861
 
 
862
 
    if ((attr = NSS_CMSAttribute_Create(poolp, SEC_OID_MS_SMIME_ENCRYPTION_KEY_PREFERENCE, smimeekp, PR_TRUE)) == NULL)
863
 
        goto loser;
864
 
 
865
 
    if (NSS_CMSSignerInfo_AddAuthAttr(signerinfo, attr) != SECSuccess)
866
 
        goto loser;
867
 
 
868
 
    PORT_ArenaUnmark (poolp, mark);
869
 
    return SECSuccess;
870
 
 
871
 
loser:
872
 
    PORT_ArenaRelease (poolp, mark);
873
 
    return SECFailure;
874
 
}
875
 
 
876
 
/* 
877
 
 * NSS_CMSSignerInfo_AddCounterSignature - countersign a signerinfo
878
 
 *
879
 
 * 1. digest the DER-encoded signature value of the original signerinfo
880
 
 * 2. create new signerinfo with correct version, sid, digestAlg
881
 
 * 3. add message-digest authAttr, but NO content-type
882
 
 * 4. sign the authAttrs
883
 
 * 5. DER-encode the new signerInfo
884
 
 * 6. add the whole thing to original signerInfo's unAuthAttrs
885
 
 *    as a SEC_OID_PKCS9_COUNTER_SIGNATURE attribute
886
 
 *
887
 
 * XXXX give back the new signerinfo?
888
 
 */
889
 
SECStatus
890
 
NSS_CMSSignerInfo_AddCounterSignature(NSSCMSSignerInfo *signerinfo,
891
 
                                    SECOidTag digestalg, CERTCertificate signingcert)
892
 
{
893
 
    /* XXXX TBD XXXX */
894
 
    return SECFailure;
895
 
}
896
 
 
897
 
/*
898
 
 * XXXX the following needs to be done in the S/MIME layer code
899
 
 * after signature of a signerinfo is verified
900
 
 */
901
 
SECStatus
902
 
NSS_SMIMESignerInfo_SaveSMIMEProfile(NSSCMSSignerInfo *signerinfo)
903
 
{
904
 
    CERTCertificate *cert = NULL;
905
 
    SECItem *profile = NULL;
906
 
    NSSCMSAttribute *attr;
907
 
    SECItem *stime = NULL;
908
 
    SECItem *ekp;
909
 
    CERTCertDBHandle *certdb;
910
 
    int save_error;
911
 
    SECStatus rv;
912
 
    PRBool must_free_cert = PR_FALSE;
913
 
 
914
 
    certdb = CERT_GetDefaultCertDB();
915
 
 
916
 
    /* sanity check - see if verification status is ok (unverified does not count...) */
917
 
    if (signerinfo->verificationStatus != NSSCMSVS_GoodSignature)
918
 
        return SECFailure;
919
 
 
920
 
    /* find preferred encryption cert */
921
 
    if (!NSS_CMSArray_IsEmpty((void **)signerinfo->authAttr) &&
922
 
        (attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr,
923
 
                               SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE, PR_TRUE)) != NULL)
924
 
    { /* we have a SMIME_ENCRYPTION_KEY_PREFERENCE attribute! */
925
 
        ekp = NSS_CMSAttribute_GetValue(attr);
926
 
        if (ekp == NULL)
927
 
            return SECFailure;
928
 
 
929
 
        /* we assume that all certs coming with the message have been imported to the */
930
 
        /* temporary database */
931
 
        cert = NSS_SMIMEUtil_GetCertFromEncryptionKeyPreference(certdb, ekp);
932
 
        if (cert == NULL)
933
 
            return SECFailure;
934
 
        must_free_cert = PR_TRUE;
935
 
    }
936
 
 
937
 
    if (cert == NULL) {
938
 
        /* no preferred cert found?
939
 
         * find the cert the signerinfo is signed with instead */
940
 
        cert = NSS_CMSSignerInfo_GetSigningCertificate(signerinfo, certdb);
941
 
        if (cert == NULL || cert->emailAddr == NULL || !cert->emailAddr[0])
942
 
            return SECFailure;
943
 
    }
944
 
 
945
 
    /* verify this cert for encryption (has been verified for signing so far) */
946
 
    /* don't verify this cert for encryption. It may just be a signing cert.
947
 
     * that's OK, we can still save the S/MIME profile. The encryption cert
948
 
     * should have already been saved */
949
 
#ifdef notdef
950
 
    if (CERT_VerifyCert(certdb, cert, PR_TRUE, certUsageEmailRecipient, PR_Now(), signerinfo->cmsg->pwfn_arg, NULL) != SECSuccess) {
951
 
        if (must_free_cert)
952
 
            CERT_DestroyCertificate(cert);
953
 
        return SECFailure;
954
 
    }
955
 
#endif
956
 
 
957
 
    /* XXX store encryption cert permanently? */
958
 
 
959
 
    /*
960
 
     * Remember the current error set because we do not care about
961
 
     * anything set by the functions we are about to call.
962
 
     */
963
 
    save_error = PORT_GetError();
964
 
 
965
 
    if (!NSS_CMSArray_IsEmpty((void **)signerinfo->authAttr)) {
966
 
        attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr,
967
 
                                       SEC_OID_PKCS9_SMIME_CAPABILITIES,
968
 
                                       PR_TRUE);
969
 
        profile = NSS_CMSAttribute_GetValue(attr);
970
 
        attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr,
971
 
                                       SEC_OID_PKCS9_SIGNING_TIME,
972
 
                                       PR_TRUE);
973
 
        stime = NSS_CMSAttribute_GetValue(attr);
974
 
    }
975
 
 
976
 
    rv = CERT_SaveSMimeProfile (cert, profile, stime);
977
 
    if (must_free_cert)
978
 
        CERT_DestroyCertificate(cert);
979
 
 
980
 
    /*
981
 
     * Restore the saved error in case the calls above set a new
982
 
     * one that we do not actually care about.
983
 
     */
984
 
    PORT_SetError (save_error);
985
 
 
986
 
    return rv;
987
 
}
988
 
 
989
 
/*
990
 
 * NSS_CMSSignerInfo_IncludeCerts - set cert chain inclusion mode for this signer
991
 
 */
992
 
SECStatus
993
 
NSS_CMSSignerInfo_IncludeCerts(NSSCMSSignerInfo *signerinfo, NSSCMSCertChainMode cm, SECCertUsage usage)
994
 
{
995
 
    if (signerinfo->cert == NULL)
996
 
        return SECFailure;
997
 
 
998
 
    /* don't leak if we get called twice */
999
 
    if (signerinfo->certList != NULL) {
1000
 
        CERT_DestroyCertificateList(signerinfo->certList);
1001
 
        signerinfo->certList = NULL;
1002
 
    }
1003
 
 
1004
 
    switch (cm) {
1005
 
    case NSSCMSCM_None:
1006
 
        signerinfo->certList = NULL;
1007
 
        break;
1008
 
    case NSSCMSCM_CertOnly:
1009
 
        signerinfo->certList = CERT_CertListFromCert(signerinfo->cert);
1010
 
        break;
1011
 
    case NSSCMSCM_CertChain:
1012
 
        signerinfo->certList = CERT_CertChainFromCert(signerinfo->cert, usage, PR_FALSE);
1013
 
        break;
1014
 
    case NSSCMSCM_CertChainWithRoot:
1015
 
        signerinfo->certList = CERT_CertChainFromCert(signerinfo->cert, usage, PR_TRUE);
1016
 
        break;
1017
 
    }
1018
 
 
1019
 
    if (cm != NSSCMSCM_None && signerinfo->certList == NULL)
1020
 
        return SECFailure;
1021
 
    
1022
 
    return SECSuccess;
1023
 
}