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"
44 #include "SecAsn1Item.h"
48 #include <security_asn1/secasn1.h>
49 #include <security_asn1/secerr.h>
50 #include <security_asn1/secport.h>
53 #include <Security/SecKeychain.h>
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 #include <Security/SecBasePriv.h>
63 #include <Security/SecItem.h>
66 #define HIDIGIT(v) (((v) / 10) + '0')
67 #define LODIGIT(v) (((v) % 10) + '0')
69 #define ISDIGIT(dig) (((dig) >= '0') && ((dig) <= '9'))
70 #define CAPTURE(var,p,label) \
72 if (!ISDIGIT((p)[0]) || !ISDIGIT((p)[1])) goto label; \
73 (var) = ((p)[0] - '0') * 10 + ((p)[1] - '0'); \
78 DER_UTCTimeToCFDate(const SecAsn1Item
* utcTime
, CFAbsoluteTime
*date
)
80 char *string
= (char *)utcTime
->Data
;
81 int year
, month
, mday
, hour
, minute
, second
, hourOff
, minOff
;
83 /* Verify time is formatted properly and capture information */
87 CAPTURE(year
,string
+0,loser
);
89 /* ASSUME that year # is in the 2000's, not the 1900's */
94 CAPTURE(month
,string
+2,loser
);
95 if ((month
== 0) || (month
> 12)) goto loser
;
96 CAPTURE(mday
,string
+4,loser
);
97 if ((mday
== 0) || (mday
> 31)) goto loser
;
98 CAPTURE(hour
,string
+6,loser
);
99 if (hour
> 23) goto loser
;
100 CAPTURE(minute
,string
+8,loser
);
101 if (minute
> 59) goto loser
;
102 if (ISDIGIT(string
[10])) {
103 CAPTURE(second
,string
+10,loser
);
104 if (second
> 59) goto loser
;
107 if (string
[10] == '+') {
108 CAPTURE(hourOff
,string
+11,loser
);
109 if (hourOff
> 23) goto loser
;
110 CAPTURE(minOff
,string
+13,loser
);
111 if (minOff
> 59) goto loser
;
112 } else if (string
[10] == '-') {
113 CAPTURE(hourOff
,string
+11,loser
);
114 if (hourOff
> 23) goto loser
;
116 CAPTURE(minOff
,string
+13,loser
);
117 if (minOff
> 59) goto loser
;
119 } else if (string
[10] != 'Z') {
123 if (hourOff
== 0 && minOff
== 0) {
124 *date
= CFAbsoluteTimeForGregorianZuluMoment(year
, month
, mday
, hour
, minute
, second
);
126 CFTimeZoneRef tz
= CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorDefault
, (hourOff
* 60 + minOff
) * 60);
127 *date
= CFAbsoluteTimeForGregorianMoment(tz
, year
, month
, mday
, hour
, minute
, second
);
138 DER_CFDateToUTCTime(CFAbsoluteTime date
, SecAsn1Item
* utcTime
)
142 utcTime
->Length
= 13;
143 utcTime
->Data
= d
= PORT_Alloc(13);
147 __block
int year
= 0, month
= 0, day
= 0, hour
= 0, minute
= 0, second
= 0;
149 SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar
) {
150 result
= CFCalendarDecomposeAbsoluteTime(zuluCalendar
, date
, "yMdHms", &year
, &month
, &day
, &hour
, &minute
, &second
);
155 /* UTC time does not handle the years before 1950 */
159 /* remove the century since it's added to the year by the
160 CFAbsoluteTimeGetGregorianDate routine, but is not needed for UTC time */
163 d
[0] = HIDIGIT(year
);
164 d
[1] = LODIGIT(year
);
165 d
[2] = HIDIGIT(month
);
166 d
[3] = LODIGIT(month
);
169 d
[6] = HIDIGIT(hour
);
170 d
[7] = LODIGIT(hour
);
171 d
[8] = HIDIGIT(minute
);
172 d
[9] = LODIGIT(minute
);
173 d
[10] = HIDIGIT(second
);
174 d
[11] = LODIGIT(second
);
179 /* =============================================================================
183 nss_cmssignerinfo_create(SecCmsSignedDataRef sigd
, SecCmsSignerIDSelector type
, SecCertificateRef cert
, const SecAsn1Item
*subjKeyID
, SecPublicKeyRef pubKey
, SecPrivateKeyRef signingKey
, SECOidTag digestalgtag
);
186 SecCmsSignerInfoCreateWithSubjKeyID(SecCmsSignedDataRef sigd
, const SecAsn1Item
*subjKeyID
, SecPublicKeyRef pubKey
, SecPrivateKeyRef signingKey
, SECOidTag digestalgtag
)
188 return nss_cmssignerinfo_create(sigd
, SecCmsSignerIDSubjectKeyID
, NULL
, subjKeyID
, pubKey
, signingKey
, digestalgtag
);
192 SecCmsSignerInfoCreate(SecCmsSignedDataRef sigd
, SecIdentityRef identity
, SECOidTag digestalgtag
)
194 SecCmsSignerInfoRef signerInfo
= NULL
;
195 SecCertificateRef cert
= NULL
;
196 SecPrivateKeyRef signingKey
= NULL
;
197 CFDictionaryRef keyAttrs
= NULL
;
199 if (SecIdentityCopyCertificate(identity
, &cert
))
201 if (SecIdentityCopyPrivateKey(identity
, &signingKey
))
204 /* In some situations, the "Private Key" in the identity is actually a public key. Check. */
205 keyAttrs
= SecKeyCopyAttributes(signingKey
);
208 CFTypeRef
class = CFDictionaryGetValue(keyAttrs
, kSecAttrKeyClass
);
209 if (!class || (CFGetTypeID(class) != CFStringGetTypeID()) || !CFEqual(class, kSecAttrKeyClassPrivate
)) {
213 signerInfo
= nss_cmssignerinfo_create(sigd
, SecCmsSignerIDIssuerSN
, cert
, NULL
, NULL
, signingKey
, digestalgtag
);
219 CFRelease(signingKey
);
227 nss_cmssignerinfo_create(SecCmsSignedDataRef sigd
, SecCmsSignerIDSelector type
, SecCertificateRef cert
, const SecAsn1Item
*subjKeyID
, SecPublicKeyRef pubKey
, SecPrivateKeyRef signingKey
, SECOidTag digestalgtag
)
230 SecCmsSignerInfoRef signerinfo
;
234 poolp
= sigd
->contentInfo
.cmsg
->poolp
;
236 mark
= PORT_ArenaMark(poolp
);
238 signerinfo
= (SecCmsSignerInfoRef
)PORT_ArenaZAlloc(poolp
, sizeof(SecCmsSignerInfo
));
239 if (signerinfo
== NULL
) {
240 PORT_ArenaRelease(poolp
, mark
);
245 signerinfo
->signedData
= sigd
;
248 case SecCmsSignerIDIssuerSN
:
249 signerinfo
->signerIdentifier
.identifierType
= SecCmsSignerIDIssuerSN
;
250 if ((signerinfo
->cert
= CERT_DupCertificate(cert
)) == NULL
)
252 if ((signerinfo
->signerIdentifier
.id
.issuerAndSN
= CERT_GetCertIssuerAndSN(poolp
, cert
)) == NULL
)
255 case SecCmsSignerIDSubjectKeyID
:
256 signerinfo
->signerIdentifier
.identifierType
= SecCmsSignerIDSubjectKeyID
;
257 PORT_Assert(subjKeyID
);
260 signerinfo
->signerIdentifier
.id
.subjectKeyID
= PORT_ArenaNew(poolp
, SecAsn1Item
);
261 if (SECITEM_CopyItem(poolp
, signerinfo
->signerIdentifier
.id
.subjectKeyID
,
265 signerinfo
->pubKey
= SECKEY_CopyPublicKey(pubKey
);
266 if (!signerinfo
->pubKey
)
276 signerinfo
->signingKey
= SECKEY_CopyPrivateKey(signingKey
);
277 if (!signerinfo
->signingKey
)
280 /* set version right now */
281 version
= SEC_CMS_SIGNER_INFO_VERSION_ISSUERSN
;
282 /* RFC2630 5.3 "version is the syntax version number. If the .... " */
283 if (signerinfo
->signerIdentifier
.identifierType
== SecCmsSignerIDSubjectKeyID
)
284 version
= SEC_CMS_SIGNER_INFO_VERSION_SUBJKEY
;
285 (void)SEC_ASN1EncodeInteger(poolp
, &(signerinfo
->version
), (long)version
);
287 if (SECOID_SetAlgorithmID(poolp
, &signerinfo
->digestAlg
, digestalgtag
, NULL
) != SECSuccess
)
290 if (SecCmsSignedDataAddSignerInfo(sigd
, signerinfo
))
293 PORT_ArenaUnmark(poolp
, mark
);
297 PORT_ArenaRelease(poolp
, mark
);
302 * SecCmsSignerInfoDestroy - destroy a SignerInfo data structure
305 SecCmsSignerInfoDestroy(SecCmsSignerInfoRef si
)
307 if (si
->cert
!= NULL
) {
308 CERT_DestroyCertificate(si
->cert
);
311 if (si
->certList
!= NULL
) {
312 CFRelease(si
->certList
);
315 if (si
->hashAgilityAttrValue
!= NULL
) {
316 CFRelease(si
->hashAgilityAttrValue
);
319 if (si
->hashAgilityV2AttrValues
!= NULL
) {
320 CFRelease(si
->hashAgilityV2AttrValues
);
323 /* XXX storage ??? */
326 static SecAsn1AlgId
SecCertificateGetPublicKeyAlgorithmID(SecCertificateRef cert
)
328 const DERAlgorithmId
*length_data_swapped
= SecCertificateGetPublicKeyAlgorithm(cert
);
329 SecAsn1AlgId temp
= {
330 { length_data_swapped
->oid
.length
, length_data_swapped
->oid
.data
},
331 { length_data_swapped
->params
.length
, length_data_swapped
->params
.data
} };
337 * SecCmsSignerInfoSign - sign something
341 SecCmsSignerInfoSign(SecCmsSignerInfoRef signerinfo
, SecAsn1Item
* digest
, SecAsn1Item
* contentType
)
343 SecCertificateRef cert
;
344 SecPrivateKeyRef privkey
= NULL
;
345 SECOidTag digestalgtag
;
346 SECOidTag pubkAlgTag
;
347 SecAsn1Item signature
= { 0 };
349 PLArenaPool
*poolp
, *tmppoolp
= NULL
;
350 const SECAlgorithmID
*algID
= NULL
;
351 //CERTSubjectPublicKeyInfo *spki;
353 PORT_Assert (digest
!= NULL
);
355 poolp
= signerinfo
->signedData
->contentInfo
.cmsg
->poolp
;
359 switch (signerinfo
->signerIdentifier
.identifierType
) {
360 case SecCmsSignerIDIssuerSN
:
361 privkey
= signerinfo
->signingKey
;
362 signerinfo
->signingKey
= NULL
;
363 cert
= signerinfo
->cert
;
365 if (SecCertificateGetAlgorithmID(cert
,&algID
)) {
366 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM
);
370 _algID
= SecCertificateGetPublicKeyAlgorithmID(cert
);
374 case SecCmsSignerIDSubjectKeyID
:
375 privkey
= signerinfo
->signingKey
;
376 signerinfo
->signingKey
= NULL
;
378 spki
= SECKEY_CreateSubjectPublicKeyInfo(signerinfo
->pubKey
);
379 SECKEY_DestroyPublicKey(signerinfo
->pubKey
);
380 signerinfo
->pubKey
= NULL
;
381 SECOID_CopyAlgorithmID(NULL
, &freeAlgID
, &spki
->algorithm
);
382 SECKEY_DestroySubjectPublicKeyInfo(spki
);
386 if (SecKeyGetAlgorithmID(signerinfo
->pubKey
,&algID
)) {
387 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM
);
392 CFRelease(signerinfo
->pubKey
);
393 signerinfo
->pubKey
= NULL
;
396 PORT_SetError(SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE
);
399 digestalgtag
= SecCmsSignerInfoGetDigestAlgTag(signerinfo
);
400 pubkAlgTag
= SECOID_GetAlgorithmTag(algID
);
402 /* we no longer support signing with MD5 */
403 if (digestalgtag
== SEC_OID_MD5
) {
404 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM
);
409 if (signerinfo
->signerIdentifier
.identifierType
== SecCmsSignerIDSubjectKeyID
) {
410 SECOID_DestroyAlgorithmID(&freeAlgID
, PR_FALSE
);
415 /* Fortezza MISSI have weird signature formats.
416 * Map them to standard DSA formats
418 pubkAlgTag
= PK11_FortezzaMapSig(pubkAlgTag
);
421 if (signerinfo
->authAttr
!= NULL
) {
422 SecAsn1Item encoded_attrs
;
424 /* find and fill in the message digest attribute. */
425 rv
= SecCmsAttributeArraySetAttr(poolp
, &(signerinfo
->authAttr
),
426 SEC_OID_PKCS9_MESSAGE_DIGEST
, digest
, PR_FALSE
);
427 if (rv
!= SECSuccess
)
430 if (contentType
!= NULL
) {
431 /* if the caller wants us to, find and fill in the content type attribute. */
432 rv
= SecCmsAttributeArraySetAttr(poolp
, &(signerinfo
->authAttr
),
433 SEC_OID_PKCS9_CONTENT_TYPE
, contentType
, PR_FALSE
);
434 if (rv
!= SECSuccess
)
438 if ((tmppoolp
= PORT_NewArena (1024)) == NULL
) {
439 PORT_SetError(SEC_ERROR_NO_MEMORY
);
444 * Before encoding, reorder the attributes so that when they
445 * are encoded, they will be conforming DER, which is required
446 * to have a specific order and that is what must be used for
447 * the hash/signature. We do this here, rather than building
448 * it into EncodeAttributes, because we do not want to do
449 * such reordering on incoming messages (which also uses
450 * EncodeAttributes) or our old signatures (and other "broken"
451 * implementations) will not verify. So, we want to guarantee
452 * that we send out good DER encodings of attributes, but not
453 * to expect to receive them.
455 if (SecCmsAttributeArrayReorder(signerinfo
->authAttr
) != SECSuccess
)
458 encoded_attrs
.Data
= NULL
;
459 encoded_attrs
.Length
= 0;
460 if (SecCmsAttributeArrayEncode(tmppoolp
, &(signerinfo
->authAttr
),
461 &encoded_attrs
) == NULL
)
465 rv
= SEC_SignData(&signature
, encoded_attrs
.Data
, encoded_attrs
.Length
,
466 privkey
, digestalgtag
, pubkAlgTag
);
468 signature
.Length
= SecKeyGetSize(privkey
, kSecKeySignatureSize
);
469 signature
.Data
= PORT_ZAlloc(signature
.Length
);
470 if (!signature
.Data
) {
471 signature
.Length
= 0;
474 rv
= SecKeyDigestAndSign(privkey
, &signerinfo
->digestAlg
, encoded_attrs
.Data
, encoded_attrs
.Length
, signature
.Data
, &signature
.Length
);
476 PORT_ZFree(signature
.Data
, signature
.Length
);
477 signature
.Length
= 0;
481 PORT_FreeArena(tmppoolp
, PR_FALSE
); /* awkward memory management :-( */
484 signature
.Length
= SecKeyGetSize(privkey
, kSecKeySignatureSize
);
485 signature
.Data
= PORT_ZAlloc(signature
.Length
);
486 if (!signature
.Data
) {
487 signature
.Length
= 0;
490 rv
= SecKeySignDigest(privkey
, &signerinfo
->digestAlg
, digest
->Data
, digest
->Length
,
491 signature
.Data
, &signature
.Length
);
493 PORT_ZFree(signature
.Data
, signature
.Length
);
494 signature
.Length
= 0;
497 SECKEY_DestroyPrivateKey(privkey
);
500 if (rv
!= SECSuccess
)
503 if (SECITEM_CopyItem(poolp
, &(signerinfo
->encDigest
), &signature
)
507 SECITEM_FreeItem(&signature
, PR_FALSE
);
509 if (SECOID_SetAlgorithmID(poolp
, &(signerinfo
->digestEncAlg
), pubkAlgTag
,
516 if (signature
.Length
!= 0)
517 SECITEM_FreeItem (&signature
, PR_FALSE
);
519 SECKEY_DestroyPrivateKey(privkey
);
521 PORT_FreeArena(tmppoolp
, PR_FALSE
);
527 SecCmsSignerInfoCopySigningCertificates(SecCmsSignerInfoRef signerinfo
)
529 CFMutableArrayRef certs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
530 SecAsn1Item
**cert_datas
= signerinfo
->signedData
->rawCerts
;
531 SecAsn1Item
*cert_data
;
532 if (cert_datas
) while ((cert_data
= *cert_datas
) != NULL
) {
533 SecCertificateRef cert
= SecCertificateCreateWithBytes(NULL
, cert_data
->Data
, cert_data
->Length
);
535 switch (signerinfo
->signerIdentifier
.identifierType
) {
536 case SecCmsSignerIDIssuerSN
:
537 if (CERT_CheckIssuerAndSerial(cert
,
538 &(signerinfo
->signerIdentifier
.id
.issuerAndSN
->derIssuer
),
539 &(signerinfo
->signerIdentifier
.id
.issuerAndSN
->serialNumber
)))
540 CFArrayInsertValueAtIndex(certs
, 0, cert
);
542 CFArrayAppendValue(certs
, cert
);
544 case SecCmsSignerIDSubjectKeyID
:
546 CFDataRef cert_keyid
= SecCertificateGetSubjectKeyID(cert
);
547 SecAsn1Item
*tbf_keyid
= signerinfo
->signerIdentifier
.id
.subjectKeyID
;
548 if (tbf_keyid
->Length
== (size_t)CFDataGetLength(cert_keyid
) &&
549 !memcmp(tbf_keyid
->Data
, CFDataGetBytePtr(cert_keyid
), tbf_keyid
->Length
))
550 CFArrayInsertValueAtIndex(certs
, 0, cert
);
552 CFArrayAppendValue(certs
, cert
);
561 if ((CFArrayGetCount(certs
) == 0) &&
562 (signerinfo
->signerIdentifier
.identifierType
== SecCmsSignerIDIssuerSN
))
564 SecCertificateRef cert
= CERT_FindCertificateByIssuerAndSN(signerinfo
->signedData
->certs
, signerinfo
->signerIdentifier
.id
.issuerAndSN
);
566 CFArrayAppendValue(certs
, cert
);
571 if ((CFArrayGetCount(certs
) == 0) &&
572 (signerinfo
->signerIdentifier
.identifierType
== SecCmsSignerIDSubjectKeyID
))
574 SecCertificateRef cert
= CERT_FindCertificateBySubjectKeyID(signerinfo
->signedData
->certs
,
575 signerinfo
->signerIdentifier
.id
.subjectKeyID
);
577 CFArrayAppendValue(certs
, cert
);
586 SecCmsSignerInfoVerifyCertificate(SecCmsSignerInfoRef signerinfo
, SecKeychainRef keychainOrArray
,
587 CFTypeRef policies
, SecTrustRef
*trustRef
)
589 CFAbsoluteTime stime
;
593 SecCertificateRef cert
;
595 if ((cert
= SecCmsSignerInfoGetSigningCertificate(signerinfo
, keychainOrArray
)) == NULL
) {
599 if ((certs
= SecCmsSignerInfoCopySigningCertificates(signerinfo
)) == NULL
) {
601 signerinfo
->verificationStatus
= SecCmsVSSigningCertNotFound
;
605 * Get and convert the signing time; if available, it will be used
606 * both on the cert verification and for importing the sender
609 if (SecCmsSignerInfoGetSigningTime(signerinfo
, &stime
) != SECSuccess
)
610 stime
= CFAbsoluteTimeGetCurrent();
613 rv
= CERT_VerifyCert(keychainOrArray
, cert
, policies
, stime
, trustRef
);
615 rv
= CERT_VerifyCert(keychainOrArray
, certs
, policies
, stime
, trustRef
);
620 if (PORT_GetError() == SEC_ERROR_UNTRUSTED_CERT
)
622 /* Signature or digest level verificationStatus errors should supercede certificate level errors, so only change the verificationStatus if the status was GoodSignature. */
624 #warning DEBUG - SecCmsSignerInfoVerifyCertificate trusts everything!
625 if (signerinfo
->verificationStatus
== SecCmsVSGoodSignature
) {
626 syslog(LOG_ERR
, "SecCmsSignerInfoVerifyCertificate ignoring SEC_ERROR_UNTRUSTED_CERT");
630 if (signerinfo
->verificationStatus
== SecCmsVSGoodSignature
)
631 signerinfo
->verificationStatus
= SecCmsVSSigningCertNotTrusted
;
640 * SecCmsSignerInfoVerify - verify the signature of a single SignerInfo
642 * Just verifies the signature. The assumption is that verification of the certificate
646 SecCmsSignerInfoVerify(SecCmsSignerInfoRef signerinfo
, SecAsn1Item
* digest
, SecAsn1Item
* contentType
)
648 SecPublicKeyRef publickey
= NULL
;
649 SecCmsAttribute
*attr
;
650 SecAsn1Item encoded_attrs
;
651 SecCertificateRef cert
;
652 SecCmsVerificationStatus vs
= SecCmsVSUnverified
;
655 if (signerinfo
== NULL
)
658 /* SecCmsSignerInfoGetSigningCertificate will fail if 2nd parm is NULL and */
659 /* cert has not been verified */
660 if ((cert
= SecCmsSignerInfoGetSigningCertificate(signerinfo
, NULL
)) == NULL
) {
661 vs
= SecCmsVSSigningCertNotFound
;
666 if (SecCertificateCopyPublicKey(cert
, &publickey
)) {
667 vs
= SecCmsVSProcessingError
;
671 publickey
= SecCertificateCopyPublicKey(cert
);
672 if (publickey
== NULL
)
676 if (!SecCmsArrayIsEmpty((void **)signerinfo
->authAttr
)) {
681 * RFC2630 sez that if there are any authenticated attributes,
682 * then there must be one for content type which matches the
683 * content type of the content being signed, and there must
684 * be one for message digest which matches our message digest.
685 * So check these things first.
687 if ((attr
= SecCmsAttributeArrayFindAttrByOidTag(signerinfo
->authAttr
,
688 SEC_OID_PKCS9_CONTENT_TYPE
, PR_TRUE
)) == NULL
)
690 vs
= SecCmsVSMalformedSignature
;
694 if (SecCmsAttributeCompareValue(attr
, contentType
) == PR_FALSE
) {
695 vs
= SecCmsVSMalformedSignature
;
703 if ((attr
= SecCmsAttributeArrayFindAttrByOidTag(signerinfo
->authAttr
, SEC_OID_PKCS9_MESSAGE_DIGEST
, PR_TRUE
)) == NULL
)
705 vs
= SecCmsVSMalformedSignature
;
708 if (SecCmsAttributeCompareValue(attr
, digest
) == PR_FALSE
) {
709 vs
= SecCmsVSDigestMismatch
;
713 if ((poolp
= PORT_NewArena (1024)) == NULL
) {
714 vs
= SecCmsVSProcessingError
;
721 * The signature is based on a digest of the DER-encoded authenticated
722 * attributes. So, first we encode and then we digest/verify.
723 * we trust the decoder to have the attributes in the right (sorted) order
725 encoded_attrs
.Data
= NULL
;
726 encoded_attrs
.Length
= 0;
728 if (SecCmsAttributeArrayEncode(poolp
, &(signerinfo
->authAttr
), &encoded_attrs
) == NULL
||
729 encoded_attrs
.Data
== NULL
|| encoded_attrs
.Length
== 0)
731 vs
= SecCmsVSProcessingError
;
734 if (errSecSuccess
== SecKeyDigestAndVerify(publickey
, &signerinfo
->digestAlg
, encoded_attrs
.Data
, encoded_attrs
.Length
, signerinfo
->encDigest
.Data
, signerinfo
->encDigest
.Length
))
735 vs
= SecCmsVSGoodSignature
;
737 vs
= SecCmsVSBadSignature
;
739 PORT_FreeArena(poolp
, PR_FALSE
); /* awkward memory management :-( */
744 /* No authenticated attributes. The signature is based on the plain message digest. */
745 sig
= &(signerinfo
->encDigest
);
746 if (sig
->Length
== 0)
749 if (SecKeyVerifyDigest(publickey
, &signerinfo
->digestAlg
, digest
->Data
, digest
->Length
, sig
->Data
, sig
->Length
))
750 vs
= SecCmsVSBadSignature
;
752 vs
= SecCmsVSGoodSignature
;
755 if (vs
== SecCmsVSBadSignature
) {
757 * XXX Change the generic error into our specific one, because
758 * in that case we get a better explanation out of the Security
759 * Advisor. This is really a bug in our error strings (the
760 * "generic" error has a lousy/wrong message associated with it
761 * which assumes the signature verification was done for the
762 * purposes of checking the issuer signature on a certificate)
763 * but this is at least an easy workaround and/or in the
764 * Security Advisor, which specifically checks for the error
765 * SEC_ERROR_PKCS7_BAD_SIGNATURE and gives more explanation
766 * in that case but does not similarly check for
767 * SEC_ERROR_BAD_SIGNATURE. It probably should, but then would
768 * probably say the wrong thing in the case that it *was* the
769 * certificate signature check that failed during the cert
770 * verification done above. Our error handling is really a mess.
772 if (PORT_GetError() == SEC_ERROR_BAD_SIGNATURE
)
773 PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE
);
776 if (publickey
!= NULL
)
777 CFRelease(publickey
);
779 signerinfo
->verificationStatus
= vs
;
781 return (vs
== SecCmsVSGoodSignature
) ? SECSuccess
: SECFailure
;
784 if (publickey
!= NULL
)
785 SECKEY_DestroyPublicKey (publickey
);
787 signerinfo
->verificationStatus
= vs
;
789 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE
);
793 SecCmsVerificationStatus
794 SecCmsSignerInfoGetVerificationStatus(SecCmsSignerInfoRef signerinfo
)
796 return signerinfo
->verificationStatus
;
800 SecCmsSignerInfoGetDigestAlg(SecCmsSignerInfoRef signerinfo
)
802 return SECOID_FindOID (&(signerinfo
->digestAlg
.algorithm
));
806 SecCmsSignerInfoGetDigestAlgTag(SecCmsSignerInfoRef signerinfo
)
810 algdata
= SECOID_FindOID (&(signerinfo
->digestAlg
.algorithm
));
812 return algdata
->offset
;
814 return SEC_OID_UNKNOWN
;
818 SecCmsSignerInfoGetCertList(SecCmsSignerInfoRef signerinfo
)
820 return signerinfo
->certList
;
824 SecCmsSignerInfoGetVersion(SecCmsSignerInfoRef signerinfo
)
826 unsigned long version
;
828 /* always take apart the SecAsn1Item */
829 if (SEC_ASN1DecodeInteger(&(signerinfo
->version
), &version
) != SECSuccess
)
836 * SecCmsSignerInfoGetSigningTime - return the signing time,
837 * in UTCTime format, of a CMS signerInfo.
839 * sinfo - signerInfo data for this signer
841 * Returns a pointer to XXXX (what?)
842 * A return value of NULL is an error.
845 SecCmsSignerInfoGetSigningTime(SecCmsSignerInfoRef sinfo
, CFAbsoluteTime
*stime
)
847 SecCmsAttribute
*attr
;
853 if (sinfo
->signingTime
!= 0) {
854 *stime
= sinfo
->signingTime
; /* cached copy */
858 attr
= SecCmsAttributeArrayFindAttrByOidTag(sinfo
->authAttr
, SEC_OID_PKCS9_SIGNING_TIME
, PR_TRUE
);
859 /* XXXX multi-valued attributes NIH */
860 if (attr
== NULL
|| (value
= SecCmsAttributeGetValue(attr
)) == NULL
)
862 if (DER_UTCTimeToCFDate(value
, stime
) != SECSuccess
)
864 sinfo
->signingTime
= *stime
; /* make cached copy */
870 @abstract Return the data in the signed Codesigning Hash Agility attribute.
871 @param sinfo SignerInfo data for this signer, pointer to a CFDataRef for attribute value
872 @discussion Returns a CFDataRef containing the value of the attribute
873 @result A return value of errSecInternal is an error trying to look up the oid.
874 A status value of success with null result data indicates the attribute was not present.
877 SecCmsSignerInfoGetAppleCodesigningHashAgility(SecCmsSignerInfoRef sinfo
, CFDataRef
*sdata
)
879 SecCmsAttribute
*attr
;
882 if (sinfo
== NULL
|| sdata
== NULL
)
887 if (sinfo
->hashAgilityAttrValue
!= NULL
) {
888 *sdata
= sinfo
->hashAgilityAttrValue
; /* cached copy */
892 attr
= SecCmsAttributeArrayFindAttrByOidTag(sinfo
->authAttr
, SEC_OID_APPLE_HASH_AGILITY
, PR_TRUE
);
894 /* attribute not found */
895 if (attr
== NULL
|| (value
= SecCmsAttributeGetValue(attr
)) == NULL
)
898 sinfo
->hashAgilityAttrValue
= CFDataCreate(NULL
, value
->Data
, value
->Length
); /* make cached copy */
899 if (sinfo
->hashAgilityAttrValue
) {
900 *sdata
= sinfo
->hashAgilityAttrValue
;
903 return errSecAllocate
;
906 /* AgileHash ::= SEQUENCE {
907 hashType OBJECT IDENTIFIER,
908 hashValues OCTET STRING }
911 SecAsn1Item digestOID
;
912 SecAsn1Item digestValue
;
915 static const SecAsn1Template CMSAppleAgileHashTemplate
[] = {
917 0, NULL
, sizeof(CMSAppleAgileHash
) },
918 { SEC_ASN1_OBJECT_ID
,
919 offsetof(CMSAppleAgileHash
, digestOID
), },
920 { SEC_ASN1_OCTET_STRING
,
921 offsetof(CMSAppleAgileHash
, digestValue
), },
925 static OSStatus
CMSAddAgileHashToDictionary(CFMutableDictionaryRef dictionary
, SecAsn1Item
*DERAgileHash
) {
926 PLArenaPool
*tmppoolp
= NULL
;
927 OSStatus status
= errSecSuccess
;
928 CMSAppleAgileHash agileHash
;
929 CFDataRef digestValue
= NULL
;
930 CFNumberRef digestTag
= NULL
;
932 tmppoolp
= PORT_NewArena(1024);
933 if (tmppoolp
== NULL
) {
934 return errSecAllocate
;
937 if ((status
= SEC_ASN1DecodeItem(tmppoolp
, &agileHash
, CMSAppleAgileHashTemplate
, DERAgileHash
)) != errSecSuccess
) {
941 int64_t tag
= SECOID_FindOIDTag(&agileHash
.digestOID
);
942 digestTag
= CFNumberCreate(NULL
, kCFNumberSInt64Type
, &tag
);
943 digestValue
= CFDataCreate(NULL
, agileHash
.digestValue
.Data
, agileHash
.digestValue
.Length
);
944 CFDictionaryAddValue(dictionary
, digestTag
, digestValue
);
947 CFReleaseNull(digestValue
);
948 CFReleaseNull(digestTag
);
950 PORT_FreeArena(tmppoolp
, PR_FALSE
);
957 @abstract Return the data in the signed Codesigning Hash Agility V2 attribute.
958 @param sinfo SignerInfo data for this signer, pointer to a CFDictionaryRef for attribute values
959 @discussion Returns a CFDictionaryRef containing the values of the attribute
960 @result A return value of errSecInternal is an error trying to look up the oid.
961 A status value of success with null result data indicates the attribute was not present.
964 SecCmsSignerInfoGetAppleCodesigningHashAgilityV2(SecCmsSignerInfoRef sinfo
, CFDictionaryRef
*sdict
)
966 SecCmsAttribute
*attr
;
968 if (sinfo
== NULL
|| sdict
== NULL
) {
974 if (sinfo
->hashAgilityV2AttrValues
!= NULL
) {
975 *sdict
= sinfo
->hashAgilityV2AttrValues
; /* cached copy */
979 attr
= SecCmsAttributeArrayFindAttrByOidTag(sinfo
->authAttr
, SEC_OID_APPLE_HASH_AGILITY_V2
, PR_TRUE
);
981 /* attribute not found */
986 /* attrValues SET OF AttributeValue
987 * AttributeValue ::= ANY
989 SecAsn1Item
**values
= attr
->values
;
990 if (values
== NULL
) { /* There must be values */
994 CFMutableDictionaryRef agileHashValues
= CFDictionaryCreateMutable(NULL
, SecCmsArrayCount((void **)values
),
995 &kCFTypeDictionaryKeyCallBacks
,
996 &kCFTypeDictionaryValueCallBacks
);
997 while (*values
!= NULL
) {
998 (void)CMSAddAgileHashToDictionary(agileHashValues
, *values
++);
1000 if (CFDictionaryGetCount(agileHashValues
) != SecCmsArrayCount((void **)attr
->values
)) {
1001 CFReleaseNull(agileHashValues
);
1002 return errSecDecode
;
1005 sinfo
->hashAgilityV2AttrValues
= agileHashValues
; /* make cached copy */
1006 if (sinfo
->hashAgilityV2AttrValues
) {
1007 *sdict
= sinfo
->hashAgilityV2AttrValues
;
1010 return errSecAllocate
;
1014 * Return the signing cert of a CMS signerInfo.
1016 * the certs in the enclosing SignedData must have been imported already
1019 SecCmsSignerInfoGetSigningCertificate(SecCmsSignerInfoRef signerinfo
, SecKeychainRef keychainOrArray
)
1021 SecCertificateRef cert
= NULL
;
1023 if (signerinfo
->cert
!= NULL
)
1024 return signerinfo
->cert
;
1026 /* @@@ Make sure we search though all the certs in the cms message itself as well, it's silly
1027 to require them to be added to a keychain first. */
1030 SecCmsSignerIdentifier
*sid
;
1033 * This cert will also need to be freed, but since we save it
1034 * in signerinfo for later, we do not want to destroy it when
1035 * we leave this function -- we let the clean-up of the entire
1036 * cinfo structure later do the destroy of this cert.
1038 sid
= &signerinfo
->signerIdentifier
;
1039 switch (sid
->identifierType
) {
1040 case SecCmsSignerIDIssuerSN
:
1041 cert
= CERT_FindCertByIssuerAndSN(keychainOrArray
, sid
->id
.issuerAndSN
);
1043 case SecCmsSignerIDSubjectKeyID
:
1044 cert
= CERT_FindCertBySubjectKeyID(keychainOrArray
, sid
->id
.subjectKeyID
);
1051 /* cert can be NULL at that point */
1052 signerinfo
->cert
= cert
; /* earmark it */
1054 SecAsn1Item
**cert_datas
= signerinfo
->signedData
->rawCerts
;
1055 SecAsn1Item
*cert_data
;
1056 if (cert_datas
) while ((cert_data
= *cert_datas
) != NULL
) {
1057 cert
= SecCertificateCreateWithBytes(NULL
, cert_data
->Data
, cert_data
->Length
);
1059 switch (signerinfo
->signerIdentifier
.identifierType
) {
1060 case SecCmsSignerIDIssuerSN
:
1061 if (CERT_CheckIssuerAndSerial(cert
,
1062 &(signerinfo
->signerIdentifier
.id
.issuerAndSN
->derIssuer
),
1063 &(signerinfo
->signerIdentifier
.id
.issuerAndSN
->serialNumber
)))
1064 signerinfo
->cert
= cert
;
1066 case SecCmsSignerIDSubjectKeyID
: {
1067 CFDataRef cert_keyid
= SecCertificateGetSubjectKeyID(cert
);
1068 SecAsn1Item
*tbf_keyid
= signerinfo
->signerIdentifier
.id
.subjectKeyID
;
1069 if (tbf_keyid
->Length
== (size_t)CFDataGetLength(cert_keyid
) &&
1070 !memcmp(tbf_keyid
->Data
, CFDataGetBytePtr(cert_keyid
), tbf_keyid
->Length
))
1071 signerinfo
->cert
= cert
;
1074 if (signerinfo
->cert
)
1076 CFReleaseNull(cert
);
1081 if (!signerinfo
->cert
&& (signerinfo
->signerIdentifier
.identifierType
== SecCmsSignerIDIssuerSN
)) {
1082 cert
= CERT_FindCertificateByIssuerAndSN(signerinfo
->signedData
->certs
, signerinfo
->signerIdentifier
.id
.issuerAndSN
);
1083 signerinfo
->cert
= cert
;
1085 if (!signerinfo
->cert
&& (signerinfo
->signerIdentifier
.identifierType
== SecCmsSignerIDSubjectKeyID
)) {
1086 cert
= CERT_FindCertificateBySubjectKeyID(signerinfo
->signedData
->certs
, signerinfo
->signerIdentifier
.id
.subjectKeyID
);
1087 signerinfo
->cert
= cert
;
1096 * SecCmsSignerInfoGetSignerCommonName - return the common name of the signer
1098 * sinfo - signerInfo data for this signer
1100 * Returns a CFStringRef containing the common name of the signer.
1101 * A return value of NULL is an error.
1104 SecCmsSignerInfoGetSignerCommonName(SecCmsSignerInfoRef sinfo
)
1106 SecCertificateRef signercert
;
1107 CFStringRef commonName
= NULL
;
1109 /* will fail if cert is not verified */
1110 if ((signercert
= SecCmsSignerInfoGetSigningCertificate(sinfo
, NULL
)) == NULL
)
1114 SecCertificateGetCommonName(signercert
, &commonName
);
1116 CFArrayRef commonNames
= SecCertificateCopyCommonNames(signercert
);
1118 /* SecCertificateCopyCommonNames doesn't return empty arrays */
1119 commonName
= (CFStringRef
)CFArrayGetValueAtIndex(commonNames
, CFArrayGetCount(commonNames
) - 1);
1120 CFRetain(commonName
);
1121 CFRelease(commonNames
);
1129 * SecCmsSignerInfoGetSignerEmailAddress - return the email address of the signer
1131 * sinfo - signerInfo data for this signer
1133 * Returns a CFStringRef containing the name of the signer.
1134 * A return value of NULL is an error.
1137 SecCmsSignerInfoGetSignerEmailAddress(SecCmsSignerInfoRef sinfo
)
1139 SecCertificateRef signercert
;
1140 CFStringRef emailAddress
= NULL
;
1142 if ((signercert
= SecCmsSignerInfoGetSigningCertificate(sinfo
, NULL
)) == NULL
)
1146 SecCertificateGetEmailAddress(signercert
, &emailAddress
);
1148 CFArrayRef names
= SecCertificateCopyRFC822Names(signercert
);
1150 if (CFArrayGetCount(names
) > 0)
1151 emailAddress
= (CFStringRef
)CFArrayGetValueAtIndex(names
, 0);
1153 CFRetain(emailAddress
);
1157 return emailAddress
;
1162 * SecCmsSignerInfoAddAuthAttr - add an attribute to the
1163 * authenticated (i.e. signed) attributes of "signerinfo".
1166 SecCmsSignerInfoAddAuthAttr(SecCmsSignerInfoRef signerinfo
, SecCmsAttribute
*attr
)
1168 return SecCmsAttributeArrayAddAttr(signerinfo
->signedData
->contentInfo
.cmsg
->poolp
, &(signerinfo
->authAttr
), attr
);
1172 * SecCmsSignerInfoAddUnauthAttr - add an attribute to the
1173 * unauthenticated attributes of "signerinfo".
1176 SecCmsSignerInfoAddUnauthAttr(SecCmsSignerInfoRef signerinfo
, SecCmsAttribute
*attr
)
1178 return SecCmsAttributeArrayAddAttr(signerinfo
->signedData
->contentInfo
.cmsg
->poolp
, &(signerinfo
->unAuthAttr
), attr
);
1182 * SecCmsSignerInfoAddSigningTime - add the signing time to the
1183 * authenticated (i.e. signed) attributes of "signerinfo".
1185 * This is expected to be included in outgoing signed
1186 * messages for email (S/MIME) but is likely useful in other situations.
1188 * This should only be added once; a second call will do nothing.
1190 * XXX This will probably just shove the current time into "signerinfo"
1191 * but it will not actually get signed until the entire item is
1192 * processed for encoding. Is this (expected to be small) delay okay?
1195 SecCmsSignerInfoAddSigningTime(SecCmsSignerInfoRef signerinfo
, CFAbsoluteTime t
)
1197 SecCmsAttribute
*attr
;
1202 poolp
= signerinfo
->signedData
->contentInfo
.cmsg
->poolp
;
1204 mark
= PORT_ArenaMark(poolp
);
1206 /* create new signing time attribute */
1207 if (DER_CFDateToUTCTime(t
, &stime
) != SECSuccess
)
1210 if ((attr
= SecCmsAttributeCreate(poolp
, SEC_OID_PKCS9_SIGNING_TIME
, &stime
, PR_FALSE
)) == NULL
) {
1211 SECITEM_FreeItem (&stime
, PR_FALSE
);
1215 SECITEM_FreeItem (&stime
, PR_FALSE
);
1217 if (SecCmsSignerInfoAddAuthAttr(signerinfo
, attr
) != SECSuccess
)
1220 PORT_ArenaUnmark (poolp
, mark
);
1225 PORT_ArenaRelease (poolp
, mark
);
1230 * SecCmsSignerInfoAddSMIMECaps - add a SMIMECapabilities attribute to the
1231 * authenticated (i.e. signed) attributes of "signerinfo".
1233 * This is expected to be included in outgoing signed
1234 * messages for email (S/MIME).
1237 SecCmsSignerInfoAddSMIMECaps(SecCmsSignerInfoRef signerinfo
)
1239 SecCmsAttribute
*attr
;
1240 SecAsn1Item
* smimecaps
= NULL
;
1244 poolp
= signerinfo
->signedData
->contentInfo
.cmsg
->poolp
;
1246 mark
= PORT_ArenaMark(poolp
);
1248 smimecaps
= SECITEM_AllocItem(poolp
, NULL
, 0);
1249 if (smimecaps
== NULL
)
1252 /* create new signing time attribute */
1254 // @@@ We don't do Fortezza yet.
1255 if (SecSMIMECreateSMIMECapabilities(poolp
, smimecaps
, PR_FALSE
) != SECSuccess
)
1257 if (SecSMIMECreateSMIMECapabilities(poolp
, smimecaps
,
1258 PK11_FortezzaHasKEA(signerinfo
->cert
)) != SECSuccess
)
1262 if ((attr
= SecCmsAttributeCreate(poolp
, SEC_OID_PKCS9_SMIME_CAPABILITIES
, smimecaps
, PR_TRUE
)) == NULL
)
1265 if (SecCmsSignerInfoAddAuthAttr(signerinfo
, attr
) != SECSuccess
)
1268 PORT_ArenaUnmark (poolp
, mark
);
1272 PORT_ArenaRelease (poolp
, mark
);
1277 * SecCmsSignerInfoAddSMIMEEncKeyPrefs - add a SMIMEEncryptionKeyPreferences attribute to the
1278 * authenticated (i.e. signed) attributes of "signerinfo".
1280 * This is expected to be included in outgoing signed messages for email (S/MIME).
1283 SecCmsSignerInfoAddSMIMEEncKeyPrefs(SecCmsSignerInfoRef signerinfo
, SecCertificateRef cert
, SecKeychainRef keychainOrArray
)
1285 SecCmsAttribute
*attr
;
1286 SecAsn1Item
* smimeekp
= NULL
;
1293 /* verify this cert for encryption */
1294 policy
= CERT_PolicyForCertUsage(certUsageEmailRecipient
);
1295 if (CERT_VerifyCert(keychainOrArray
, cert
, policy
, CFAbsoluteTimeGetCurrent(), NULL
) != SECSuccess
) {
1302 poolp
= signerinfo
->signedData
->contentInfo
.cmsg
->poolp
;
1303 mark
= PORT_ArenaMark(poolp
);
1305 smimeekp
= SECITEM_AllocItem(poolp
, NULL
, 0);
1306 if (smimeekp
== NULL
)
1309 /* create new signing time attribute */
1310 if (SecSMIMECreateSMIMEEncKeyPrefs(poolp
, smimeekp
, cert
) != SECSuccess
)
1313 if ((attr
= SecCmsAttributeCreate(poolp
, SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE
, smimeekp
, PR_TRUE
)) == NULL
)
1316 if (SecCmsSignerInfoAddAuthAttr(signerinfo
, attr
) != SECSuccess
)
1319 PORT_ArenaUnmark (poolp
, mark
);
1323 PORT_ArenaRelease (poolp
, mark
);
1328 * SecCmsSignerInfoAddMSSMIMEEncKeyPrefs - add a SMIMEEncryptionKeyPreferences attribute to the
1329 * authenticated (i.e. signed) attributes of "signerinfo", using the OID preferred by Microsoft.
1331 * This is expected to be included in outgoing signed messages for email (S/MIME),
1332 * if compatibility with Microsoft mail clients is wanted.
1335 SecCmsSignerInfoAddMSSMIMEEncKeyPrefs(SecCmsSignerInfoRef signerinfo
, SecCertificateRef cert
, SecKeychainRef keychainOrArray
)
1337 SecCmsAttribute
*attr
;
1338 SecAsn1Item
* smimeekp
= NULL
;
1345 /* verify this cert for encryption */
1346 policy
= CERT_PolicyForCertUsage(certUsageEmailRecipient
);
1347 if (CERT_VerifyCert(keychainOrArray
, cert
, policy
, CFAbsoluteTimeGetCurrent(), NULL
) != SECSuccess
) {
1354 poolp
= signerinfo
->signedData
->contentInfo
.cmsg
->poolp
;
1355 mark
= PORT_ArenaMark(poolp
);
1357 smimeekp
= SECITEM_AllocItem(poolp
, NULL
, 0);
1358 if (smimeekp
== NULL
)
1361 /* create new signing time attribute */
1362 if (SecSMIMECreateMSSMIMEEncKeyPrefs(poolp
, smimeekp
, cert
) != SECSuccess
)
1365 if ((attr
= SecCmsAttributeCreate(poolp
, SEC_OID_MS_SMIME_ENCRYPTION_KEY_PREFERENCE
, smimeekp
, PR_TRUE
)) == NULL
)
1368 if (SecCmsSignerInfoAddAuthAttr(signerinfo
, attr
) != SECSuccess
)
1371 PORT_ArenaUnmark (poolp
, mark
);
1375 PORT_ArenaRelease (poolp
, mark
);
1380 * SecCmsSignerInfoAddCounterSignature - countersign a signerinfo
1382 * 1. digest the DER-encoded signature value of the original signerinfo
1383 * 2. create new signerinfo with correct version, sid, digestAlg
1384 * 3. add message-digest authAttr, but NO content-type
1385 * 4. sign the authAttrs
1386 * 5. DER-encode the new signerInfo
1387 * 6. add the whole thing to original signerInfo's unAuthAttrs
1388 * as a SEC_OID_PKCS9_COUNTER_SIGNATURE attribute
1390 * XXXX give back the new signerinfo?
1393 SecCmsSignerInfoAddCounterSignature(SecCmsSignerInfoRef signerinfo
,
1394 SECOidTag digestalg
, SecIdentityRef identity
)
1402 @abstract Add the Apple Codesigning Hash Agility attribute to the authenticated (i.e. signed) attributes of "signerinfo".
1403 @discussion This is expected to be included in outgoing Apple code signatures.
1406 SecCmsSignerInfoAddAppleCodesigningHashAgility(SecCmsSignerInfoRef signerinfo
, CFDataRef attrValue
)
1408 SecCmsAttribute
*attr
;
1409 PLArenaPool
*poolp
= signerinfo
->signedData
->contentInfo
.cmsg
->poolp
;
1410 void *mark
= PORT_ArenaMark(poolp
);
1411 OSStatus status
= SECFailure
;
1413 /* The value is required for this attribute. */
1415 status
= errSecParam
;
1420 * SecCmsAttributeCreate makes a copy of the data in value, so
1421 * we don't need to copy into the CSSM_DATA struct.
1424 value
.Length
= CFDataGetLength(attrValue
);
1425 value
.Data
= (uint8_t *)CFDataGetBytePtr(attrValue
);
1427 if ((attr
= SecCmsAttributeCreate(poolp
,
1428 SEC_OID_APPLE_HASH_AGILITY
,
1430 PR_FALSE
)) == NULL
) {
1431 status
= errSecAllocate
;
1435 if (SecCmsSignerInfoAddAuthAttr(signerinfo
, attr
) != SECSuccess
) {
1436 status
= errSecInternal
;
1440 PORT_ArenaUnmark(poolp
, mark
);
1444 PORT_ArenaRelease(poolp
, mark
);
1448 static OSStatus
CMSAddAgileHashToAttribute(PLArenaPool
*poolp
, SecCmsAttribute
*attr
, CFNumberRef cftag
, CFDataRef value
) {
1449 PLArenaPool
*tmppoolp
= NULL
;
1451 SECOidData
*digestOid
= NULL
;
1452 CMSAppleAgileHash agileHash
;
1453 SecAsn1Item attrValue
= { .Data
= NULL
, .Length
= 0 };
1454 OSStatus status
= errSecSuccess
;
1456 memset(&agileHash
, 0, sizeof(agileHash
));
1458 if(!CFNumberGetValue(cftag
, kCFNumberSInt64Type
, &tag
)) {
1461 digestOid
= SECOID_FindOIDByTag((SECOidTag
)tag
);
1463 agileHash
.digestValue
.Data
= (uint8_t *)CFDataGetBytePtr(value
);
1464 agileHash
.digestValue
.Length
= CFDataGetLength(value
);
1465 agileHash
.digestOID
.Data
= digestOid
->oid
.Data
;
1466 agileHash
.digestOID
.Length
= digestOid
->oid
.Length
;
1468 tmppoolp
= PORT_NewArena(1024);
1469 if (tmppoolp
== NULL
) {
1470 return errSecAllocate
;
1473 if (SEC_ASN1EncodeItem(tmppoolp
, &attrValue
, &agileHash
, CMSAppleAgileHashTemplate
) == NULL
) {
1474 status
= errSecParam
;
1478 status
= SecCmsAttributeAddValue(poolp
, attr
, &attrValue
);
1482 PORT_FreeArena(tmppoolp
, PR_FALSE
);
1489 @abstract Add the Apple Codesigning Hash Agility attribute to the authenticated (i.e. signed) attributes of "signerinfo".
1490 @discussion This is expected to be included in outgoing Apple code signatures.
1493 SecCmsSignerInfoAddAppleCodesigningHashAgilityV2(SecCmsSignerInfoRef signerinfo
, CFDictionaryRef attrValues
)
1495 __block SecCmsAttribute
*attr
;
1496 __block PLArenaPool
*poolp
= signerinfo
->signedData
->contentInfo
.cmsg
->poolp
;
1497 void *mark
= PORT_ArenaMark(poolp
);
1498 OSStatus status
= SECFailure
;
1500 /* The value is required for this attribute. */
1502 status
= errSecParam
;
1506 if ((attr
= SecCmsAttributeCreate(poolp
, SEC_OID_APPLE_HASH_AGILITY_V2
,
1507 NULL
, PR_TRUE
)) == NULL
) {
1508 status
= errSecAllocate
;
1512 CFDictionaryForEach(attrValues
, ^(const void *key
, const void *value
) {
1513 if (!isNumber(key
) || !isData(value
)) {
1516 (void)CMSAddAgileHashToAttribute(poolp
, attr
, (CFNumberRef
)key
, (CFDataRef
)value
);
1519 if (SecCmsSignerInfoAddAuthAttr(signerinfo
, attr
) != SECSuccess
) {
1520 status
= errSecInternal
;
1524 PORT_ArenaUnmark(poolp
, mark
);
1528 PORT_ArenaRelease(poolp
, mark
);
1532 SecCertificateRef
SecCmsSignerInfoCopyCertFromEncryptionKeyPreference(SecCmsSignerInfoRef signerinfo
) {
1533 SecCertificateRef cert
= NULL
;
1534 SecCmsAttribute
*attr
;
1537 /* sanity check - see if verification status is ok (unverified does not count...) */
1538 if (signerinfo
->verificationStatus
!= SecCmsVSGoodSignature
)
1541 /* Prep the rawCerts */
1542 SecAsn1Item
**rawCerts
= NULL
;
1543 if (signerinfo
->signedData
) {
1544 rawCerts
= signerinfo
->signedData
->rawCerts
;
1547 /* find preferred encryption cert */
1548 if (!SecCmsArrayIsEmpty((void **)signerinfo
->authAttr
) &&
1549 (attr
= SecCmsAttributeArrayFindAttrByOidTag(signerinfo
->authAttr
,
1550 SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE
, PR_TRUE
)) != NULL
)
1551 { /* we have a SMIME_ENCRYPTION_KEY_PREFERENCE attribute! Find the cert. */
1552 ekp
= SecCmsAttributeGetValue(attr
);
1555 cert
= SecSMIMEGetCertFromEncryptionKeyPreference(rawCerts
, ekp
);
1557 if (cert
) return cert
;
1559 if (!SecCmsArrayIsEmpty((void **)signerinfo
->authAttr
) &&
1560 (attr
= SecCmsAttributeArrayFindAttrByOidTag(signerinfo
->authAttr
,
1561 SEC_OID_MS_SMIME_ENCRYPTION_KEY_PREFERENCE
, PR_TRUE
)) != NULL
)
1562 { /* we have a MS_SMIME_ENCRYPTION_KEY_PREFERENCE attribute! Find the cert. */
1563 ekp
= SecCmsAttributeGetValue(attr
);
1566 cert
= SecSMIMEGetCertFromEncryptionKeyPreference(rawCerts
, ekp
);
1572 * XXXX the following needs to be done in the S/MIME layer code
1573 * after signature of a signerinfo is verified
1576 SecCmsSignerInfoSaveSMIMEProfile(SecCmsSignerInfoRef signerinfo
)
1578 return -4 /*unImp*/;
1582 * SecCmsSignerInfoIncludeCerts - set cert chain inclusion mode for this signer
1585 SecCmsSignerInfoIncludeCerts(SecCmsSignerInfoRef signerinfo
, SecCmsCertChainMode cm
, SECCertUsage usage
)
1587 if (signerinfo
->cert
== NULL
)
1590 /* don't leak if we get called twice */
1591 if (signerinfo
->certList
!= NULL
) {
1592 CFRelease(signerinfo
->certList
);
1593 signerinfo
->certList
= NULL
;
1598 signerinfo
->certList
= NULL
;
1600 case SecCmsCMCertOnly
:
1601 signerinfo
->certList
= CERT_CertListFromCert(signerinfo
->cert
);
1603 case SecCmsCMCertChain
:
1604 signerinfo
->certList
= CERT_CertChainFromCert(signerinfo
->cert
, usage
, PR_FALSE
);
1606 case SecCmsCMCertChainWithRoot
:
1607 signerinfo
->certList
= CERT_CertChainFromCert(signerinfo
->cert
, usage
, PR_TRUE
);
1611 if (cm
!= SecCmsCMNone
&& signerinfo
->certList
== NULL
)