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/. */
6
* CMS signerInfo methods.
8
* $Id: cmssiginfo.c,v 1.37 2012/04/25 14:50:09 gerv%gerv.net Exp $
26
/* =============================================================================
30
nss_cmssignerinfo_create(NSSCMSMessage *cmsg, NSSCMSSignerIDSelector type,
31
CERTCertificate *cert, SECItem *subjKeyID, SECKEYPublicKey *pubKey,
32
SECKEYPrivateKey *signingKey, SECOidTag digestalgtag);
35
NSS_CMSSignerInfo_CreateWithSubjKeyID(NSSCMSMessage *cmsg, SECItem *subjKeyID,
36
SECKEYPublicKey *pubKey, SECKEYPrivateKey *signingKey, SECOidTag digestalgtag)
38
return nss_cmssignerinfo_create(cmsg, NSSCMSSignerID_SubjectKeyID, NULL, subjKeyID, pubKey, signingKey, digestalgtag);
42
NSS_CMSSignerInfo_Create(NSSCMSMessage *cmsg, CERTCertificate *cert, SECOidTag digestalgtag)
44
return nss_cmssignerinfo_create(cmsg, NSSCMSSignerID_IssuerSN, cert, NULL, NULL, NULL, digestalgtag);
48
nss_cmssignerinfo_create(NSSCMSMessage *cmsg, NSSCMSSignerIDSelector type,
49
CERTCertificate *cert, SECItem *subjKeyID, SECKEYPublicKey *pubKey,
50
SECKEYPrivateKey *signingKey, SECOidTag digestalgtag)
53
NSSCMSSignerInfo *signerinfo;
59
mark = PORT_ArenaMark(poolp);
61
signerinfo = (NSSCMSSignerInfo *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSSignerInfo));
62
if (signerinfo == NULL) {
63
PORT_ArenaRelease(poolp, mark);
68
signerinfo->cmsg = cmsg;
71
case NSSCMSSignerID_IssuerSN:
72
signerinfo->signerIdentifier.identifierType = NSSCMSSignerID_IssuerSN;
73
if ((signerinfo->cert = CERT_DupCertificate(cert)) == NULL)
75
if ((signerinfo->signerIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL)
78
case NSSCMSSignerID_SubjectKeyID:
79
signerinfo->signerIdentifier.identifierType = NSSCMSSignerID_SubjectKeyID;
80
PORT_Assert(subjKeyID);
84
signerinfo->signerIdentifier.id.subjectKeyID = PORT_ArenaNew(poolp, SECItem);
85
SECITEM_CopyItem(poolp, signerinfo->signerIdentifier.id.subjectKeyID,
87
signerinfo->signingKey = SECKEY_CopyPrivateKey(signingKey);
88
if (!signerinfo->signingKey)
90
signerinfo->pubKey = SECKEY_CopyPublicKey(pubKey);
91
if (!signerinfo->pubKey)
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);
105
if (SECOID_SetAlgorithmID(poolp, &signerinfo->digestAlg, digestalgtag, NULL) != SECSuccess)
108
PORT_ArenaUnmark(poolp, mark);
112
PORT_ArenaRelease(poolp, mark);
117
* NSS_CMSSignerInfo_Destroy - destroy a SignerInfo data structure
120
NSS_CMSSignerInfo_Destroy(NSSCMSSignerInfo *si)
122
if (si->cert != NULL)
123
CERT_DestroyCertificate(si->cert);
125
if (si->certList != NULL)
126
CERT_DestroyCertificateList(si->certList);
128
/* XXX storage ??? */
132
* NSS_CMSSignerInfo_Sign - sign something
136
NSS_CMSSignerInfo_Sign(NSSCMSSignerInfo *signerinfo, SECItem *digest,
137
SECItem *contentType)
139
CERTCertificate *cert;
140
SECKEYPrivateKey *privkey = NULL;
141
SECOidTag digestalgtag;
142
SECOidTag pubkAlgTag;
143
SECItem signature = { 0 };
145
PLArenaPool *poolp, *tmppoolp = NULL;
146
SECAlgorithmID *algID, freeAlgID;
147
CERTSubjectPublicKeyInfo *spki;
149
PORT_Assert (digest != NULL);
151
poolp = signerinfo->cmsg->poolp;
153
switch (signerinfo->signerIdentifier.identifierType) {
154
case NSSCMSSignerID_IssuerSN:
155
cert = signerinfo->cert;
157
privkey = PK11_FindKeyByAnyCert(cert, signerinfo->cmsg->pwfn_arg);
160
algID = &cert->subjectPublicKeyInfo.algorithm;
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);
175
digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo);
177
* XXX I think there should be a cert-level interface for this,
178
* so that I do not have to know about subjectPublicKeyInfo...
180
pubkAlgTag = SECOID_GetAlgorithmTag(algID);
181
if (signerinfo->signerIdentifier.identifierType == NSSCMSSignerID_SubjectKeyID) {
182
SECOID_DestroyAlgorithmID(&freeAlgID, PR_FALSE);
185
if (signerinfo->authAttr != NULL) {
186
SECOidTag signAlgTag;
187
SECItem encoded_attrs;
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)
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)
203
if ((tmppoolp = PORT_NewArena (1024)) == NULL) {
204
PORT_SetError(SEC_ERROR_NO_MEMORY);
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.
220
if (NSS_CMSAttributeArray_Reorder(signerinfo->authAttr) != SECSuccess)
223
encoded_attrs.data = NULL;
224
encoded_attrs.len = 0;
225
if (NSS_CMSAttributeArray_Encode(tmppoolp, &(signerinfo->authAttr),
226
&encoded_attrs) == NULL)
229
signAlgTag = SEC_GetSignatureAlgorithmOidTag(privkey->keyType,
231
if (signAlgTag == SEC_OID_UNKNOWN) {
232
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
236
rv = SEC_SignData(&signature, encoded_attrs.data, encoded_attrs.len,
237
privkey, signAlgTag);
238
PORT_FreeArena(tmppoolp, PR_FALSE); /* awkward memory management :-( */
241
rv = SGN_Digest(privkey, digestalgtag, &signature, digest);
243
SECKEY_DestroyPrivateKey(privkey);
246
if (rv != SECSuccess)
249
if (SECITEM_CopyItem(poolp, &(signerinfo->encDigest), &signature)
253
SECITEM_FreeItem(&signature, PR_FALSE);
255
if (SECOID_SetAlgorithmID(poolp, &(signerinfo->digestEncAlg), pubkAlgTag,
262
if (signature.len != 0)
263
SECITEM_FreeItem (&signature, PR_FALSE);
265
SECKEY_DestroyPrivateKey(privkey);
267
PORT_FreeArena(tmppoolp, PR_FALSE);
272
NSS_CMSSignerInfo_VerifyCertificate(NSSCMSSignerInfo *signerinfo, CERTCertDBHandle *certdb,
273
SECCertUsage certusage)
275
CERTCertificate *cert;
278
if ((cert = NSS_CMSSignerInfo_GetSigningCertificate(signerinfo, certdb)) == NULL) {
279
signerinfo->verificationStatus = NSSCMSVS_SigningCertNotFound;
284
* Get and convert the signing time; if available, it will be used
285
* both on the cert verification and for importing the sender
288
if (NSS_CMSSignerInfo_GetSigningTime (signerinfo, &stime) != SECSuccess)
289
stime = PR_Now(); /* not found or conversion failed, so check against now */
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?).
299
if (CERT_VerifyCert(certdb, cert, PR_TRUE, certusage, stime,
300
signerinfo->cmsg->pwfn_arg, NULL) != SECSuccess) {
301
signerinfo->verificationStatus = NSSCMSVS_SigningCertNotTrusted;
308
* NSS_CMSSignerInfo_Verify - verify the signature of a single SignerInfo
310
* Just verifies the signature. The assumption is that verification of
311
* the certificate is done already.
314
NSS_CMSSignerInfo_Verify(NSSCMSSignerInfo *signerinfo,
315
SECItem *digest, /* may be NULL */
316
SECItem *contentType) /* may be NULL */
318
SECKEYPublicKey *publickey = NULL;
319
NSSCMSAttribute *attr;
320
SECItem encoded_attrs;
321
CERTCertificate *cert;
322
NSSCMSVerificationStatus vs = NSSCMSVS_Unverified;
324
SECOidTag digestalgtag;
325
SECOidTag pubkAlgTag;
327
if (signerinfo == NULL)
330
/* NSS_CMSSignerInfo_GetSigningCertificate will fail if 2nd parm is NULL
331
** and cert has not been verified
333
cert = NSS_CMSSignerInfo_GetSigningCertificate(signerinfo, NULL);
335
vs = NSSCMSVS_SigningCertNotFound;
339
if ((publickey = CERT_ExtractPublicKey(cert)) == NULL) {
340
vs = NSSCMSVS_ProcessingError;
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;
351
#ifndef NSS_ECC_MORE_THAN_SUITE_B
352
if (pubkAlgTag == SEC_OID_ANSIX962_EC_PUBLIC_KEY) {
353
vs = NSSCMSVS_SignatureAlgorithmUnknown;
358
if (!NSS_CMSArray_IsEmpty((void **)signerinfo->authAttr)) {
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.
369
attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr,
370
SEC_OID_PKCS9_CONTENT_TYPE, PR_TRUE);
372
vs = NSSCMSVS_MalformedSignature;
376
if (NSS_CMSAttribute_CompareValue(attr, contentType) == PR_FALSE) {
377
vs = NSSCMSVS_MalformedSignature;
385
attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr,
386
SEC_OID_PKCS9_MESSAGE_DIGEST, PR_TRUE);
388
vs = NSSCMSVS_MalformedSignature;
392
NSS_CMSAttribute_CompareValue(attr, digest) == PR_FALSE) {
393
vs = NSSCMSVS_DigestMismatch;
397
if ((poolp = PORT_NewArena (1024)) == NULL) {
398
vs = NSSCMSVS_ProcessingError;
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)
410
encoded_attrs.data = NULL;
411
encoded_attrs.len = 0;
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;
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;
425
PORT_FreeArena(poolp, PR_FALSE); /* awkward memory management :-( */
430
/* No authenticated attributes.
431
** The signature is based on the plain message digest.
433
sig = &(signerinfo->encDigest);
438
VFY_VerifyDigestDirect(digest, publickey, sig, pubkAlgTag,
439
digestalgtag, signerinfo->cmsg->pwfn_arg) != SECSuccess)
440
? NSSCMSVS_BadSignature : NSSCMSVS_GoodSignature;
443
if (vs == NSSCMSVS_BadSignature) {
444
int error = PORT_GetError();
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.
461
if (error == SEC_ERROR_BAD_SIGNATURE)
462
PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
464
* map algorithm failures to NSSCMSVS values
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;
474
if (publickey != NULL)
475
SECKEY_DestroyPublicKey (publickey);
477
signerinfo->verificationStatus = vs;
479
return (vs == NSSCMSVS_GoodSignature) ? SECSuccess : SECFailure;
482
if (publickey != NULL)
483
SECKEY_DestroyPublicKey (publickey);
485
signerinfo->verificationStatus = vs;
487
PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
491
NSSCMSVerificationStatus
492
NSS_CMSSignerInfo_GetVerificationStatus(NSSCMSSignerInfo *signerinfo)
494
return signerinfo->verificationStatus;
498
NSS_CMSSignerInfo_GetDigestAlg(NSSCMSSignerInfo *signerinfo)
503
algdata = SECOID_FindOID (&(signerinfo->digestAlg.algorithm));
504
if (algdata == NULL) {
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.
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);
525
NSS_CMSSignerInfo_GetDigestAlgTag(NSSCMSSignerInfo *signerinfo)
530
PORT_SetError(SEC_ERROR_INVALID_ARGS);
531
return SEC_OID_UNKNOWN;
534
algdata = NSS_CMSSignerInfo_GetDigestAlg(signerinfo);
536
return algdata->offset;
538
return SEC_OID_UNKNOWN;
541
CERTCertificateList *
542
NSS_CMSSignerInfo_GetCertList(NSSCMSSignerInfo *signerinfo)
544
return signerinfo->certList;
548
NSS_CMSSignerInfo_GetVersion(NSSCMSSignerInfo *signerinfo)
550
unsigned long version;
552
/* always take apart the SECItem */
553
if (SEC_ASN1DecodeInteger(&(signerinfo->version), &version) != SECSuccess)
560
* NSS_CMSSignerInfo_GetSigningTime - return the signing time,
561
* in UTCTime or GeneralizedTime format,
562
* of a CMS signerInfo.
564
* sinfo - signerInfo data for this signer
566
* Returns a pointer to XXXX (what?)
567
* A return value of NULL is an error.
570
NSS_CMSSignerInfo_GetSigningTime(NSSCMSSignerInfo *sinfo, PRTime *stime)
572
NSSCMSAttribute *attr;
578
if (sinfo->signingTime != 0) {
579
*stime = sinfo->signingTime; /* cached copy */
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)
587
if (DER_DecodeTimeChoice(stime, value) != SECSuccess)
589
sinfo->signingTime = *stime; /* make cached copy */
594
* Return the signing cert of a CMS signerInfo.
596
* the certs in the enclosing SignedData must have been imported already
599
NSS_CMSSignerInfo_GetSigningCertificate(NSSCMSSignerInfo *signerinfo, CERTCertDBHandle *certdb)
601
CERTCertificate *cert;
602
NSSCMSSignerIdentifier *sid;
604
if (signerinfo->cert != NULL)
605
return signerinfo->cert;
607
/* no certdb, and cert hasn't been set yet? */
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.
617
sid = &signerinfo->signerIdentifier;
618
switch (sid->identifierType) {
619
case NSSCMSSignerID_IssuerSN:
620
cert = CERT_FindCertByIssuerAndSN(certdb, sid->id.issuerAndSN);
622
case NSSCMSSignerID_SubjectKeyID:
623
cert = CERT_FindCertBySubjectKeyID(certdb, sid->id.subjectKeyID);
630
/* cert can be NULL at that point */
631
signerinfo->cert = cert; /* earmark it */
637
* NSS_CMSSignerInfo_GetSignerCommonName - return the common name of the signer
639
* sinfo - signerInfo data for this signer
641
* Returns a pointer to allocated memory, which must be freed with PORT_Free.
642
* A return value of NULL is an error.
645
NSS_CMSSignerInfo_GetSignerCommonName(NSSCMSSignerInfo *sinfo)
647
CERTCertificate *signercert;
649
/* will fail if cert is not verified */
650
if ((signercert = NSS_CMSSignerInfo_GetSigningCertificate(sinfo, NULL)) == NULL)
653
return (CERT_GetCommonName(&signercert->subject));
657
* NSS_CMSSignerInfo_GetSignerEmailAddress - return the common name of the signer
659
* sinfo - signerInfo data for this signer
661
* Returns a pointer to allocated memory, which must be freed.
662
* A return value of NULL is an error.
665
NSS_CMSSignerInfo_GetSignerEmailAddress(NSSCMSSignerInfo *sinfo)
667
CERTCertificate *signercert;
669
if ((signercert = NSS_CMSSignerInfo_GetSigningCertificate(sinfo, NULL)) == NULL)
672
if (!signercert->emailAddr || !signercert->emailAddr[0])
675
return (PORT_Strdup(signercert->emailAddr));
679
* NSS_CMSSignerInfo_AddAuthAttr - add an attribute to the
680
* authenticated (i.e. signed) attributes of "signerinfo".
683
NSS_CMSSignerInfo_AddAuthAttr(NSSCMSSignerInfo *signerinfo, NSSCMSAttribute *attr)
685
return NSS_CMSAttributeArray_AddAttr(signerinfo->cmsg->poolp, &(signerinfo->authAttr), attr);
689
* NSS_CMSSignerInfo_AddUnauthAttr - add an attribute to the
690
* unauthenticated attributes of "signerinfo".
693
NSS_CMSSignerInfo_AddUnauthAttr(NSSCMSSignerInfo *signerinfo, NSSCMSAttribute *attr)
695
return NSS_CMSAttributeArray_AddAttr(signerinfo->cmsg->poolp, &(signerinfo->unAuthAttr), attr);
699
* NSS_CMSSignerInfo_AddSigningTime - add the signing time to the
700
* authenticated (i.e. signed) attributes of "signerinfo".
702
* This is expected to be included in outgoing signed
703
* messages for email (S/MIME) but is likely useful in other situations.
705
* This should only be added once; a second call will do nothing.
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?
712
NSS_CMSSignerInfo_AddSigningTime(NSSCMSSignerInfo *signerinfo, PRTime t)
714
NSSCMSAttribute *attr;
719
poolp = signerinfo->cmsg->poolp;
721
mark = PORT_ArenaMark(poolp);
723
/* create new signing time attribute */
724
if (DER_EncodeTimeChoice(NULL, &stime, t) != SECSuccess)
727
if ((attr = NSS_CMSAttribute_Create(poolp, SEC_OID_PKCS9_SIGNING_TIME, &stime, PR_FALSE)) == NULL) {
728
SECITEM_FreeItem (&stime, PR_FALSE);
732
SECITEM_FreeItem (&stime, PR_FALSE);
734
if (NSS_CMSSignerInfo_AddAuthAttr(signerinfo, attr) != SECSuccess)
737
PORT_ArenaUnmark (poolp, mark);
742
PORT_ArenaRelease (poolp, mark);
747
* NSS_CMSSignerInfo_AddSMIMECaps - add a SMIMECapabilities attribute to the
748
* authenticated (i.e. signed) attributes of "signerinfo".
750
* This is expected to be included in outgoing signed
751
* messages for email (S/MIME).
754
NSS_CMSSignerInfo_AddSMIMECaps(NSSCMSSignerInfo *signerinfo)
756
NSSCMSAttribute *attr;
757
SECItem *smimecaps = NULL;
761
poolp = signerinfo->cmsg->poolp;
763
mark = PORT_ArenaMark(poolp);
765
smimecaps = SECITEM_AllocItem(poolp, NULL, 0);
766
if (smimecaps == NULL)
769
/* create new signing time attribute */
770
if (NSS_SMIMEUtil_CreateSMIMECapabilities(poolp, smimecaps) != SECSuccess)
773
if ((attr = NSS_CMSAttribute_Create(poolp, SEC_OID_PKCS9_SMIME_CAPABILITIES, smimecaps, PR_TRUE)) == NULL)
776
if (NSS_CMSSignerInfo_AddAuthAttr(signerinfo, attr) != SECSuccess)
779
PORT_ArenaUnmark (poolp, mark);
783
PORT_ArenaRelease (poolp, mark);
788
* NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs - add a SMIMEEncryptionKeyPreferences attribute to the
789
* authenticated (i.e. signed) attributes of "signerinfo".
791
* This is expected to be included in outgoing signed messages for email (S/MIME).
794
NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(NSSCMSSignerInfo *signerinfo, CERTCertificate *cert, CERTCertDBHandle *certdb)
796
NSSCMSAttribute *attr;
797
SECItem *smimeekp = NULL;
801
/* verify this cert for encryption */
802
if (CERT_VerifyCert(certdb, cert, PR_TRUE, certUsageEmailRecipient, PR_Now(), signerinfo->cmsg->pwfn_arg, NULL) != SECSuccess) {
806
poolp = signerinfo->cmsg->poolp;
807
mark = PORT_ArenaMark(poolp);
809
smimeekp = SECITEM_AllocItem(poolp, NULL, 0);
810
if (smimeekp == NULL)
813
/* create new signing time attribute */
814
if (NSS_SMIMEUtil_CreateSMIMEEncKeyPrefs(poolp, smimeekp, cert) != SECSuccess)
817
if ((attr = NSS_CMSAttribute_Create(poolp, SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE, smimeekp, PR_TRUE)) == NULL)
820
if (NSS_CMSSignerInfo_AddAuthAttr(signerinfo, attr) != SECSuccess)
823
PORT_ArenaUnmark (poolp, mark);
827
PORT_ArenaRelease (poolp, mark);
832
* NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs - add a SMIMEEncryptionKeyPreferences attribute to the
833
* authenticated (i.e. signed) attributes of "signerinfo", using the OID preferred by Microsoft.
835
* This is expected to be included in outgoing signed messages for email (S/MIME),
836
* if compatibility with Microsoft mail clients is wanted.
839
NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(NSSCMSSignerInfo *signerinfo, CERTCertificate *cert, CERTCertDBHandle *certdb)
841
NSSCMSAttribute *attr;
842
SECItem *smimeekp = NULL;
846
/* verify this cert for encryption */
847
if (CERT_VerifyCert(certdb, cert, PR_TRUE, certUsageEmailRecipient, PR_Now(), signerinfo->cmsg->pwfn_arg, NULL) != SECSuccess) {
851
poolp = signerinfo->cmsg->poolp;
852
mark = PORT_ArenaMark(poolp);
854
smimeekp = SECITEM_AllocItem(poolp, NULL, 0);
855
if (smimeekp == NULL)
858
/* create new signing time attribute */
859
if (NSS_SMIMEUtil_CreateMSSMIMEEncKeyPrefs(poolp, smimeekp, cert) != SECSuccess)
862
if ((attr = NSS_CMSAttribute_Create(poolp, SEC_OID_MS_SMIME_ENCRYPTION_KEY_PREFERENCE, smimeekp, PR_TRUE)) == NULL)
865
if (NSS_CMSSignerInfo_AddAuthAttr(signerinfo, attr) != SECSuccess)
868
PORT_ArenaUnmark (poolp, mark);
872
PORT_ArenaRelease (poolp, mark);
877
* NSS_CMSSignerInfo_AddCounterSignature - countersign a signerinfo
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
887
* XXXX give back the new signerinfo?
890
NSS_CMSSignerInfo_AddCounterSignature(NSSCMSSignerInfo *signerinfo,
891
SECOidTag digestalg, CERTCertificate signingcert)
898
* XXXX the following needs to be done in the S/MIME layer code
899
* after signature of a signerinfo is verified
902
NSS_SMIMESignerInfo_SaveSMIMEProfile(NSSCMSSignerInfo *signerinfo)
904
CERTCertificate *cert = NULL;
905
SECItem *profile = NULL;
906
NSSCMSAttribute *attr;
907
SECItem *stime = NULL;
909
CERTCertDBHandle *certdb;
912
PRBool must_free_cert = PR_FALSE;
914
certdb = CERT_GetDefaultCertDB();
916
/* sanity check - see if verification status is ok (unverified does not count...) */
917
if (signerinfo->verificationStatus != NSSCMSVS_GoodSignature)
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);
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);
934
must_free_cert = PR_TRUE;
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])
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 */
950
if (CERT_VerifyCert(certdb, cert, PR_TRUE, certUsageEmailRecipient, PR_Now(), signerinfo->cmsg->pwfn_arg, NULL) != SECSuccess) {
952
CERT_DestroyCertificate(cert);
957
/* XXX store encryption cert permanently? */
960
* Remember the current error set because we do not care about
961
* anything set by the functions we are about to call.
963
save_error = PORT_GetError();
965
if (!NSS_CMSArray_IsEmpty((void **)signerinfo->authAttr)) {
966
attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr,
967
SEC_OID_PKCS9_SMIME_CAPABILITIES,
969
profile = NSS_CMSAttribute_GetValue(attr);
970
attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr,
971
SEC_OID_PKCS9_SIGNING_TIME,
973
stime = NSS_CMSAttribute_GetValue(attr);
976
rv = CERT_SaveSMimeProfile (cert, profile, stime);
978
CERT_DestroyCertificate(cert);
981
* Restore the saved error in case the calls above set a new
982
* one that we do not actually care about.
984
PORT_SetError (save_error);
990
* NSS_CMSSignerInfo_IncludeCerts - set cert chain inclusion mode for this signer
993
NSS_CMSSignerInfo_IncludeCerts(NSSCMSSignerInfo *signerinfo, NSSCMSCertChainMode cm, SECCertUsage usage)
995
if (signerinfo->cert == NULL)
998
/* don't leak if we get called twice */
999
if (signerinfo->certList != NULL) {
1000
CERT_DestroyCertificateList(signerinfo->certList);
1001
signerinfo->certList = NULL;
1006
signerinfo->certList = NULL;
1008
case NSSCMSCM_CertOnly:
1009
signerinfo->certList = CERT_CertListFromCert(signerinfo->cert);
1011
case NSSCMSCM_CertChain:
1012
signerinfo->certList = CERT_CertChainFromCert(signerinfo->cert, usage, PR_FALSE);
1014
case NSSCMSCM_CertChainWithRoot:
1015
signerinfo->certList = CERT_CertChainFromCert(signerinfo->cert, usage, PR_TRUE);
1019
if (cm != NSSCMSCM_None && signerinfo->certList == NULL)