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/
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.
12 * The Original Code is the Netscape security libraries.
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
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
35 * CMS signerInfo methods.
38 #include <Security/SecCmsSignerInfo.h>
39 #include "SecSMIMEPriv.h"
48 #include <security_asn1/secasn1.h>
49 #include <security_asn1/secerr.h>
50 #include <Security/SecKeychain.h>
51 #include <Security/SecIdentity.h>
52 #include <Security/SecCertificatePriv.h>
53 #include <Security/SecKeyPriv.h>
54 #include <CoreFoundation/CFTimeZone.h>
55 #include <utilities/SecCFWrappers.h>
56 #include <AssertMacros.h>
57 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
58 #include <Security/SecPolicyPriv.h>
60 #include "tsaSupport.h"
61 #include "tsaSupportPriv.h"
65 #define HIDIGIT(v) (((v) / 10) + '0')
66 #define LODIGIT(v) (((v) % 10) + '0')
68 #define ISDIGIT(dig) (((dig) >= '0') && ((dig) <= '9'))
69 #define CAPTURE(var,p,label) \
71 if (!ISDIGIT((p)[0]) || !ISDIGIT((p)[1])) goto label; \
72 (var) = ((p)[0] - '0') * 10 + ((p)[1] - '0'); \
76 #define SIGINFO_DEBUG 1
80 #define dprintf(args...) fprintf(stderr, args)
82 #define dprintf(args...)
86 #define dprintfRC(args...) dprintf(args)
88 #define dprintfRC(args...)
92 DER_UTCTimeToCFDate(const CSSM_DATA_PTR utcTime
, CFAbsoluteTime
*date
)
94 CFGregorianDate gdate
;
95 char *string
= (char *)utcTime
->Data
;
96 long year
, month
, mday
, hour
, minute
, second
, hourOff
, minOff
;
97 CFTimeZoneRef timeZone
;
99 /* Verify time is formatted properly and capture information */
103 CAPTURE(year
,string
+0,loser
);
105 /* ASSUME that year # is in the 2000's, not the 1900's */
108 CAPTURE(month
,string
+2,loser
);
109 if ((month
== 0) || (month
> 12)) goto loser
;
110 CAPTURE(mday
,string
+4,loser
);
111 if ((mday
== 0) || (mday
> 31)) goto loser
;
112 CAPTURE(hour
,string
+6,loser
);
113 if (hour
> 23) goto loser
;
114 CAPTURE(minute
,string
+8,loser
);
115 if (minute
> 59) goto loser
;
116 if (ISDIGIT(string
[10])) {
117 CAPTURE(second
,string
+10,loser
);
118 if (second
> 59) goto loser
;
121 if (string
[10] == '+') {
122 CAPTURE(hourOff
,string
+11,loser
);
123 if (hourOff
> 23) goto loser
;
124 CAPTURE(minOff
,string
+13,loser
);
125 if (minOff
> 59) goto loser
;
126 } else if (string
[10] == '-') {
127 CAPTURE(hourOff
,string
+11,loser
);
128 if (hourOff
> 23) goto loser
;
130 CAPTURE(minOff
,string
+13,loser
);
131 if (minOff
> 59) goto loser
;
133 } else if (string
[10] != 'Z') {
137 gdate
.year
= (SInt32
)(year
+ 1900);
141 gdate
.minute
= minute
;
142 gdate
.second
= second
;
144 if (hourOff
== 0 && minOff
== 0)
145 timeZone
= NULL
; /* GMT */
148 timeZone
= CFTimeZoneCreateWithTimeIntervalFromGMT(NULL
, (hourOff
* 60 + minOff
) * 60);
151 *date
= CFGregorianDateGetAbsoluteTime(gdate
, timeZone
);
162 DER_CFDateToUTCTime(CFAbsoluteTime date
, CSSM_DATA_PTR utcTime
)
164 CFGregorianDate gdate
= CFAbsoluteTimeGetGregorianDate(date
, NULL
/* GMT */);
168 utcTime
->Length
= 13;
169 utcTime
->Data
= d
= PORT_Alloc(13);
173 /* UTC time does not handle the years before 1950 */
174 if (gdate
.year
< 1950)
177 /* remove the century since it's added to the year by the
178 CFAbsoluteTimeGetGregorianDate routine, but is not needed for UTC time */
180 second
= gdate
.second
+ 0.5;
182 d
[0] = HIDIGIT(gdate
.year
);
183 d
[1] = LODIGIT(gdate
.year
);
184 d
[2] = HIDIGIT(gdate
.month
);
185 d
[3] = LODIGIT(gdate
.month
);
186 d
[4] = HIDIGIT(gdate
.day
);
187 d
[5] = LODIGIT(gdate
.day
);
188 d
[6] = HIDIGIT(gdate
.hour
);
189 d
[7] = LODIGIT(gdate
.hour
);
190 d
[8] = HIDIGIT(gdate
.minute
);
191 d
[9] = LODIGIT(gdate
.minute
);
192 d
[10] = HIDIGIT(second
);
193 d
[11] = LODIGIT(second
);
198 /* =============================================================================
202 nss_cmssignerinfo_create(SecCmsMessageRef cmsg
, SecCmsSignerIDSelector type
, SecCertificateRef cert
, CSSM_DATA_PTR subjKeyID
, SecPublicKeyRef pubKey
, SecPrivateKeyRef signingKey
, SECOidTag digestalgtag
);
205 SecCmsSignerInfoCreateWithSubjKeyID(SecCmsMessageRef cmsg
, CSSM_DATA_PTR subjKeyID
, SecPublicKeyRef pubKey
, SecPrivateKeyRef signingKey
, SECOidTag digestalgtag
)
207 return nss_cmssignerinfo_create(cmsg
, SecCmsSignerIDSubjectKeyID
, NULL
, subjKeyID
, pubKey
, signingKey
, digestalgtag
);
211 SecCmsSignerInfoCreate(SecCmsMessageRef cmsg
, SecIdentityRef identity
, SECOidTag digestalgtag
)
213 SecCmsSignerInfoRef signerInfo
= NULL
;
214 SecCertificateRef cert
= NULL
;
215 SecPrivateKeyRef signingKey
= NULL
;
217 if (SecIdentityCopyCertificate(identity
, &cert
))
219 if (SecIdentityCopyPrivateKey(identity
, &signingKey
))
222 signerInfo
= nss_cmssignerinfo_create(cmsg
, SecCmsSignerIDIssuerSN
, cert
, NULL
, NULL
, signingKey
, digestalgtag
);
228 CFRelease(signingKey
);
234 nss_cmssignerinfo_create(SecCmsMessageRef cmsg
, SecCmsSignerIDSelector type
, SecCertificateRef cert
, CSSM_DATA_PTR subjKeyID
, SecPublicKeyRef pubKey
, SecPrivateKeyRef signingKey
, SECOidTag digestalgtag
)
237 SecCmsSignerInfoRef signerinfo
;
243 mark
= PORT_ArenaMark(poolp
);
245 signerinfo
= (SecCmsSignerInfoRef
)PORT_ArenaZAlloc(poolp
, sizeof(SecCmsSignerInfo
));
246 if (signerinfo
== NULL
) {
247 PORT_ArenaRelease(poolp
, mark
);
252 signerinfo
->cmsg
= cmsg
;
255 case SecCmsSignerIDIssuerSN
:
256 signerinfo
->signerIdentifier
.identifierType
= SecCmsSignerIDIssuerSN
;
257 if ((signerinfo
->cert
= CERT_DupCertificate(cert
)) == NULL
)
259 if ((signerinfo
->signerIdentifier
.id
.issuerAndSN
= CERT_GetCertIssuerAndSN(poolp
, cert
)) == NULL
)
261 dprintfRC("nss_cmssignerinfo_create: SecCmsSignerIDIssuerSN: cert.rc %d\n",
262 (int)CFGetRetainCount(signerinfo
->cert
));
264 case SecCmsSignerIDSubjectKeyID
:
265 signerinfo
->signerIdentifier
.identifierType
= SecCmsSignerIDSubjectKeyID
;
266 PORT_Assert(subjKeyID
);
269 signerinfo
->signerIdentifier
.id
.subjectKeyID
= PORT_ArenaNew(poolp
, CSSM_DATA
);
270 SECITEM_CopyItem(poolp
, signerinfo
->signerIdentifier
.id
.subjectKeyID
,
272 signerinfo
->pubKey
= SECKEY_CopyPublicKey(pubKey
);
273 if (!signerinfo
->pubKey
)
283 signerinfo
->signingKey
= SECKEY_CopyPrivateKey(signingKey
);
284 if (!signerinfo
->signingKey
)
287 /* set version right now */
288 version
= SEC_CMS_SIGNER_INFO_VERSION_ISSUERSN
;
289 /* RFC2630 5.3 "version is the syntax version number. If the .... " */
290 if (signerinfo
->signerIdentifier
.identifierType
== SecCmsSignerIDSubjectKeyID
)
291 version
= SEC_CMS_SIGNER_INFO_VERSION_SUBJKEY
;
292 (void)SEC_ASN1EncodeInteger(poolp
, &(signerinfo
->version
), (long)version
);
294 if (SECOID_SetAlgorithmID(poolp
, &signerinfo
->digestAlg
, digestalgtag
, NULL
) != SECSuccess
)
297 PORT_ArenaUnmark(poolp
, mark
);
301 PORT_ArenaRelease(poolp
, mark
);
306 * SecCmsSignerInfoDestroy - destroy a SignerInfo data structure
309 SecCmsSignerInfoDestroy(SecCmsSignerInfoRef si
)
311 if (si
->cert
!= NULL
) {
312 dprintfRC("SecCmsSignerInfoDestroy top: certp %p cert.rc %d\n",
313 si
->cert
, (int)CFGetRetainCount(si
->cert
));
314 CERT_DestroyCertificate(si
->cert
);
316 if (si
->certList
!= NULL
) {
317 dprintfRC("SecCmsSignerInfoDestroy top: certList.rc %d\n",
318 (int)CFGetRetainCount(si
->certList
));
319 CFRelease(si
->certList
);
321 if (si
->timestampCertList
!= NULL
) {
322 dprintfRC("SecCmsSignerInfoDestroy top: timestampCertList.rc %d\n",
323 (int)CFGetRetainCount(si
->timestampCertList
));
324 CFRelease(si
->timestampCertList
);
326 if (si
->hashAgilityAttrValue
!= NULL
) {
327 dprintfRC("SecCmsSignerInfoDestroy top: hashAgilityAttrValue.rc %d\n",
328 (int)CFGetRetainCount(si
->hashAgilityAttrValue
));
329 CFRelease(si
->hashAgilityAttrValue
);
331 /* XXX storage ??? */
335 * SecCmsSignerInfoSign - sign something
339 SecCmsSignerInfoSign(SecCmsSignerInfoRef signerinfo
, CSSM_DATA_PTR digest
, CSSM_DATA_PTR contentType
)
341 SecCertificateRef cert
;
342 SecPrivateKeyRef privkey
= NULL
;
343 SECOidTag digestalgtag
;
344 SECOidTag pubkAlgTag
;
345 CSSM_DATA signature
= { 0 };
347 PLArenaPool
*poolp
, *tmppoolp
= NULL
;
348 const SECAlgorithmID
*algID
;
349 SECAlgorithmID freeAlgID
;
350 //CERTSubjectPublicKeyInfo *spki;
352 PORT_Assert (digest
!= NULL
);
354 poolp
= signerinfo
->cmsg
->poolp
;
356 switch (signerinfo
->signerIdentifier
.identifierType
) {
357 case SecCmsSignerIDIssuerSN
:
358 privkey
= signerinfo
->signingKey
;
359 signerinfo
->signingKey
= NULL
;
360 cert
= signerinfo
->cert
;
361 if (SecCertificateGetAlgorithmID(cert
,&algID
)) {
362 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM
);
366 case SecCmsSignerIDSubjectKeyID
:
367 privkey
= signerinfo
->signingKey
;
368 signerinfo
->signingKey
= NULL
;
370 spki
= SECKEY_CreateSubjectPublicKeyInfo(signerinfo
->pubKey
);
371 SECKEY_DestroyPublicKey(signerinfo
->pubKey
);
372 signerinfo
->pubKey
= NULL
;
373 SECOID_CopyAlgorithmID(NULL
, &freeAlgID
, &spki
->algorithm
);
374 SECKEY_DestroySubjectPublicKeyInfo(spki
);
378 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR))
379 if (SecKeyGetAlgorithmID(signerinfo
->pubKey
,&algID
)) {
381 /* TBD: Unify this code. Currently, iOS has an incompatible
382 * SecKeyGetAlgorithmID implementation. */
385 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM
);
388 CFRelease(signerinfo
->pubKey
);
389 signerinfo
->pubKey
= NULL
;
393 PORT_SetError(SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE
);
396 digestalgtag
= SecCmsSignerInfoGetDigestAlgTag(signerinfo
);
398 * XXX I think there should be a cert-level interface for this,
399 * so that I do not have to know about subjectPublicKeyInfo...
401 pubkAlgTag
= SECOID_GetAlgorithmTag(algID
);
402 if (signerinfo
->signerIdentifier
.identifierType
== SecCmsSignerIDSubjectKeyID
) {
403 SECOID_DestroyAlgorithmID(&freeAlgID
, PR_FALSE
);
408 /* Fortezza MISSI have weird signature formats.
409 * Map them to standard DSA formats
411 pubkAlgTag
= PK11_FortezzaMapSig(pubkAlgTag
);
414 if (signerinfo
->authAttr
!= NULL
) {
415 CSSM_DATA encoded_attrs
;
417 /* find and fill in the message digest attribute. */
418 rv
= SecCmsAttributeArraySetAttr(poolp
, &(signerinfo
->authAttr
),
419 SEC_OID_PKCS9_MESSAGE_DIGEST
, digest
, PR_FALSE
);
420 if (rv
!= SECSuccess
)
423 if (contentType
!= NULL
) {
424 /* if the caller wants us to, find and fill in the content type attribute. */
425 rv
= SecCmsAttributeArraySetAttr(poolp
, &(signerinfo
->authAttr
),
426 SEC_OID_PKCS9_CONTENT_TYPE
, contentType
, PR_FALSE
);
427 if (rv
!= SECSuccess
)
431 if ((tmppoolp
= PORT_NewArena (1024)) == NULL
) {
432 PORT_SetError(SEC_ERROR_NO_MEMORY
);
437 * Before encoding, reorder the attributes so that when they
438 * are encoded, they will be conforming DER, which is required
439 * to have a specific order and that is what must be used for
440 * the hash/signature. We do this here, rather than building
441 * it into EncodeAttributes, because we do not want to do
442 * such reordering on incoming messages (which also uses
443 * EncodeAttributes) or our old signatures (and other "broken"
444 * implementations) will not verify. So, we want to guarantee
445 * that we send out good DER encodings of attributes, but not
446 * to expect to receive them.
448 if (SecCmsAttributeArrayReorder(signerinfo
->authAttr
) != SECSuccess
)
451 encoded_attrs
.Data
= NULL
;
452 encoded_attrs
.Length
= 0;
453 if (SecCmsAttributeArrayEncode(tmppoolp
, &(signerinfo
->authAttr
),
454 &encoded_attrs
) == NULL
)
457 rv
= SEC_SignData(&signature
, encoded_attrs
.Data
, (int)encoded_attrs
.Length
,
458 privkey
, digestalgtag
, pubkAlgTag
);
459 PORT_FreeArena(tmppoolp
, PR_FALSE
); /* awkward memory management :-( */
462 rv
= SGN_Digest(privkey
, digestalgtag
, pubkAlgTag
, &signature
, digest
);
464 SECKEY_DestroyPrivateKey(privkey
);
467 if (rv
!= SECSuccess
)
470 if (SECITEM_CopyItem(poolp
, &(signerinfo
->encDigest
), &signature
)
474 SECITEM_FreeItem(&signature
, PR_FALSE
);
476 if(pubkAlgTag
== SEC_OID_EC_PUBLIC_KEY
) {
478 * RFC 3278 section section 2.1.1 states that the signatureAlgorithm
479 * field contains the full ecdsa-with-SHA1 OID, not plain old ecPublicKey
480 * as would appear in other forms of signed datas. However Microsoft doesn't
481 * do this, it puts ecPublicKey there, and if we put ecdsa-with-SHA1 there,
482 * MS can't verify - presumably because it takes the digest of the digest
483 * before feeding it to ECDSA.
484 * We handle this with a preference; default if it's not there is
485 * "Microsoft compatibility mode".
487 if(!SecCmsMsEcdsaCompatMode()) {
488 pubkAlgTag
= SEC_OID_ECDSA_WithSHA1
;
490 /* else violating the spec for compatibility */
493 if (SECOID_SetAlgorithmID(poolp
, &(signerinfo
->digestEncAlg
), pubkAlgTag
,
500 if (signature
.Length
!= 0)
501 SECITEM_FreeItem (&signature
, PR_FALSE
);
503 SECKEY_DestroyPrivateKey(privkey
);
504 if((algID
!= NULL
) & (algID
!= &freeAlgID
)) {
505 /* this is dicey - this was actually mallocd by either SecCertificate or
506 * by SecKey...it all boils down to a free() in the end though. */
507 SECOID_DestroyAlgorithmID((SECAlgorithmID
*)algID
, PR_FALSE
);
510 PORT_FreeArena(tmppoolp
, PR_FALSE
);
515 SecCmsSignerInfoVerifyCertificate(SecCmsSignerInfoRef signerinfo
, SecKeychainRef keychainOrArray
,
516 CFTypeRef policies
, SecTrustRef
*trustRef
)
518 SecCertificateRef cert
;
519 CFAbsoluteTime stime
;
521 CSSM_DATA_PTR
*otherCerts
;
523 if ((cert
= SecCmsSignerInfoGetSigningCertificate(signerinfo
, keychainOrArray
)) == NULL
) {
524 dprintf("SecCmsSignerInfoVerifyCertificate: no signing cert\n");
525 signerinfo
->verificationStatus
= SecCmsVSSigningCertNotFound
;
530 * Get and convert the signing time; if available, it will be used
531 * both on the cert verification and for importing the sender
534 CFTypeRef timeStampPolicies
=SecPolicyCreateAppleTimeStampingAndRevocationPolicies(policies
);
535 if (SecCmsSignerInfoGetTimestampTimeWithPolicy(signerinfo
, timeStampPolicies
, &stime
) != SECSuccess
)
536 if (SecCmsSignerInfoGetSigningTime(signerinfo
, &stime
) != SECSuccess
)
537 stime
= CFAbsoluteTimeGetCurrent();
538 CFReleaseSafe(timeStampPolicies
);
540 rv
= SecCmsSignedDataRawCerts(signerinfo
->sigd
, &otherCerts
);
544 rv
= CERT_VerifyCert(keychainOrArray
, cert
, otherCerts
, policies
, stime
, trustRef
);
545 dprintfRC("SecCmsSignerInfoVerifyCertificate after vfy: certp %p cert.rc %d\n",
546 cert
, (int)CFGetRetainCount(cert
));
549 if (PORT_GetError() == SEC_ERROR_UNTRUSTED_CERT
)
551 /* Signature or digest level verificationStatus errors should supercede certificate level errors, so only change the verificationStatus if the status was GoodSignature. */
552 if (signerinfo
->verificationStatus
== SecCmsVSGoodSignature
)
553 signerinfo
->verificationStatus
= SecCmsVSSigningCertNotTrusted
;
556 /* FIXME isn't this leaking the cert? */
557 dprintf("SecCmsSignerInfoVerifyCertificate: CertVerify rtn %d\n", (int)rv
);
561 static void debugShowSigningCertificate(SecCmsSignerInfoRef signerinfo
)
564 CFStringRef cn
= SecCmsSignerInfoGetSignerCommonName(signerinfo
);
567 char *ccn
= cfStringToChar(cn
);
570 dprintf("SecCmsSignerInfoVerify: cn: %s\n", ccn
);
579 * SecCmsSignerInfoVerify - verify the signature of a single SignerInfo
581 * Just verifies the signature. The assumption is that verification of the certificate
585 SecCmsSignerInfoVerify(SecCmsSignerInfoRef signerinfo
, CSSM_DATA_PTR digest
, CSSM_DATA_PTR contentType
)
587 return SecCmsSignerInfoVerifyWithPolicy(signerinfo
,NULL
, digest
,contentType
);
591 SecCmsSignerInfoVerifyWithPolicy(SecCmsSignerInfoRef signerinfo
,CFTypeRef timeStampPolicy
, CSSM_DATA_PTR digest
, CSSM_DATA_PTR contentType
)
593 SecPublicKeyRef publickey
= NULL
;
594 SecCmsAttribute
*attr
;
595 CSSM_DATA encoded_attrs
;
596 SecCertificateRef cert
;
597 SecCmsVerificationStatus vs
= SecCmsVSUnverified
;
599 SECOidTag digestAlgTag
, digestEncAlgTag
;
601 if (signerinfo
== NULL
)
604 /* SecCmsSignerInfoGetSigningCertificate will fail if 2nd parm is NULL and */
605 /* cert has not been verified */
606 if ((cert
= SecCmsSignerInfoGetSigningCertificate(signerinfo
, NULL
)) == NULL
) {
607 dprintf("SecCmsSignerInfoVerify: no signing cert\n");
608 vs
= SecCmsVSSigningCertNotFound
;
612 dprintfRC("SecCmsSignerInfoVerify top: cert %p cert.rc %d\n", cert
, (int)CFGetRetainCount(cert
));
614 debugShowSigningCertificate(signerinfo
);
617 if ((status
= SecCertificateCopyPublicKey(cert
, &publickey
))) {
618 syslog(LOG_ERR
, "SecCmsSignerInfoVerifyWithPolicy: copy public key failed %d", (int)status
);
619 vs
= SecCmsVSProcessingError
;
623 digestAlgTag
= SECOID_GetAlgorithmTag(&(signerinfo
->digestAlg
));
624 digestEncAlgTag
= SECOID_GetAlgorithmTag(&(signerinfo
->digestEncAlg
));
627 * Gross hack necessitated by RFC 3278 section 2.1.1, which states
628 * that the signature algorithm (here, digestEncAlg) contains ecdsa_with-SHA1,
629 * *not* (as in all other algorithms) the raw signature algorithm, e.g.
630 * pkcs1RSAEncryption.
632 if(digestEncAlgTag
== SEC_OID_ECDSA_WithSHA1
) {
633 digestEncAlgTag
= SEC_OID_EC_PUBLIC_KEY
;
636 if (!SecCmsArrayIsEmpty((void **)signerinfo
->authAttr
)) {
641 * RFC2630 sez that if there are any authenticated attributes,
642 * then there must be one for content type which matches the
643 * content type of the content being signed, and there must
644 * be one for message digest which matches our message digest.
645 * So check these things first.
647 if ((attr
= SecCmsAttributeArrayFindAttrByOidTag(signerinfo
->authAttr
,
648 SEC_OID_PKCS9_CONTENT_TYPE
, PR_TRUE
)) == NULL
)
650 vs
= SecCmsVSMalformedSignature
;
654 if (SecCmsAttributeCompareValue(attr
, contentType
) == PR_FALSE
) {
655 vs
= SecCmsVSMalformedSignature
;
663 if ((attr
= SecCmsAttributeArrayFindAttrByOidTag(signerinfo
->authAttr
, SEC_OID_PKCS9_MESSAGE_DIGEST
, PR_TRUE
)) == NULL
)
665 vs
= SecCmsVSMalformedSignature
;
668 if (SecCmsAttributeCompareValue(attr
, digest
) == PR_FALSE
) {
669 vs
= SecCmsVSDigestMismatch
;
673 if ((poolp
= PORT_NewArena (1024)) == NULL
) {
674 syslog(LOG_ERR
, "SecCmsSignerInfoVerifyWithPolicy: failed to make new Arena %d", PORT_GetError());
675 vs
= SecCmsVSProcessingError
;
682 * The signature is based on a digest of the DER-encoded authenticated
683 * attributes. So, first we encode and then we digest/verify.
684 * we trust the decoder to have the attributes in the right (sorted) order
686 encoded_attrs
.Data
= NULL
;
687 encoded_attrs
.Length
= 0;
689 if (SecCmsAttributeArrayEncode(poolp
, &(signerinfo
->authAttr
), &encoded_attrs
) == NULL
||
690 encoded_attrs
.Data
== NULL
|| encoded_attrs
.Length
== 0)
692 syslog(LOG_ERR
, "SecCmsSignerInfoVerifyWithPolicy: failed to encode attributes");
693 vs
= SecCmsVSProcessingError
;
697 vs
= (VFY_VerifyData (encoded_attrs
.Data
, (int)encoded_attrs
.Length
,
698 publickey
, &(signerinfo
->encDigest
),
699 digestAlgTag
, digestEncAlgTag
,
700 signerinfo
->cmsg
->pwfn_arg
) != SECSuccess
) ? SecCmsVSBadSignature
: SecCmsVSGoodSignature
;
702 dprintf("VFY_VerifyData (authenticated attributes): %s\n",
703 (vs
== SecCmsVSGoodSignature
)?"SecCmsVSGoodSignature":"SecCmsVSBadSignature");
705 PORT_FreeArena(poolp
, PR_FALSE
); /* awkward memory management :-( */
710 /* No authenticated attributes. The signature is based on the plain message digest. */
711 sig
= &(signerinfo
->encDigest
);
712 if (sig
->Length
== 0)
715 vs
= (VFY_VerifyDigest(digest
, publickey
, sig
,
716 digestAlgTag
, digestEncAlgTag
,
717 signerinfo
->cmsg
->pwfn_arg
) != SECSuccess
) ? SecCmsVSBadSignature
: SecCmsVSGoodSignature
;
719 dprintf("VFY_VerifyData (plain message digest): %s\n",
720 (vs
== SecCmsVSGoodSignature
)?"SecCmsVSGoodSignature":"SecCmsVSBadSignature");
723 if (!SecCmsArrayIsEmpty((void **)signerinfo
->unAuthAttr
))
725 dprintf("found an unAuthAttr\n");
726 OSStatus rux
= SecCmsSignerInfoVerifyUnAuthAttrsWithPolicy(signerinfo
,timeStampPolicy
);
727 dprintf("SecCmsSignerInfoVerifyUnAuthAttrs Status: %ld\n", (long)rux
);
733 if (vs
== SecCmsVSBadSignature
) {
735 * XXX Change the generic error into our specific one, because
736 * in that case we get a better explanation out of the Security
737 * Advisor. This is really a bug in our error strings (the
738 * "generic" error has a lousy/wrong message associated with it
739 * which assumes the signature verification was done for the
740 * purposes of checking the issuer signature on a certificate)
741 * but this is at least an easy workaround and/or in the
742 * Security Advisor, which specifically checks for the error
743 * SEC_ERROR_PKCS7_BAD_SIGNATURE and gives more explanation
744 * in that case but does not similarly check for
745 * SEC_ERROR_BAD_SIGNATURE. It probably should, but then would
746 * probably say the wrong thing in the case that it *was* the
747 * certificate signature check that failed during the cert
748 * verification done above. Our error handling is really a mess.
750 if (PORT_GetError() == SEC_ERROR_BAD_SIGNATURE
)
751 PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE
);
754 if (publickey
!= NULL
)
755 CFRelease(publickey
);
757 signerinfo
->verificationStatus
= vs
;
758 dprintfRC("SecCmsSignerInfoVerify end: cerp %p cert.rc %d\n",
759 cert
, (int)CFGetRetainCount(cert
));
761 dprintf("verificationStatus: %d\n", vs
);
763 return (vs
== SecCmsVSGoodSignature
) ? SECSuccess
: SECFailure
;
766 if (publickey
!= NULL
)
767 SECKEY_DestroyPublicKey (publickey
);
769 dprintf("verificationStatus2: %d\n", vs
);
770 signerinfo
->verificationStatus
= vs
;
772 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE
);
777 SecCmsSignerInfoVerifyUnAuthAttrs(SecCmsSignerInfoRef signerinfo
) {
778 return SecCmsSignerInfoVerifyUnAuthAttrsWithPolicy(signerinfo
, NULL
);
782 SecCmsSignerInfoVerifyUnAuthAttrsWithPolicy(SecCmsSignerInfoRef signerinfo
,CFTypeRef timeStampPolicy
)
785 unAuthAttr is an array of attributes; we expect to
786 see just one: the timestamp blob. If we have an unAuthAttr,
787 but don't see a timestamp, return an error since we have
788 no other cases where this would be present.
791 SecCmsAttribute
*attr
= NULL
;
792 OSStatus status
= SECFailure
;
794 require(signerinfo
, xit
);
795 attr
= SecCmsAttributeArrayFindAttrByOidTag(signerinfo
->unAuthAttr
,
796 SEC_OID_PKCS9_TIMESTAMP_TOKEN
, PR_TRUE
);
799 status
= errSecTimestampMissing
;
803 dprintf("found an id-ct-TSTInfo\n");
804 // Don't check the nonce in this case
805 status
= decodeTimeStampTokenWithPolicy(signerinfo
, timeStampPolicy
, (attr
->values
)[0], &signerinfo
->encDigest
, 0);
811 SecCmsSignerInfoGetEncDigest(SecCmsSignerInfoRef signerinfo
)
813 return &signerinfo
->encDigest
;
816 SecCmsVerificationStatus
817 SecCmsSignerInfoGetVerificationStatus(SecCmsSignerInfoRef signerinfo
)
819 return signerinfo
->verificationStatus
;
823 SecCmsSignerInfoGetDigestAlg(SecCmsSignerInfoRef signerinfo
)
825 return SECOID_FindOID (&(signerinfo
->digestAlg
.algorithm
));
829 SecCmsSignerInfoGetDigestAlgTag(SecCmsSignerInfoRef signerinfo
)
833 algdata
= SECOID_FindOID (&(signerinfo
->digestAlg
.algorithm
));
835 return algdata
->offset
;
837 return SEC_OID_UNKNOWN
;
841 SecCmsSignerInfoGetCertList(SecCmsSignerInfoRef signerinfo
)
843 dprintfRC("SecCmsSignerInfoGetCertList: certList.rc %d\n",
844 (int)CFGetRetainCount(signerinfo
->certList
));
845 return signerinfo
->certList
;
849 SecCmsSignerInfoGetTimestampCertList(SecCmsSignerInfoRef signerinfo
)
851 dprintfRC("SecCmsSignerInfoGetCertList: timestampCertList.rc %d\n",
852 (int)CFGetRetainCount(signerinfo
->timestampCertList
));
853 return signerinfo
->timestampCertList
;
859 SecCmsSignerInfoGetVersion(SecCmsSignerInfoRef signerinfo
)
861 unsigned long version
;
863 /* always take apart the CSSM_DATA */
864 if (SEC_ASN1DecodeInteger(&(signerinfo
->version
), &version
) != SECSuccess
)
871 * SecCmsSignerInfoGetSigningTime - return the signing time,
872 * in UTCTime format, of a CMS signerInfo.
874 * sinfo - signerInfo data for this signer
876 * Returns a pointer to XXXX (what?)
877 * A return value of NULL is an error.
880 SecCmsSignerInfoGetSigningTime(SecCmsSignerInfoRef sinfo
, CFAbsoluteTime
*stime
)
882 SecCmsAttribute
*attr
;
888 if (sinfo
->signingTime
!= 0) {
889 *stime
= sinfo
->signingTime
; /* cached copy */
893 attr
= SecCmsAttributeArrayFindAttrByOidTag(sinfo
->authAttr
, SEC_OID_PKCS9_SIGNING_TIME
, PR_TRUE
);
894 /* XXXX multi-valued attributes NIH */
895 if (attr
== NULL
|| (value
= SecCmsAttributeGetValue(attr
)) == NULL
)
896 return errSecSigningTimeMissing
;
897 if (DER_UTCTimeToCFDate(value
, stime
) != SECSuccess
)
898 return errSecSigningTimeMissing
;
899 sinfo
->signingTime
= *stime
; /* make cached copy */
904 SecCmsSignerInfoGetTimestampTime(SecCmsSignerInfoRef sinfo
, CFAbsoluteTime
*stime
)
906 return SecCmsSignerInfoGetTimestampTimeWithPolicy(sinfo
, NULL
, stime
);
910 SecCmsSignerInfoGetTimestampTimeWithPolicy(SecCmsSignerInfoRef sinfo
, CFTypeRef timeStampPolicy
, CFAbsoluteTime
*stime
)
912 OSStatus status
= paramErr
;
914 require(sinfo
&& stime
, xit
);
916 if (sinfo
->timestampTime
!= 0)
918 *stime
= sinfo
->timestampTime
; /* cached copy */
922 // A bit heavyweight if haven't already called verify
923 status
= SecCmsSignerInfoVerifyUnAuthAttrsWithPolicy(sinfo
,timeStampPolicy
);
924 *stime
= sinfo
->timestampTime
;
931 @abstract Return the data in the signed Codesigning Hash Agility attribute.
932 @param sinfo SignerInfo data for this signer, pointer to a CFDataRef for attribute value
933 @discussion Returns a CFDataRef containing the value of the attribute
934 @result A return value of errSecInternal is an error trying to look up the oid.
935 A status value of success with null result data indicates the attribute was not present.
938 SecCmsSignerInfoGetAppleCodesigningHashAgility(SecCmsSignerInfoRef sinfo
, CFDataRef
*sdata
)
940 SecCmsAttribute
*attr
;
943 if (sinfo
== NULL
|| sdata
== NULL
)
948 if (sinfo
->hashAgilityAttrValue
!= NULL
) {
949 *sdata
= sinfo
->hashAgilityAttrValue
; /* cached copy */
953 attr
= SecCmsAttributeArrayFindAttrByOidTag(sinfo
->authAttr
, SEC_OID_APPLE_HASH_AGILITY
, PR_TRUE
);
955 /* attribute not found */
956 if (attr
== NULL
|| (value
= SecCmsAttributeGetValue(attr
)) == NULL
)
959 sinfo
->hashAgilityAttrValue
= CFDataCreate(NULL
, value
->Data
, value
->Length
); /* make cached copy */
960 if (sinfo
->hashAgilityAttrValue
) {
961 *sdata
= sinfo
->hashAgilityAttrValue
;
964 return errSecAllocate
;
968 * Return the signing cert of a CMS signerInfo.
970 * the certs in the enclosing SignedData must have been imported already
973 SecCmsSignerInfoGetSigningCertificate(SecCmsSignerInfoRef signerinfo
, SecKeychainRef keychainOrArray
)
975 SecCertificateRef cert
;
976 SecCmsSignerIdentifier
*sid
;
978 CSSM_DATA_PTR
*rawCerts
;
980 if (signerinfo
->cert
!= NULL
) {
981 dprintfRC("SecCmsSignerInfoGetSigningCertificate top: cert %p cert.rc %d\n",
982 signerinfo
->cert
, (int)CFGetRetainCount(signerinfo
->cert
));
983 return signerinfo
->cert
;
985 ortn
= SecCmsSignedDataRawCerts(signerinfo
->sigd
, &rawCerts
);
989 dprintf("SecCmsSignerInfoGetSigningCertificate: numRawCerts %d\n",
990 SecCmsArrayCount((void **)rawCerts
));
993 * This cert will also need to be freed, but since we save it
994 * in signerinfo for later, we do not want to destroy it when
995 * we leave this function -- we let the clean-up of the entire
996 * cinfo structure later do the destroy of this cert.
998 sid
= &signerinfo
->signerIdentifier
;
999 switch (sid
->identifierType
) {
1000 case SecCmsSignerIDIssuerSN
:
1001 cert
= CERT_FindCertByIssuerAndSN(keychainOrArray
, rawCerts
, signerinfo
->cmsg
->poolp
,
1002 sid
->id
.issuerAndSN
);
1004 case SecCmsSignerIDSubjectKeyID
:
1005 cert
= CERT_FindCertBySubjectKeyID(keychainOrArray
, rawCerts
, sid
->id
.subjectKeyID
);
1012 /* cert can be NULL at that point */
1013 signerinfo
->cert
= cert
; /* earmark it */
1014 dprintfRC("SecCmsSignerInfoGetSigningCertificate end: certp %p cert.rc %d\n",
1015 signerinfo
->cert
, (int)CFGetRetainCount(signerinfo
->cert
));
1021 * SecCmsSignerInfoGetSignerCommonName - return the common name of the signer
1023 * sinfo - signerInfo data for this signer
1025 * Returns a CFStringRef containing the common name of the signer.
1026 * A return value of NULL is an error.
1029 SecCmsSignerInfoGetSignerCommonName(SecCmsSignerInfoRef sinfo
)
1031 SecCertificateRef signercert
;
1032 CFStringRef commonName
= NULL
;
1034 /* will fail if cert is not verified */
1035 if ((signercert
= SecCmsSignerInfoGetSigningCertificate(sinfo
, NULL
)) == NULL
)
1038 SecCertificateCopyCommonName(signercert
, &commonName
);
1044 * SecCmsSignerInfoGetSignerEmailAddress - return the email address of the signer
1046 * sinfo - signerInfo data for this signer
1048 * Returns a CFStringRef containing the name of the signer.
1049 * A return value of NULL is an error.
1052 SecCmsSignerInfoGetSignerEmailAddress(SecCmsSignerInfoRef sinfo
)
1054 SecCertificateRef signercert
;
1055 CFStringRef emailAddress
= NULL
;
1057 if ((signercert
= SecCmsSignerInfoGetSigningCertificate(sinfo
, NULL
)) == NULL
)
1060 SecCertificateGetEmailAddress(signercert
, &emailAddress
);
1062 return emailAddress
;
1067 * SecCmsSignerInfoAddAuthAttr - add an attribute to the
1068 * authenticated (i.e. signed) attributes of "signerinfo".
1071 SecCmsSignerInfoAddAuthAttr(SecCmsSignerInfoRef signerinfo
, SecCmsAttribute
*attr
)
1073 return SecCmsAttributeArrayAddAttr(signerinfo
->cmsg
->poolp
, &(signerinfo
->authAttr
), attr
);
1077 * SecCmsSignerInfoAddUnauthAttr - add an attribute to the
1078 * unauthenticated attributes of "signerinfo".
1081 SecCmsSignerInfoAddUnauthAttr(SecCmsSignerInfoRef signerinfo
, SecCmsAttribute
*attr
)
1083 return SecCmsAttributeArrayAddAttr(signerinfo
->cmsg
->poolp
, &(signerinfo
->unAuthAttr
), attr
);
1087 * SecCmsSignerInfoAddSigningTime - add the signing time to the
1088 * authenticated (i.e. signed) attributes of "signerinfo".
1090 * This is expected to be included in outgoing signed
1091 * messages for email (S/MIME) but is likely useful in other situations.
1093 * This should only be added once; a second call will do nothing.
1095 * XXX This will probably just shove the current time into "signerinfo"
1096 * but it will not actually get signed until the entire item is
1097 * processed for encoding. Is this (expected to be small) delay okay?
1100 SecCmsSignerInfoAddSigningTime(SecCmsSignerInfoRef signerinfo
, CFAbsoluteTime t
)
1102 SecCmsAttribute
*attr
;
1107 poolp
= signerinfo
->cmsg
->poolp
;
1109 mark
= PORT_ArenaMark(poolp
);
1111 /* create new signing time attribute */
1112 if (DER_CFDateToUTCTime(t
, &stime
) != SECSuccess
)
1115 if ((attr
= SecCmsAttributeCreate(poolp
, SEC_OID_PKCS9_SIGNING_TIME
, &stime
, PR_FALSE
)) == NULL
) {
1116 SECITEM_FreeItem (&stime
, PR_FALSE
);
1120 SECITEM_FreeItem (&stime
, PR_FALSE
);
1122 if (SecCmsSignerInfoAddAuthAttr(signerinfo
, attr
) != SECSuccess
)
1125 PORT_ArenaUnmark (poolp
, mark
);
1130 PORT_ArenaRelease (poolp
, mark
);
1135 * SecCmsSignerInfoAddSMIMECaps - add a SMIMECapabilities attribute to the
1136 * authenticated (i.e. signed) attributes of "signerinfo".
1138 * This is expected to be included in outgoing signed
1139 * messages for email (S/MIME).
1142 SecCmsSignerInfoAddSMIMECaps(SecCmsSignerInfoRef signerinfo
)
1144 SecCmsAttribute
*attr
;
1145 CSSM_DATA_PTR smimecaps
= NULL
;
1149 poolp
= signerinfo
->cmsg
->poolp
;
1151 mark
= PORT_ArenaMark(poolp
);
1153 smimecaps
= SECITEM_AllocItem(poolp
, NULL
, 0);
1154 if (smimecaps
== NULL
)
1157 /* create new signing time attribute */
1159 // @@@ We don't do Fortezza yet.
1160 if (SecSMIMECreateSMIMECapabilities((SecArenaPoolRef
)poolp
, smimecaps
, PR_FALSE
) != SECSuccess
)
1162 if (SecSMIMECreateSMIMECapabilities(poolp
, smimecaps
,
1163 PK11_FortezzaHasKEA(signerinfo
->cert
)) != SECSuccess
)
1167 if ((attr
= SecCmsAttributeCreate(poolp
, SEC_OID_PKCS9_SMIME_CAPABILITIES
, smimecaps
, PR_TRUE
)) == NULL
)
1170 if (SecCmsSignerInfoAddAuthAttr(signerinfo
, attr
) != SECSuccess
)
1173 PORT_ArenaUnmark (poolp
, mark
);
1177 PORT_ArenaRelease (poolp
, mark
);
1182 * SecCmsSignerInfoAddSMIMEEncKeyPrefs - add a SMIMEEncryptionKeyPreferences attribute to the
1183 * authenticated (i.e. signed) attributes of "signerinfo".
1185 * This is expected to be included in outgoing signed messages for email (S/MIME).
1188 SecCmsSignerInfoAddSMIMEEncKeyPrefs(SecCmsSignerInfoRef signerinfo
, SecCertificateRef cert
, SecKeychainRef keychainOrArray
)
1190 SecCmsAttribute
*attr
;
1191 CSSM_DATA_PTR smimeekp
= NULL
;
1198 /* verify this cert for encryption */
1199 policy
= CERT_PolicyForCertUsage(certUsageEmailRecipient
);
1200 if (CERT_VerifyCert(keychainOrArray
, cert
, policy
, CFAbsoluteTimeGetCurrent(), NULL
) != SECSuccess
) {
1207 poolp
= signerinfo
->cmsg
->poolp
;
1208 mark
= PORT_ArenaMark(poolp
);
1210 smimeekp
= SECITEM_AllocItem(poolp
, NULL
, 0);
1211 if (smimeekp
== NULL
)
1214 /* create new signing time attribute */
1215 if (SecSMIMECreateSMIMEEncKeyPrefs((SecArenaPoolRef
)poolp
, smimeekp
, cert
) != SECSuccess
)
1218 if ((attr
= SecCmsAttributeCreate(poolp
, SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE
, smimeekp
, PR_TRUE
)) == NULL
)
1221 if (SecCmsSignerInfoAddAuthAttr(signerinfo
, attr
) != SECSuccess
)
1224 PORT_ArenaUnmark (poolp
, mark
);
1228 PORT_ArenaRelease (poolp
, mark
);
1233 * SecCmsSignerInfoAddMSSMIMEEncKeyPrefs - add a SMIMEEncryptionKeyPreferences attribute to the
1234 * authenticated (i.e. signed) attributes of "signerinfo", using the OID prefered by Microsoft.
1236 * This is expected to be included in outgoing signed messages for email (S/MIME),
1237 * if compatibility with Microsoft mail clients is wanted.
1240 SecCmsSignerInfoAddMSSMIMEEncKeyPrefs(SecCmsSignerInfoRef signerinfo
, SecCertificateRef cert
, SecKeychainRef keychainOrArray
)
1242 SecCmsAttribute
*attr
;
1243 CSSM_DATA_PTR smimeekp
= NULL
;
1250 /* verify this cert for encryption */
1251 policy
= CERT_PolicyForCertUsage(certUsageEmailRecipient
);
1252 if (CERT_VerifyCert(keychainOrArray
, cert
, policy
, CFAbsoluteTimeGetCurrent(), NULL
) != SECSuccess
) {
1259 poolp
= signerinfo
->cmsg
->poolp
;
1260 mark
= PORT_ArenaMark(poolp
);
1262 smimeekp
= SECITEM_AllocItem(poolp
, NULL
, 0);
1263 if (smimeekp
== NULL
)
1266 /* create new signing time attribute */
1267 if (SecSMIMECreateMSSMIMEEncKeyPrefs((SecArenaPoolRef
)poolp
, smimeekp
, cert
) != SECSuccess
)
1270 if ((attr
= SecCmsAttributeCreate(poolp
, SEC_OID_MS_SMIME_ENCRYPTION_KEY_PREFERENCE
, smimeekp
, PR_TRUE
)) == NULL
)
1273 if (SecCmsSignerInfoAddAuthAttr(signerinfo
, attr
) != SECSuccess
)
1276 PORT_ArenaUnmark (poolp
, mark
);
1280 PORT_ArenaRelease (poolp
, mark
);
1285 * SecCmsSignerInfoAddTimeStamp - add time stamp to the
1286 * unauthenticated (i.e. unsigned) attributes of "signerinfo".
1288 * This will initially be used for time stamping signed applications
1289 * by using a Time Stamping Authority. It may also be included in outgoing signed
1290 * messages for email (S/MIME), and may be useful in other situations.
1292 * This should only be added once; a second call will do nothing.
1297 Countersignature attribute values have ASN.1 type Countersignature:
1298 Countersignature ::= SignerInfo
1299 Countersignature values have the same meaning as SignerInfo values
1300 for ordinary signatures, except that:
1301 1. The signedAttributes field MUST NOT contain a content-type
1302 attribute; there is no content type for countersignatures.
1303 2. The signedAttributes field MUST contain a message-digest
1304 attribute if it contains any other attributes.
1305 3. The input to the message-digesting process is the contents octets
1306 of the DER encoding of the signatureValue field of the SignerInfo
1307 value with which the attribute is associated.
1312 @abstract Create a timestamp unsigned attribute with a TimeStampToken.
1316 SecCmsSignerInfoAddTimeStamp(SecCmsSignerInfoRef signerinfo
, CSSM_DATA
*tstoken
)
1318 SecCmsAttribute
*attr
;
1319 PLArenaPool
*poolp
= signerinfo
->cmsg
->poolp
;
1320 void *mark
= PORT_ArenaMark(poolp
);
1322 // We have already encoded this ourselves, so last param is PR_TRUE
1323 if ((attr
= SecCmsAttributeCreate(poolp
, SEC_OID_PKCS9_TIMESTAMP_TOKEN
, tstoken
, PR_TRUE
)) == NULL
)
1326 if (SecCmsSignerInfoAddUnauthAttr(signerinfo
, attr
) != SECSuccess
)
1329 PORT_ArenaUnmark (poolp
, mark
);
1334 PORT_ArenaRelease (poolp
, mark
);
1339 * SecCmsSignerInfoAddCounterSignature - countersign a signerinfo
1341 * 1. digest the DER-encoded signature value of the original signerinfo
1342 * 2. create new signerinfo with correct version, sid, digestAlg
1343 * 3. add message-digest authAttr, but NO content-type
1344 * 4. sign the authAttrs
1345 * 5. DER-encode the new signerInfo
1346 * 6. add the whole thing to original signerInfo's unAuthAttrs
1347 * as a SEC_OID_PKCS9_COUNTER_SIGNATURE attribute
1349 * XXXX give back the new signerinfo?
1352 SecCmsSignerInfoAddCounterSignature(SecCmsSignerInfoRef signerinfo
,
1353 SECOidTag digestalg
, SecIdentityRef identity
)
1361 @abstract Add the Apple Codesigning Hash Agility attribute to the authenticated (i.e. signed) attributes of "signerinfo".
1362 @discussion This is expected to be included in outgoing signed Apple code signatures.
1365 SecCmsSignerInfoAddAppleCodesigningHashAgility(SecCmsSignerInfoRef signerinfo
, CFDataRef attrValue
)
1367 SecCmsAttribute
*attr
;
1368 PLArenaPool
*poolp
= signerinfo
->cmsg
->poolp
;
1369 void *mark
= PORT_ArenaMark(poolp
);
1370 OSStatus status
= SECFailure
;
1372 /* The value is required for this attribute. */
1374 status
= errSecParam
;
1379 * SecCmsAttributeCreate makes a copy of the data in value, so
1380 * we don't need to copy into the CSSM_DATA struct.
1383 value
.Length
= CFDataGetLength(attrValue
);
1384 value
.Data
= (uint8_t *)CFDataGetBytePtr(attrValue
);
1386 if ((attr
= SecCmsAttributeCreate(poolp
,
1387 SEC_OID_APPLE_HASH_AGILITY
,
1389 PR_FALSE
)) == NULL
) {
1390 status
= errSecAllocate
;
1394 if (SecCmsSignerInfoAddAuthAttr(signerinfo
, attr
) != SECSuccess
) {
1395 status
= errSecInternalError
;
1399 PORT_ArenaUnmark(poolp
, mark
);
1403 PORT_ArenaRelease(poolp
, mark
);
1408 * XXXX the following needs to be done in the S/MIME layer code
1409 * after signature of a signerinfo is verified
1412 SecCmsSignerInfoSaveSMIMEProfile(SecCmsSignerInfoRef signerinfo
)
1414 SecCertificateRef cert
= NULL
;
1415 CSSM_DATA_PTR profile
= NULL
;
1416 SecCmsAttribute
*attr
;
1417 CSSM_DATA_PTR utc_stime
= NULL
;
1421 Boolean must_free_cert
= PR_FALSE
;
1423 SecKeychainRef keychainOrArray
;
1425 status
= SecKeychainCopyDefault(&keychainOrArray
);
1427 /* sanity check - see if verification status is ok (unverified does not count...) */
1428 if (signerinfo
->verificationStatus
!= SecCmsVSGoodSignature
)
1431 /* find preferred encryption cert */
1432 if (!SecCmsArrayIsEmpty((void **)signerinfo
->authAttr
) &&
1433 (attr
= SecCmsAttributeArrayFindAttrByOidTag(signerinfo
->authAttr
,
1434 SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE
, PR_TRUE
)) != NULL
)
1435 { /* we have a SMIME_ENCRYPTION_KEY_PREFERENCE attribute! */
1436 ekp
= SecCmsAttributeGetValue(attr
);
1440 /* we assume that all certs coming with the message have been imported to the */
1441 /* temporary database */
1442 cert
= SecSMIMEGetCertFromEncryptionKeyPreference(keychainOrArray
, ekp
);
1445 must_free_cert
= PR_TRUE
;
1449 /* no preferred cert found?
1450 * find the cert the signerinfo is signed with instead */
1451 CFStringRef emailAddress
=NULL
;
1453 cert
= SecCmsSignerInfoGetSigningCertificate(signerinfo
, keychainOrArray
);
1456 if (SecCertificateGetEmailAddress(cert
,&emailAddress
))
1460 /* verify this cert for encryption (has been verified for signing so far) */ /* don't verify this cert for encryption. It may just be a signing cert.
1461 * that's OK, we can still save the S/MIME profile. The encryption cert
1462 * should have already been saved */
1464 if (CERT_VerifyCert(keychainOrArray
, cert
, certUsageEmailRecipient
, CFAbsoluteTimeGetCurrent(), NULL
) != SECSuccess
) {
1466 CERT_DestroyCertificate(cert
);
1471 /* XXX store encryption cert permanently? */
1474 * Remember the current error set because we do not care about
1475 * anything set by the functions we are about to call.
1477 save_error
= PORT_GetError();
1479 if (!SecCmsArrayIsEmpty((void **)signerinfo
->authAttr
)) {
1480 attr
= SecCmsAttributeArrayFindAttrByOidTag(signerinfo
->authAttr
,
1481 SEC_OID_PKCS9_SMIME_CAPABILITIES
,
1483 profile
= SecCmsAttributeGetValue(attr
);
1484 attr
= SecCmsAttributeArrayFindAttrByOidTag(signerinfo
->authAttr
,
1485 SEC_OID_PKCS9_SIGNING_TIME
,
1487 utc_stime
= SecCmsAttributeGetValue(attr
);
1490 rv
= CERT_SaveSMimeProfile (cert
, profile
, utc_stime
);
1492 CERT_DestroyCertificate(cert
);
1495 * Restore the saved error in case the calls above set a new
1496 * one that we do not actually care about.
1498 PORT_SetError (save_error
);
1504 * SecCmsSignerInfoIncludeCerts - set cert chain inclusion mode for this signer
1507 SecCmsSignerInfoIncludeCerts(SecCmsSignerInfoRef signerinfo
, SecCmsCertChainMode cm
, SECCertUsage usage
)
1509 if (signerinfo
->cert
== NULL
)
1512 /* don't leak if we get called twice */
1513 if (signerinfo
->certList
!= NULL
) {
1514 CFRelease(signerinfo
->certList
);
1515 signerinfo
->certList
= NULL
;
1520 signerinfo
->certList
= NULL
;
1522 case SecCmsCMCertOnly
:
1523 signerinfo
->certList
= CERT_CertListFromCert(signerinfo
->cert
);
1525 case SecCmsCMCertChain
:
1526 signerinfo
->certList
= CERT_CertChainFromCert(signerinfo
->cert
, usage
, PR_FALSE
);
1528 case SecCmsCMCertChainWithRoot
:
1529 signerinfo
->certList
= CERT_CertChainFromCert(signerinfo
->cert
, usage
, PR_TRUE
);
1533 if (cm
!= SecCmsCMNone
&& signerinfo
->certList
== NULL
)