]> git.saurik.com Git - apple/security.git/blob - libsecurity_smime/lib/cmssiginfo.c
41ab2e23638b9cd82dfdab5e465def045c26c941
[apple/security.git] / libsecurity_smime / lib / cmssiginfo.c
1 /*
2 * The contents of this file are subject to the Mozilla Public
3 * License Version 1.1 (the "License"); you may not use this file
4 * except in compliance with the License. You may obtain a copy of
5 * the License at http://www.mozilla.org/MPL/
6 *
7 * Software distributed under the License is distributed on an "AS
8 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9 * implied. See the License for the specific language governing
10 * rights and limitations under the License.
11 *
12 * The Original Code is the Netscape security libraries.
13 *
14 * The Initial Developer of the Original Code is Netscape
15 * Communications Corporation. Portions created by Netscape are
16 * Copyright (C) 1994-2000 Netscape Communications Corporation. All
17 * Rights Reserved.
18 *
19 * Contributor(s):
20 *
21 * Alternatively, the contents of this file may be used under the
22 * terms of the GNU General Public License Version 2 or later (the
23 * "GPL"), in which case the provisions of the GPL are applicable
24 * instead of those above. If you wish to allow use of your
25 * version of this file only under the terms of the GPL and not to
26 * allow others to use your version of this file under the MPL,
27 * indicate your decision by deleting the provisions above and
28 * replace them with the notice and other provisions required by
29 * the GPL. If you do not delete the provisions above, a recipient
30 * may use your version of this file under either the MPL or the
31 * GPL.
32 */
33
34 /*
35 * CMS signerInfo methods.
36 */
37
38 #include <Security/SecCmsSignerInfo.h>
39 #include "SecSMIMEPriv.h"
40
41 #include "cmslocal.h"
42
43 #include "cert.h"
44 #include "SecAsn1Item.h"
45 #include "secoid.h"
46 #include "cryptohi.h"
47
48 #include <security_asn1/secasn1.h>
49 #include <security_asn1/secerr.h>
50 #include <security_asn1/secport.h>
51
52 #if USE_CDSA_CRYPTO
53 #include <Security/SecKeychain.h>
54 #endif
55
56 #include <Security/SecIdentity.h>
57 #include <Security/SecCertificateInternal.h>
58 #include <Security/SecInternal.h>
59 #include <Security/SecKeyPriv.h>
60 #include <utilities/SecCFWrappers.h>
61 #include <CoreFoundation/CFTimeZone.h>
62
63
64 #define HIDIGIT(v) (((v) / 10) + '0')
65 #define LODIGIT(v) (((v) % 10) + '0')
66
67 #define ISDIGIT(dig) (((dig) >= '0') && ((dig) <= '9'))
68 #define CAPTURE(var,p,label) \
69 { \
70 if (!ISDIGIT((p)[0]) || !ISDIGIT((p)[1])) goto label; \
71 (var) = ((p)[0] - '0') * 10 + ((p)[1] - '0'); \
72 }
73
74
75 static OSStatus
76 DER_UTCTimeToCFDate(const SecAsn1Item * utcTime, CFAbsoluteTime *date)
77 {
78 char *string = (char *)utcTime->Data;
79 int year, month, mday, hour, minute, second, hourOff, minOff;
80
81 /* Verify time is formatted properly and capture information */
82 second = 0;
83 hourOff = 0;
84 minOff = 0;
85 CAPTURE(year,string+0,loser);
86 if (year < 50) {
87 /* ASSUME that year # is in the 2000's, not the 1900's */
88 year += 2000;
89 } else {
90 year += 1900;
91 }
92 CAPTURE(month,string+2,loser);
93 if ((month == 0) || (month > 12)) goto loser;
94 CAPTURE(mday,string+4,loser);
95 if ((mday == 0) || (mday > 31)) goto loser;
96 CAPTURE(hour,string+6,loser);
97 if (hour > 23) goto loser;
98 CAPTURE(minute,string+8,loser);
99 if (minute > 59) goto loser;
100 if (ISDIGIT(string[10])) {
101 CAPTURE(second,string+10,loser);
102 if (second > 59) goto loser;
103 string += 2;
104 }
105 if (string[10] == '+') {
106 CAPTURE(hourOff,string+11,loser);
107 if (hourOff > 23) goto loser;
108 CAPTURE(minOff,string+13,loser);
109 if (minOff > 59) goto loser;
110 } else if (string[10] == '-') {
111 CAPTURE(hourOff,string+11,loser);
112 if (hourOff > 23) goto loser;
113 hourOff = -hourOff;
114 CAPTURE(minOff,string+13,loser);
115 if (minOff > 59) goto loser;
116 minOff = -minOff;
117 } else if (string[10] != 'Z') {
118 goto loser;
119 }
120
121 if (hourOff == 0 && minOff == 0) {
122 *date = CFAbsoluteTimeForGregorianZuluMoment(year, month, mday, hour, minute, second);
123 } else {
124 CFTimeZoneRef tz = CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorDefault, (hourOff * 60 + minOff) * 60);
125 *date = CFAbsoluteTimeForGregorianMoment(tz, year, month, mday, hour, minute, second);
126 CFReleaseSafe(tz);
127 }
128
129 return SECSuccess;
130
131 loser:
132 return SECFailure;
133 }
134
135 static OSStatus
136 DER_CFDateToUTCTime(CFAbsoluteTime date, SecAsn1Item * utcTime)
137 {
138 unsigned char *d;
139
140 utcTime->Length = 13;
141 utcTime->Data = d = PORT_Alloc(13);
142 if (!utcTime->Data)
143 return SECFailure;
144
145 int year;
146 int month;
147 int day;
148 int hour;
149 int minute;
150 int second;
151
152 if (!CFCalendarDecomposeAbsoluteTime(SecCFCalendarGetZulu(), date, "yMdHms", &year, &month, &day, &hour, &minute, &second))
153 return SECFailure;
154
155
156 /* UTC time does not handle the years before 1950 */
157 if (year < 1950)
158 return SECFailure;
159
160 /* remove the century since it's added to the year by the
161 CFAbsoluteTimeGetGregorianDate routine, but is not needed for UTC time */
162 year %= 100;
163
164 d[0] = HIDIGIT(year);
165 d[1] = LODIGIT(year);
166 d[2] = HIDIGIT(month);
167 d[3] = LODIGIT(month);
168 d[4] = HIDIGIT(day);
169 d[5] = LODIGIT(day);
170 d[6] = HIDIGIT(hour);
171 d[7] = LODIGIT(hour);
172 d[8] = HIDIGIT(minute);
173 d[9] = LODIGIT(minute);
174 d[10] = HIDIGIT(second);
175 d[11] = LODIGIT(second);
176 d[12] = 'Z';
177 return SECSuccess;
178 }
179
180 /* =============================================================================
181 * SIGNERINFO
182 */
183 SecCmsSignerInfoRef
184 nss_cmssignerinfo_create(SecCmsSignedDataRef sigd, SecCmsSignerIDSelector type, SecCertificateRef cert, const SecAsn1Item *subjKeyID, SecPublicKeyRef pubKey, SecPrivateKeyRef signingKey, SECOidTag digestalgtag);
185
186 SecCmsSignerInfoRef
187 SecCmsSignerInfoCreateWithSubjKeyID(SecCmsSignedDataRef sigd, const SecAsn1Item *subjKeyID, SecPublicKeyRef pubKey, SecPrivateKeyRef signingKey, SECOidTag digestalgtag)
188 {
189 return nss_cmssignerinfo_create(sigd, SecCmsSignerIDSubjectKeyID, NULL, subjKeyID, pubKey, signingKey, digestalgtag);
190 }
191
192 SecCmsSignerInfoRef
193 SecCmsSignerInfoCreate(SecCmsSignedDataRef sigd, SecIdentityRef identity, SECOidTag digestalgtag)
194 {
195 SecCmsSignerInfoRef signerInfo = NULL;
196 SecCertificateRef cert = NULL;
197 SecPrivateKeyRef signingKey = NULL;
198
199 if (SecIdentityCopyCertificate(identity, &cert))
200 goto loser;
201 if (SecIdentityCopyPrivateKey(identity, &signingKey))
202 goto loser;
203
204 signerInfo = nss_cmssignerinfo_create(sigd, SecCmsSignerIDIssuerSN, cert, NULL, NULL, signingKey, digestalgtag);
205
206 loser:
207 if (cert)
208 CFRelease(cert);
209 if (signingKey)
210 CFRelease(signingKey);
211
212 return signerInfo;
213 }
214
215 SecCmsSignerInfoRef
216 nss_cmssignerinfo_create(SecCmsSignedDataRef sigd, SecCmsSignerIDSelector type, SecCertificateRef cert, const SecAsn1Item *subjKeyID, SecPublicKeyRef pubKey, SecPrivateKeyRef signingKey, SECOidTag digestalgtag)
217 {
218 void *mark;
219 SecCmsSignerInfoRef signerinfo;
220 int version;
221 PLArenaPool *poolp;
222
223 poolp = sigd->contentInfo.cmsg->poolp;
224
225 mark = PORT_ArenaMark(poolp);
226
227 signerinfo = (SecCmsSignerInfoRef)PORT_ArenaZAlloc(poolp, sizeof(SecCmsSignerInfo));
228 if (signerinfo == NULL) {
229 PORT_ArenaRelease(poolp, mark);
230 return NULL;
231 }
232
233
234 signerinfo->signedData = sigd;
235
236 switch(type) {
237 case SecCmsSignerIDIssuerSN:
238 signerinfo->signerIdentifier.identifierType = SecCmsSignerIDIssuerSN;
239 if ((signerinfo->cert = CERT_DupCertificate(cert)) == NULL)
240 goto loser;
241 if ((signerinfo->signerIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL)
242 goto loser;
243 break;
244 case SecCmsSignerIDSubjectKeyID:
245 signerinfo->signerIdentifier.identifierType = SecCmsSignerIDSubjectKeyID;
246 PORT_Assert(subjKeyID);
247 if (!subjKeyID)
248 goto loser;
249 signerinfo->signerIdentifier.id.subjectKeyID = PORT_ArenaNew(poolp, SecAsn1Item);
250 SECITEM_CopyItem(poolp, signerinfo->signerIdentifier.id.subjectKeyID,
251 subjKeyID);
252 signerinfo->pubKey = SECKEY_CopyPublicKey(pubKey);
253 if (!signerinfo->pubKey)
254 goto loser;
255 break;
256 default:
257 goto loser;
258 }
259
260 if (!signingKey)
261 goto loser;
262
263 signerinfo->signingKey = SECKEY_CopyPrivateKey(signingKey);
264 if (!signerinfo->signingKey)
265 goto loser;
266
267 /* set version right now */
268 version = SEC_CMS_SIGNER_INFO_VERSION_ISSUERSN;
269 /* RFC2630 5.3 "version is the syntax version number. If the .... " */
270 if (signerinfo->signerIdentifier.identifierType == SecCmsSignerIDSubjectKeyID)
271 version = SEC_CMS_SIGNER_INFO_VERSION_SUBJKEY;
272 (void)SEC_ASN1EncodeInteger(poolp, &(signerinfo->version), (long)version);
273
274 if (SECOID_SetAlgorithmID(poolp, &signerinfo->digestAlg, digestalgtag, NULL) != SECSuccess)
275 goto loser;
276
277 if (SecCmsSignedDataAddSignerInfo(sigd, signerinfo))
278 goto loser;
279
280 PORT_ArenaUnmark(poolp, mark);
281 return signerinfo;
282
283 loser:
284 PORT_ArenaRelease(poolp, mark);
285 return NULL;
286 }
287
288 /*
289 * SecCmsSignerInfoDestroy - destroy a SignerInfo data structure
290 */
291 void
292 SecCmsSignerInfoDestroy(SecCmsSignerInfoRef si)
293 {
294 if (si->cert != NULL)
295 CERT_DestroyCertificate(si->cert);
296
297 if (si->certList != NULL)
298 CFRelease(si->certList);
299
300 /* XXX storage ??? */
301 }
302
303 static SecAsn1AlgId SecCertificateGetPublicKeyAlgorithmID(SecCertificateRef cert)
304 {
305 const DERAlgorithmId *length_data_swapped = SecCertificateGetPublicKeyAlgorithm(cert);
306 SecAsn1AlgId temp = {
307 { length_data_swapped->oid.length, length_data_swapped->oid.data },
308 { length_data_swapped->params.length, length_data_swapped->params.data } };
309
310 return temp;
311 }
312
313 /*
314 * SecCmsSignerInfoSign - sign something
315 *
316 */
317 OSStatus
318 SecCmsSignerInfoSign(SecCmsSignerInfoRef signerinfo, SecAsn1Item * digest, SecAsn1Item * contentType)
319 {
320 SecCertificateRef cert;
321 SecPrivateKeyRef privkey = NULL;
322 SECOidTag digestalgtag;
323 SECOidTag pubkAlgTag;
324 SecAsn1Item signature = { 0 };
325 OSStatus rv;
326 PLArenaPool *poolp, *tmppoolp;
327 const SECAlgorithmID *algID = NULL;
328 //CERTSubjectPublicKeyInfo *spki;
329
330 PORT_Assert (digest != NULL);
331
332 poolp = signerinfo->signedData->contentInfo.cmsg->poolp;
333
334 switch (signerinfo->signerIdentifier.identifierType) {
335 case SecCmsSignerIDIssuerSN:
336 privkey = signerinfo->signingKey;
337 signerinfo->signingKey = NULL;
338 cert = signerinfo->cert;
339 #if USE_CDSA_CRYPTO
340 if (SecCertificateGetAlgorithmID(cert,&algID)) {
341 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
342 goto loser;
343 }
344 #else
345 SecAsn1AlgId _algID = SecCertificateGetPublicKeyAlgorithmID(cert);
346 algID = &_algID;
347 #endif
348 break;
349 case SecCmsSignerIDSubjectKeyID:
350 privkey = signerinfo->signingKey;
351 signerinfo->signingKey = NULL;
352 #if 0
353 spki = SECKEY_CreateSubjectPublicKeyInfo(signerinfo->pubKey);
354 SECKEY_DestroyPublicKey(signerinfo->pubKey);
355 signerinfo->pubKey = NULL;
356 SECOID_CopyAlgorithmID(NULL, &freeAlgID, &spki->algorithm);
357 SECKEY_DestroySubjectPublicKeyInfo(spki);
358 algID = &freeAlgID;
359 #else
360 #if USE_CDSA_CRYPTO
361 if (SecKeyGetAlgorithmID(signerinfo->pubKey,&algID)) {
362 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
363 goto loser;
364 }
365 #endif
366 #endif
367 CFRelease(signerinfo->pubKey);
368 signerinfo->pubKey = NULL;
369 break;
370 default:
371 PORT_SetError(SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE);
372 goto loser;
373 }
374 digestalgtag = SecCmsSignerInfoGetDigestAlgTag(signerinfo);
375 pubkAlgTag = SECOID_GetAlgorithmTag(algID);
376 #if USE_CDSA_CRYPTO
377 if (signerinfo->signerIdentifier.identifierType == SecCmsSignerIDSubjectKeyID) {
378 SECOID_DestroyAlgorithmID(&freeAlgID, PR_FALSE);
379 }
380 #endif
381 #if 0
382 // @@@ Not yet
383 /* Fortezza MISSI have weird signature formats.
384 * Map them to standard DSA formats
385 */
386 pubkAlgTag = PK11_FortezzaMapSig(pubkAlgTag);
387 #endif
388
389 if (signerinfo->authAttr != NULL) {
390 SecAsn1Item encoded_attrs;
391
392 /* find and fill in the message digest attribute. */
393 rv = SecCmsAttributeArraySetAttr(poolp, &(signerinfo->authAttr),
394 SEC_OID_PKCS9_MESSAGE_DIGEST, digest, PR_FALSE);
395 if (rv != SECSuccess)
396 goto loser;
397
398 if (contentType != NULL) {
399 /* if the caller wants us to, find and fill in the content type attribute. */
400 rv = SecCmsAttributeArraySetAttr(poolp, &(signerinfo->authAttr),
401 SEC_OID_PKCS9_CONTENT_TYPE, contentType, PR_FALSE);
402 if (rv != SECSuccess)
403 goto loser;
404 }
405
406 if ((tmppoolp = PORT_NewArena (1024)) == NULL) {
407 PORT_SetError(SEC_ERROR_NO_MEMORY);
408 goto loser;
409 }
410
411 /*
412 * Before encoding, reorder the attributes so that when they
413 * are encoded, they will be conforming DER, which is required
414 * to have a specific order and that is what must be used for
415 * the hash/signature. We do this here, rather than building
416 * it into EncodeAttributes, because we do not want to do
417 * such reordering on incoming messages (which also uses
418 * EncodeAttributes) or our old signatures (and other "broken"
419 * implementations) will not verify. So, we want to guarantee
420 * that we send out good DER encodings of attributes, but not
421 * to expect to receive them.
422 */
423 if (SecCmsAttributeArrayReorder(signerinfo->authAttr) != SECSuccess)
424 goto loser;
425
426 encoded_attrs.Data = NULL;
427 encoded_attrs.Length = 0;
428 if (SecCmsAttributeArrayEncode(tmppoolp, &(signerinfo->authAttr),
429 &encoded_attrs) == NULL)
430 goto loser;
431
432 #if USE_CDSA_CRYPTO
433 rv = SEC_SignData(&signature, encoded_attrs.Data, encoded_attrs.Length,
434 privkey, digestalgtag, pubkAlgTag);
435 #else
436 signature.Length = SecKeyGetSize(privkey, kSecKeySignatureSize);
437 signature.Data = PORT_ZAlloc(signature.Length);
438 if (!signature.Data) {
439 signature.Length = 0;
440 goto loser;
441 }
442 rv = SecKeyDigestAndSign(privkey, &signerinfo->digestAlg, encoded_attrs.Data, encoded_attrs.Length, signature.Data, &signature.Length);
443 if (rv) {
444 PORT_ZFree(signature.Data, signature.Length);
445 signature.Length = 0;
446 }
447 #endif
448
449 PORT_FreeArena(tmppoolp, PR_FALSE); /* awkward memory management :-( */
450 } else {
451 signature.Length = SecKeyGetSize(privkey, kSecKeySignatureSize);
452 signature.Data = PORT_ZAlloc(signature.Length);
453 if (!signature.Data) {
454 signature.Length = 0;
455 goto loser;
456 }
457 rv = SecKeySignDigest(privkey, &signerinfo->digestAlg, digest->Data, digest->Length,
458 signature.Data, &signature.Length);
459 if (rv) {
460 PORT_ZFree(signature.Data, signature.Length);
461 signature.Length = 0;
462 }
463 }
464 SECKEY_DestroyPrivateKey(privkey);
465 privkey = NULL;
466
467 if (rv != SECSuccess)
468 goto loser;
469
470 if (SECITEM_CopyItem(poolp, &(signerinfo->encDigest), &signature)
471 != SECSuccess)
472 goto loser;
473
474 SECITEM_FreeItem(&signature, PR_FALSE);
475
476 if (SECOID_SetAlgorithmID(poolp, &(signerinfo->digestEncAlg), pubkAlgTag,
477 NULL) != SECSuccess)
478 goto loser;
479
480 return SECSuccess;
481
482 loser:
483 if (signature.Length != 0)
484 SECITEM_FreeItem (&signature, PR_FALSE);
485 if (privkey)
486 SECKEY_DestroyPrivateKey(privkey);
487 return SECFailure;
488 }
489
490 #if !USE_CDSA_CRYPTO
491 static CFArrayRef
492 SecCmsSignerInfoCopySigningCertificates(SecCmsSignerInfoRef signerinfo)
493 {
494 CFMutableArrayRef certs = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
495 SecAsn1Item **cert_datas = signerinfo->signedData->rawCerts;
496 SecAsn1Item *cert_data;
497 if (cert_datas) while ((cert_data = *cert_datas) != NULL) {
498 SecCertificateRef cert = SecCertificateCreateWithBytes(NULL, cert_data->Data, cert_data->Length);
499 if (cert) {
500 switch (signerinfo->signerIdentifier.identifierType) {
501 case SecCmsSignerIDIssuerSN:
502 if (CERT_CheckIssuerAndSerial(cert,
503 &(signerinfo->signerIdentifier.id.issuerAndSN->derIssuer),
504 &(signerinfo->signerIdentifier.id.issuerAndSN->serialNumber)))
505 CFArrayInsertValueAtIndex(certs, 0, cert);
506 else
507 CFArrayAppendValue(certs, cert);
508 break;
509 case SecCmsSignerIDSubjectKeyID:
510 {
511 CFDataRef cert_keyid = SecCertificateGetSubjectKeyID(cert);
512 SecAsn1Item *tbf_keyid = signerinfo->signerIdentifier.id.subjectKeyID;
513 if (tbf_keyid->Length == (size_t)CFDataGetLength(cert_keyid) &&
514 !memcmp(tbf_keyid->Data, CFDataGetBytePtr(cert_keyid), tbf_keyid->Length))
515 CFArrayInsertValueAtIndex(certs, 0, cert);
516 else
517 CFArrayAppendValue(certs, cert);
518 break;
519 }
520 }
521 CFReleaseNull(cert);
522 }
523 cert_datas++;
524 }
525
526 if ((CFArrayGetCount(certs) == 0) &&
527 (signerinfo->signerIdentifier.identifierType == SecCmsSignerIDIssuerSN))
528 {
529 SecCertificateRef cert = CERT_FindCertificateByIssuerAndSN(signerinfo->signedData->certs, signerinfo->signerIdentifier.id.issuerAndSN);
530 if (cert) {
531 CFArrayAppendValue(certs, cert);
532 CFRelease(cert);
533 }
534 }
535 return certs;
536 }
537 #endif
538
539 OSStatus
540 SecCmsSignerInfoVerifyCertificate(SecCmsSignerInfoRef signerinfo, SecKeychainRef keychainOrArray,
541 CFTypeRef policies, SecTrustRef *trustRef)
542 {
543 CFAbsoluteTime stime;
544 OSStatus rv;
545
546 #if USE_CDSA_CRYPTO
547 SecCertificateRef cert;
548
549 if ((cert = SecCmsSignerInfoGetSigningCertificate(signerinfo, keychainOrArray)) == NULL) {
550 #else
551 CFArrayRef certs;
552
553 if ((certs = SecCmsSignerInfoCopySigningCertificates(signerinfo)) == NULL) {
554 #endif
555 signerinfo->verificationStatus = SecCmsVSSigningCertNotFound;
556 return SECFailure;
557 }
558 /*
559 * Get and convert the signing time; if available, it will be used
560 * both on the cert verification and for importing the sender
561 * email profile.
562 */
563 if (SecCmsSignerInfoGetSigningTime(signerinfo, &stime) != SECSuccess)
564 stime = CFAbsoluteTimeGetCurrent();
565
566 #if USE_CDSA_CRYPTO
567 rv = CERT_VerifyCert(keychainOrArray, cert, policies, stime, trustRef);
568 #else
569 rv = CERT_VerifyCert(keychainOrArray, certs, policies, stime, trustRef);
570 CFRelease(certs);
571 #endif
572 if (rv || !trustRef)
573 {
574 if (PORT_GetError() == SEC_ERROR_UNTRUSTED_CERT)
575 {
576 /* Signature or digest level verificationStatus errors should supercede certificate level errors, so only change the verificationStatus if the status was GoodSignature. */
577 if (signerinfo->verificationStatus == SecCmsVSGoodSignature)
578 signerinfo->verificationStatus = SecCmsVSSigningCertNotTrusted;
579 }
580 }
581
582 return rv;
583 }
584
585 /*
586 * SecCmsSignerInfoVerify - verify the signature of a single SignerInfo
587 *
588 * Just verifies the signature. The assumption is that verification of the certificate
589 * is done already.
590 */
591 OSStatus
592 SecCmsSignerInfoVerify(SecCmsSignerInfoRef signerinfo, SecAsn1Item * digest, SecAsn1Item * contentType)
593 {
594 SecPublicKeyRef publickey = NULL;
595 SecCmsAttribute *attr;
596 SecAsn1Item encoded_attrs;
597 SecCertificateRef cert;
598 SecCmsVerificationStatus vs = SecCmsVSUnverified;
599 PLArenaPool *poolp;
600 SECOidTag digestAlgTag, digestEncAlgTag;
601
602 if (signerinfo == NULL)
603 return SECFailure;
604
605 /* SecCmsSignerInfoGetSigningCertificate will fail if 2nd parm is NULL and */
606 /* cert has not been verified */
607 if ((cert = SecCmsSignerInfoGetSigningCertificate(signerinfo, NULL)) == NULL) {
608 vs = SecCmsVSSigningCertNotFound;
609 goto loser;
610 }
611
612 #if USE_CDSA_CRYPTO
613 if (SecCertificateCopyPublicKey(cert, &publickey)) {
614 vs = SecCmsVSProcessingError;
615 goto loser;
616 }
617 #else
618 publickey = SecCertificateCopyPublicKey(cert);
619 if (publickey == NULL)
620 goto loser;
621 #endif
622
623 digestAlgTag = SECOID_GetAlgorithmTag(&(signerinfo->digestAlg));
624 digestEncAlgTag = SECOID_GetAlgorithmTag(&(signerinfo->digestEncAlg));
625 if (!SecCmsArrayIsEmpty((void **)signerinfo->authAttr)) {
626 if (contentType) {
627 /*
628 * Check content type
629 *
630 * RFC2630 sez that if there are any authenticated attributes,
631 * then there must be one for content type which matches the
632 * content type of the content being signed, and there must
633 * be one for message digest which matches our message digest.
634 * So check these things first.
635 */
636 if ((attr = SecCmsAttributeArrayFindAttrByOidTag(signerinfo->authAttr,
637 SEC_OID_PKCS9_CONTENT_TYPE, PR_TRUE)) == NULL)
638 {
639 vs = SecCmsVSMalformedSignature;
640 goto loser;
641 }
642
643 if (SecCmsAttributeCompareValue(attr, contentType) == PR_FALSE) {
644 vs = SecCmsVSMalformedSignature;
645 goto loser;
646 }
647 }
648
649 /*
650 * Check digest
651 */
652 if ((attr = SecCmsAttributeArrayFindAttrByOidTag(signerinfo->authAttr, SEC_OID_PKCS9_MESSAGE_DIGEST, PR_TRUE)) == NULL)
653 {
654 vs = SecCmsVSMalformedSignature;
655 goto loser;
656 }
657 if (SecCmsAttributeCompareValue(attr, digest) == PR_FALSE) {
658 vs = SecCmsVSDigestMismatch;
659 goto loser;
660 }
661
662 if ((poolp = PORT_NewArena (1024)) == NULL) {
663 vs = SecCmsVSProcessingError;
664 goto loser;
665 }
666
667 /*
668 * Check signature
669 *
670 * The signature is based on a digest of the DER-encoded authenticated
671 * attributes. So, first we encode and then we digest/verify.
672 * we trust the decoder to have the attributes in the right (sorted) order
673 */
674 encoded_attrs.Data = NULL;
675 encoded_attrs.Length = 0;
676
677 if (SecCmsAttributeArrayEncode(poolp, &(signerinfo->authAttr), &encoded_attrs) == NULL ||
678 encoded_attrs.Data == NULL || encoded_attrs.Length == 0)
679 {
680 vs = SecCmsVSProcessingError;
681 goto loser;
682 }
683 if (errSecSuccess == SecKeyDigestAndVerify(publickey, &signerinfo->digestAlg, encoded_attrs.Data, encoded_attrs.Length, signerinfo->encDigest.Data, signerinfo->encDigest.Length))
684 vs = SecCmsVSGoodSignature;
685 else
686 vs = SecCmsVSBadSignature;
687
688 PORT_FreeArena(poolp, PR_FALSE); /* awkward memory management :-( */
689
690 } else {
691 SecAsn1Item * sig;
692
693 /* No authenticated attributes. The signature is based on the plain message digest. */
694 sig = &(signerinfo->encDigest);
695 if (sig->Length == 0)
696 goto loser;
697
698 if (SecKeyVerifyDigest(publickey, &signerinfo->digestAlg, digest->Data, digest->Length, sig->Data, sig->Length))
699 vs = SecCmsVSBadSignature;
700 else
701 vs = SecCmsVSGoodSignature;
702 }
703
704 if (vs == SecCmsVSBadSignature) {
705 /*
706 * XXX Change the generic error into our specific one, because
707 * in that case we get a better explanation out of the Security
708 * Advisor. This is really a bug in our error strings (the
709 * "generic" error has a lousy/wrong message associated with it
710 * which assumes the signature verification was done for the
711 * purposes of checking the issuer signature on a certificate)
712 * but this is at least an easy workaround and/or in the
713 * Security Advisor, which specifically checks for the error
714 * SEC_ERROR_PKCS7_BAD_SIGNATURE and gives more explanation
715 * in that case but does not similarly check for
716 * SEC_ERROR_BAD_SIGNATURE. It probably should, but then would
717 * probably say the wrong thing in the case that it *was* the
718 * certificate signature check that failed during the cert
719 * verification done above. Our error handling is really a mess.
720 */
721 if (PORT_GetError() == SEC_ERROR_BAD_SIGNATURE)
722 PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
723 }
724
725 if (publickey != NULL)
726 CFRelease(publickey);
727
728 signerinfo->verificationStatus = vs;
729
730 return (vs == SecCmsVSGoodSignature) ? SECSuccess : SECFailure;
731
732 loser:
733 if (publickey != NULL)
734 SECKEY_DestroyPublicKey (publickey);
735
736 signerinfo->verificationStatus = vs;
737
738 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
739 return SECFailure;
740 }
741
742 SecCmsVerificationStatus
743 SecCmsSignerInfoGetVerificationStatus(SecCmsSignerInfoRef signerinfo)
744 {
745 return signerinfo->verificationStatus;
746 }
747
748 SECOidData *
749 SecCmsSignerInfoGetDigestAlg(SecCmsSignerInfoRef signerinfo)
750 {
751 return SECOID_FindOID (&(signerinfo->digestAlg.algorithm));
752 }
753
754 SECOidTag
755 SecCmsSignerInfoGetDigestAlgTag(SecCmsSignerInfoRef signerinfo)
756 {
757 SECOidData *algdata;
758
759 algdata = SECOID_FindOID (&(signerinfo->digestAlg.algorithm));
760 if (algdata != NULL)
761 return algdata->offset;
762 else
763 return SEC_OID_UNKNOWN;
764 }
765
766 CFArrayRef
767 SecCmsSignerInfoGetCertList(SecCmsSignerInfoRef signerinfo)
768 {
769 return signerinfo->certList;
770 }
771
772 int
773 SecCmsSignerInfoGetVersion(SecCmsSignerInfoRef signerinfo)
774 {
775 unsigned long version;
776
777 /* always take apart the SecAsn1Item */
778 if (SEC_ASN1DecodeInteger(&(signerinfo->version), &version) != SECSuccess)
779 return 0;
780 else
781 return (int)version;
782 }
783
784 /*
785 * SecCmsSignerInfoGetSigningTime - return the signing time,
786 * in UTCTime format, of a CMS signerInfo.
787 *
788 * sinfo - signerInfo data for this signer
789 *
790 * Returns a pointer to XXXX (what?)
791 * A return value of NULL is an error.
792 */
793 OSStatus
794 SecCmsSignerInfoGetSigningTime(SecCmsSignerInfoRef sinfo, CFAbsoluteTime *stime)
795 {
796 SecCmsAttribute *attr;
797 SecAsn1Item * value;
798
799 if (sinfo == NULL)
800 return SECFailure;
801
802 if (sinfo->signingTime != 0) {
803 *stime = sinfo->signingTime; /* cached copy */
804 return SECSuccess;
805 }
806
807 attr = SecCmsAttributeArrayFindAttrByOidTag(sinfo->authAttr, SEC_OID_PKCS9_SIGNING_TIME, PR_TRUE);
808 /* XXXX multi-valued attributes NIH */
809 if (attr == NULL || (value = SecCmsAttributeGetValue(attr)) == NULL)
810 return SECFailure;
811 if (DER_UTCTimeToCFDate(value, stime) != SECSuccess)
812 return SECFailure;
813 sinfo->signingTime = *stime; /* make cached copy */
814 return SECSuccess;
815 }
816
817 /*
818 * Return the signing cert of a CMS signerInfo.
819 *
820 * the certs in the enclosing SignedData must have been imported already
821 */
822 SecCertificateRef
823 SecCmsSignerInfoGetSigningCertificate(SecCmsSignerInfoRef signerinfo, SecKeychainRef keychainOrArray)
824 {
825 SecCertificateRef cert = NULL;
826
827 if (signerinfo->cert != NULL)
828 return signerinfo->cert;
829
830 /* @@@ Make sure we search though all the certs in the cms message itself as well, it's silly
831 to require them to be added to a keychain first. */
832
833 #if USE_CDSA_CRYPTO
834 SecCmsSignerIdentifier *sid;
835
836 /*
837 * This cert will also need to be freed, but since we save it
838 * in signerinfo for later, we do not want to destroy it when
839 * we leave this function -- we let the clean-up of the entire
840 * cinfo structure later do the destroy of this cert.
841 */
842 sid = &signerinfo->signerIdentifier;
843 switch (sid->identifierType) {
844 case SecCmsSignerIDIssuerSN:
845 cert = CERT_FindCertByIssuerAndSN(keychainOrArray, sid->id.issuerAndSN);
846 break;
847 case SecCmsSignerIDSubjectKeyID:
848 cert = CERT_FindCertBySubjectKeyID(keychainOrArray, sid->id.subjectKeyID);
849 break;
850 default:
851 cert = NULL;
852 break;
853 }
854
855 /* cert can be NULL at that point */
856 signerinfo->cert = cert; /* earmark it */
857 #else
858 SecAsn1Item **cert_datas = signerinfo->signedData->rawCerts;
859 SecAsn1Item *cert_data;
860 if (cert_datas) while ((cert_data = *cert_datas) != NULL) {
861 cert = SecCertificateCreateWithBytes(NULL, cert_data->Data, cert_data->Length);
862 if (cert) {
863 switch (signerinfo->signerIdentifier.identifierType) {
864 case SecCmsSignerIDIssuerSN:
865 if (CERT_CheckIssuerAndSerial(cert,
866 &(signerinfo->signerIdentifier.id.issuerAndSN->derIssuer),
867 &(signerinfo->signerIdentifier.id.issuerAndSN->serialNumber)))
868 signerinfo->cert = cert;
869 break;
870 case SecCmsSignerIDSubjectKeyID: {
871 CFDataRef cert_keyid = SecCertificateGetSubjectKeyID(cert);
872 SecAsn1Item *tbf_keyid = signerinfo->signerIdentifier.id.subjectKeyID;
873 if (tbf_keyid->Length == (size_t)CFDataGetLength(cert_keyid) &&
874 !memcmp(tbf_keyid->Data, CFDataGetBytePtr(cert_keyid), tbf_keyid->Length))
875 signerinfo->cert = cert;
876 }
877 }
878 if (signerinfo->cert)
879 break;
880 CFReleaseNull(cert);
881 }
882 cert_datas++;
883 }
884
885 if (!signerinfo->cert && (signerinfo->signerIdentifier.identifierType == SecCmsSignerIDIssuerSN)) {
886 cert = CERT_FindCertificateByIssuerAndSN(signerinfo->signedData->certs, signerinfo->signerIdentifier.id.issuerAndSN);
887 signerinfo->cert = cert;
888 }
889 #endif
890
891 return cert;
892 }
893
894
895 /*
896 * SecCmsSignerInfoGetSignerCommonName - return the common name of the signer
897 *
898 * sinfo - signerInfo data for this signer
899 *
900 * Returns a CFStringRef containing the common name of the signer.
901 * A return value of NULL is an error.
902 */
903 CFStringRef
904 SecCmsSignerInfoGetSignerCommonName(SecCmsSignerInfoRef sinfo)
905 {
906 SecCertificateRef signercert;
907 CFStringRef commonName = NULL;
908
909 /* will fail if cert is not verified */
910 if ((signercert = SecCmsSignerInfoGetSigningCertificate(sinfo, NULL)) == NULL)
911 return NULL;
912
913 #if USE_CDSA_CRYPTO
914 SecCertificateGetCommonName(signercert, &commonName);
915 #else
916 CFArrayRef commonNames = SecCertificateCopyCommonNames(signercert);
917 if (commonNames) {
918 /* SecCertificateCopyCommonNames doesn't return empty arrays */
919 commonName = (CFStringRef)CFArrayGetValueAtIndex(commonNames, CFArrayGetCount(commonNames) - 1);
920 CFRetain(commonName);
921 CFRelease(commonNames);
922 }
923 #endif
924
925 return commonName;
926 }
927
928 /*
929 * SecCmsSignerInfoGetSignerEmailAddress - return the email address of the signer
930 *
931 * sinfo - signerInfo data for this signer
932 *
933 * Returns a CFStringRef containing the name of the signer.
934 * A return value of NULL is an error.
935 */
936 CFStringRef
937 SecCmsSignerInfoGetSignerEmailAddress(SecCmsSignerInfoRef sinfo)
938 {
939 SecCertificateRef signercert;
940 CFStringRef emailAddress = NULL;
941
942 if ((signercert = SecCmsSignerInfoGetSigningCertificate(sinfo, NULL)) == NULL)
943 return NULL;
944
945 #if USE_CDSA_CRYPTO
946 SecCertificateGetEmailAddress(signercert, &emailAddress);
947 #else
948 CFArrayRef names = SecCertificateCopyRFC822Names(signercert);
949 if (names) {
950 if (CFArrayGetCount(names) > 0)
951 emailAddress = (CFStringRef)CFArrayGetValueAtIndex(names, 0);
952 if (emailAddress)
953 CFRetain(emailAddress);
954 CFRelease(names);
955 }
956 #endif
957 return emailAddress;
958 }
959
960
961 /*
962 * SecCmsSignerInfoAddAuthAttr - add an attribute to the
963 * authenticated (i.e. signed) attributes of "signerinfo".
964 */
965 OSStatus
966 SecCmsSignerInfoAddAuthAttr(SecCmsSignerInfoRef signerinfo, SecCmsAttribute *attr)
967 {
968 return SecCmsAttributeArrayAddAttr(signerinfo->signedData->contentInfo.cmsg->poolp, &(signerinfo->authAttr), attr);
969 }
970
971 /*
972 * SecCmsSignerInfoAddUnauthAttr - add an attribute to the
973 * unauthenticated attributes of "signerinfo".
974 */
975 OSStatus
976 SecCmsSignerInfoAddUnauthAttr(SecCmsSignerInfoRef signerinfo, SecCmsAttribute *attr)
977 {
978 return SecCmsAttributeArrayAddAttr(signerinfo->signedData->contentInfo.cmsg->poolp, &(signerinfo->unAuthAttr), attr);
979 }
980
981 /*
982 * SecCmsSignerInfoAddSigningTime - add the signing time to the
983 * authenticated (i.e. signed) attributes of "signerinfo".
984 *
985 * This is expected to be included in outgoing signed
986 * messages for email (S/MIME) but is likely useful in other situations.
987 *
988 * This should only be added once; a second call will do nothing.
989 *
990 * XXX This will probably just shove the current time into "signerinfo"
991 * but it will not actually get signed until the entire item is
992 * processed for encoding. Is this (expected to be small) delay okay?
993 */
994 OSStatus
995 SecCmsSignerInfoAddSigningTime(SecCmsSignerInfoRef signerinfo, CFAbsoluteTime t)
996 {
997 SecCmsAttribute *attr;
998 SecAsn1Item stime;
999 void *mark;
1000 PLArenaPool *poolp;
1001
1002 poolp = signerinfo->signedData->contentInfo.cmsg->poolp;
1003
1004 mark = PORT_ArenaMark(poolp);
1005
1006 /* create new signing time attribute */
1007 if (DER_CFDateToUTCTime(t, &stime) != SECSuccess)
1008 goto loser;
1009
1010 if ((attr = SecCmsAttributeCreate(poolp, SEC_OID_PKCS9_SIGNING_TIME, &stime, PR_FALSE)) == NULL) {
1011 SECITEM_FreeItem (&stime, PR_FALSE);
1012 goto loser;
1013 }
1014
1015 SECITEM_FreeItem (&stime, PR_FALSE);
1016
1017 if (SecCmsSignerInfoAddAuthAttr(signerinfo, attr) != SECSuccess)
1018 goto loser;
1019
1020 PORT_ArenaUnmark (poolp, mark);
1021
1022 return SECSuccess;
1023
1024 loser:
1025 PORT_ArenaRelease (poolp, mark);
1026 return SECFailure;
1027 }
1028
1029 /*
1030 * SecCmsSignerInfoAddSMIMECaps - add a SMIMECapabilities attribute to the
1031 * authenticated (i.e. signed) attributes of "signerinfo".
1032 *
1033 * This is expected to be included in outgoing signed
1034 * messages for email (S/MIME).
1035 */
1036 OSStatus
1037 SecCmsSignerInfoAddSMIMECaps(SecCmsSignerInfoRef signerinfo)
1038 {
1039 SecCmsAttribute *attr;
1040 SecAsn1Item * smimecaps = NULL;
1041 void *mark;
1042 PLArenaPool *poolp;
1043
1044 poolp = signerinfo->signedData->contentInfo.cmsg->poolp;
1045
1046 mark = PORT_ArenaMark(poolp);
1047
1048 smimecaps = SECITEM_AllocItem(poolp, NULL, 0);
1049 if (smimecaps == NULL)
1050 goto loser;
1051
1052 /* create new signing time attribute */
1053 #if 1
1054 // @@@ We don't do Fortezza yet.
1055 if (SecSMIMECreateSMIMECapabilities(poolp, smimecaps, PR_FALSE) != SECSuccess)
1056 #else
1057 if (SecSMIMECreateSMIMECapabilities(poolp, smimecaps,
1058 PK11_FortezzaHasKEA(signerinfo->cert)) != SECSuccess)
1059 #endif
1060 goto loser;
1061
1062 if ((attr = SecCmsAttributeCreate(poolp, SEC_OID_PKCS9_SMIME_CAPABILITIES, smimecaps, PR_TRUE)) == NULL)
1063 goto loser;
1064
1065 if (SecCmsSignerInfoAddAuthAttr(signerinfo, attr) != SECSuccess)
1066 goto loser;
1067
1068 PORT_ArenaUnmark (poolp, mark);
1069 return SECSuccess;
1070
1071 loser:
1072 PORT_ArenaRelease (poolp, mark);
1073 return SECFailure;
1074 }
1075
1076 /*
1077 * SecCmsSignerInfoAddSMIMEEncKeyPrefs - add a SMIMEEncryptionKeyPreferences attribute to the
1078 * authenticated (i.e. signed) attributes of "signerinfo".
1079 *
1080 * This is expected to be included in outgoing signed messages for email (S/MIME).
1081 */
1082 OSStatus
1083 SecCmsSignerInfoAddSMIMEEncKeyPrefs(SecCmsSignerInfoRef signerinfo, SecCertificateRef cert, SecKeychainRef keychainOrArray)
1084 {
1085 SecCmsAttribute *attr;
1086 SecAsn1Item * smimeekp = NULL;
1087 void *mark;
1088 PLArenaPool *poolp;
1089
1090 #if 0
1091 CFTypeRef policy;
1092
1093 /* verify this cert for encryption */
1094 policy = CERT_PolicyForCertUsage(certUsageEmailRecipient);
1095 if (CERT_VerifyCert(keychainOrArray, cert, policy, CFAbsoluteTimeGetCurrent(), NULL) != SECSuccess) {
1096 CFRelease(policy);
1097 return SECFailure;
1098 }
1099 CFRelease(policy);
1100 #endif
1101
1102 poolp = signerinfo->signedData->contentInfo.cmsg->poolp;
1103 mark = PORT_ArenaMark(poolp);
1104
1105 smimeekp = SECITEM_AllocItem(poolp, NULL, 0);
1106 if (smimeekp == NULL)
1107 goto loser;
1108
1109 /* create new signing time attribute */
1110 if (SecSMIMECreateSMIMEEncKeyPrefs(poolp, smimeekp, cert) != SECSuccess)
1111 goto loser;
1112
1113 if ((attr = SecCmsAttributeCreate(poolp, SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE, smimeekp, PR_TRUE)) == NULL)
1114 goto loser;
1115
1116 if (SecCmsSignerInfoAddAuthAttr(signerinfo, attr) != SECSuccess)
1117 goto loser;
1118
1119 PORT_ArenaUnmark (poolp, mark);
1120 return SECSuccess;
1121
1122 loser:
1123 PORT_ArenaRelease (poolp, mark);
1124 return SECFailure;
1125 }
1126
1127 /*
1128 * SecCmsSignerInfoAddMSSMIMEEncKeyPrefs - add a SMIMEEncryptionKeyPreferences attribute to the
1129 * authenticated (i.e. signed) attributes of "signerinfo", using the OID prefered by Microsoft.
1130 *
1131 * This is expected to be included in outgoing signed messages for email (S/MIME),
1132 * if compatibility with Microsoft mail clients is wanted.
1133 */
1134 OSStatus
1135 SecCmsSignerInfoAddMSSMIMEEncKeyPrefs(SecCmsSignerInfoRef signerinfo, SecCertificateRef cert, SecKeychainRef keychainOrArray)
1136 {
1137 SecCmsAttribute *attr;
1138 SecAsn1Item * smimeekp = NULL;
1139 void *mark;
1140 PLArenaPool *poolp;
1141
1142 #if 0
1143 CFTypeRef policy;
1144
1145 /* verify this cert for encryption */
1146 policy = CERT_PolicyForCertUsage(certUsageEmailRecipient);
1147 if (CERT_VerifyCert(keychainOrArray, cert, policy, CFAbsoluteTimeGetCurrent(), NULL) != SECSuccess) {
1148 CFRelease(policy);
1149 return SECFailure;
1150 }
1151 CFRelease(policy);
1152 #endif
1153
1154 poolp = signerinfo->signedData->contentInfo.cmsg->poolp;
1155 mark = PORT_ArenaMark(poolp);
1156
1157 smimeekp = SECITEM_AllocItem(poolp, NULL, 0);
1158 if (smimeekp == NULL)
1159 goto loser;
1160
1161 /* create new signing time attribute */
1162 if (SecSMIMECreateMSSMIMEEncKeyPrefs(poolp, smimeekp, cert) != SECSuccess)
1163 goto loser;
1164
1165 if ((attr = SecCmsAttributeCreate(poolp, SEC_OID_MS_SMIME_ENCRYPTION_KEY_PREFERENCE, smimeekp, PR_TRUE)) == NULL)
1166 goto loser;
1167
1168 if (SecCmsSignerInfoAddAuthAttr(signerinfo, attr) != SECSuccess)
1169 goto loser;
1170
1171 PORT_ArenaUnmark (poolp, mark);
1172 return SECSuccess;
1173
1174 loser:
1175 PORT_ArenaRelease (poolp, mark);
1176 return SECFailure;
1177 }
1178
1179 /*
1180 * SecCmsSignerInfoAddCounterSignature - countersign a signerinfo
1181 *
1182 * 1. digest the DER-encoded signature value of the original signerinfo
1183 * 2. create new signerinfo with correct version, sid, digestAlg
1184 * 3. add message-digest authAttr, but NO content-type
1185 * 4. sign the authAttrs
1186 * 5. DER-encode the new signerInfo
1187 * 6. add the whole thing to original signerInfo's unAuthAttrs
1188 * as a SEC_OID_PKCS9_COUNTER_SIGNATURE attribute
1189 *
1190 * XXXX give back the new signerinfo?
1191 */
1192 OSStatus
1193 SecCmsSignerInfoAddCounterSignature(SecCmsSignerInfoRef signerinfo,
1194 SECOidTag digestalg, SecIdentityRef identity)
1195 {
1196 /* XXXX TBD XXXX */
1197 return SECFailure;
1198 }
1199
1200 /*
1201 * XXXX the following needs to be done in the S/MIME layer code
1202 * after signature of a signerinfo is verified
1203 */
1204 OSStatus
1205 SecCmsSignerInfoSaveSMIMEProfile(SecCmsSignerInfoRef signerinfo)
1206 {
1207 return -4 /*unImp*/;
1208 }
1209
1210 /*
1211 * SecCmsSignerInfoIncludeCerts - set cert chain inclusion mode for this signer
1212 */
1213 OSStatus
1214 SecCmsSignerInfoIncludeCerts(SecCmsSignerInfoRef signerinfo, SecCmsCertChainMode cm, SECCertUsage usage)
1215 {
1216 if (signerinfo->cert == NULL)
1217 return SECFailure;
1218
1219 /* don't leak if we get called twice */
1220 if (signerinfo->certList != NULL) {
1221 CFRelease(signerinfo->certList);
1222 signerinfo->certList = NULL;
1223 }
1224
1225 switch (cm) {
1226 case SecCmsCMNone:
1227 signerinfo->certList = NULL;
1228 break;
1229 case SecCmsCMCertOnly:
1230 signerinfo->certList = CERT_CertListFromCert(signerinfo->cert);
1231 break;
1232 case SecCmsCMCertChain:
1233 signerinfo->certList = CERT_CertChainFromCert(signerinfo->cert, usage, PR_FALSE);
1234 break;
1235 case SecCmsCMCertChainWithRoot:
1236 signerinfo->certList = CERT_CertChainFromCert(signerinfo->cert, usage, PR_TRUE);
1237 break;
1238 }
1239
1240 if (cm != SecCmsCMNone && signerinfo->certList == NULL)
1241 return SECFailure;
1242
1243 return SECSuccess;
1244 }