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>
65 #include <libDER/asn1Types.h>
68 #define HIDIGIT(v) (((v) / 10) + '0')
69 #define LODIGIT(v) (((v) % 10) + '0')
71 #define ISDIGIT(dig) (((dig) >= '0') && ((dig) <= '9'))
72 #define CAPTURE(var,p,label) \
74 if (!ISDIGIT((p)[0]) || !ISDIGIT((p)[1])) goto label; \
75 (var) = ((p)[0] - '0') * 10 + ((p)[1] - '0'); \
80 DER_UTCTimeToCFDate(const SecAsn1Item
* utcTime
, CFAbsoluteTime
*date
)
82 CFErrorRef error
= NULL
;
83 /* <rdar://problem/55316705> CMS attributes don't correctly encode/decode times (always use UTCTime) */
84 CFAbsoluteTime result
= SecAbsoluteTimeFromDateContentWithError(ASN1_UTC_TIME
, utcTime
->Data
, utcTime
->Length
, &error
);
97 DER_CFDateToUTCTime(CFAbsoluteTime date
, SecAsn1Item
* utcTime
)
101 utcTime
->Length
= 13;
102 utcTime
->Data
= d
= PORT_Alloc(13);
103 if (!utcTime
->Data
) {
107 __block
int year
= 0, month
= 0, day
= 0, hour
= 0, minute
= 0, second
= 0;
109 SecCFCalendarDoWithZuluCalendar(^(CFCalendarRef zuluCalendar
) {
110 result
= CFCalendarDecomposeAbsoluteTime(zuluCalendar
, date
, "yMdHms", &year
, &month
, &day
, &hour
, &minute
, &second
);
116 /* UTC time does not handle the years before 1950 or after 2049 */
117 /* <rdar://problem/55316705> CMS attributes don't correctly encode/decode times (always use UTCTime) */
118 if (year
< 1950 || year
> 2049) {
122 /* remove the century since it's added to the year by the
123 CFAbsoluteTimeGetGregorianDate routine, but is not needed for UTC time */
126 d
[0] = HIDIGIT(year
);
127 d
[1] = LODIGIT(year
);
128 d
[2] = HIDIGIT(month
);
129 d
[3] = LODIGIT(month
);
132 d
[6] = HIDIGIT(hour
);
133 d
[7] = LODIGIT(hour
);
134 d
[8] = HIDIGIT(minute
);
135 d
[9] = LODIGIT(minute
);
136 d
[10] = HIDIGIT(second
);
137 d
[11] = LODIGIT(second
);
142 /* =============================================================================
146 nss_cmssignerinfo_create(SecCmsSignedDataRef sigd
, SecCmsSignerIDSelector type
, SecCertificateRef cert
, const SecAsn1Item
*subjKeyID
, SecPublicKeyRef pubKey
, SecPrivateKeyRef signingKey
, SECOidTag digestalgtag
);
149 SecCmsSignerInfoCreateWithSubjKeyID(SecCmsSignedDataRef sigd
, const SecAsn1Item
*subjKeyID
, SecPublicKeyRef pubKey
, SecPrivateKeyRef signingKey
, SECOidTag digestalgtag
)
151 return nss_cmssignerinfo_create(sigd
, SecCmsSignerIDSubjectKeyID
, NULL
, subjKeyID
, pubKey
, signingKey
, digestalgtag
);
155 SecCmsSignerInfoCreate(SecCmsSignedDataRef sigd
, SecIdentityRef identity
, SECOidTag digestalgtag
)
157 SecCmsSignerInfoRef signerInfo
= NULL
;
158 SecCertificateRef cert
= NULL
;
159 SecPrivateKeyRef signingKey
= NULL
;
160 CFDictionaryRef keyAttrs
= NULL
;
162 if (SecIdentityCopyCertificate(identity
, &cert
))
164 if (SecIdentityCopyPrivateKey(identity
, &signingKey
))
167 /* In some situations, the "Private Key" in the identity is actually a public key. Check. */
168 keyAttrs
= SecKeyCopyAttributes(signingKey
);
171 CFTypeRef
class = CFDictionaryGetValue(keyAttrs
, kSecAttrKeyClass
);
172 if (!class || (CFGetTypeID(class) != CFStringGetTypeID()) || !CFEqual(class, kSecAttrKeyClassPrivate
)) {
176 signerInfo
= nss_cmssignerinfo_create(sigd
, SecCmsSignerIDIssuerSN
, cert
, NULL
, NULL
, signingKey
, digestalgtag
);
182 CFRelease(signingKey
);
190 nss_cmssignerinfo_create(SecCmsSignedDataRef sigd
, SecCmsSignerIDSelector type
, SecCertificateRef cert
, const SecAsn1Item
*subjKeyID
, SecPublicKeyRef pubKey
, SecPrivateKeyRef signingKey
, SECOidTag digestalgtag
)
193 SecCmsSignerInfoRef signerinfo
;
197 poolp
= sigd
->contentInfo
.cmsg
->poolp
;
199 mark
= PORT_ArenaMark(poolp
);
201 signerinfo
= (SecCmsSignerInfoRef
)PORT_ArenaZAlloc(poolp
, sizeof(SecCmsSignerInfo
));
202 if (signerinfo
== NULL
) {
203 PORT_ArenaRelease(poolp
, mark
);
208 signerinfo
->signedData
= sigd
;
211 case SecCmsSignerIDIssuerSN
:
212 signerinfo
->signerIdentifier
.identifierType
= SecCmsSignerIDIssuerSN
;
213 if ((signerinfo
->cert
= CERT_DupCertificate(cert
)) == NULL
)
215 if ((signerinfo
->signerIdentifier
.id
.issuerAndSN
= CERT_GetCertIssuerAndSN(poolp
, cert
)) == NULL
)
218 case SecCmsSignerIDSubjectKeyID
:
219 signerinfo
->signerIdentifier
.identifierType
= SecCmsSignerIDSubjectKeyID
;
220 PORT_Assert(subjKeyID
);
223 signerinfo
->signerIdentifier
.id
.subjectKeyID
= PORT_ArenaNew(poolp
, SecAsn1Item
);
224 if (SECITEM_CopyItem(poolp
, signerinfo
->signerIdentifier
.id
.subjectKeyID
,
228 signerinfo
->pubKey
= SECKEY_CopyPublicKey(pubKey
);
229 if (!signerinfo
->pubKey
)
239 signerinfo
->signingKey
= SECKEY_CopyPrivateKey(signingKey
);
240 if (!signerinfo
->signingKey
)
243 /* set version right now */
244 version
= SEC_CMS_SIGNER_INFO_VERSION_ISSUERSN
;
245 /* RFC2630 5.3 "version is the syntax version number. If the .... " */
246 if (signerinfo
->signerIdentifier
.identifierType
== SecCmsSignerIDSubjectKeyID
)
247 version
= SEC_CMS_SIGNER_INFO_VERSION_SUBJKEY
;
248 (void)SEC_ASN1EncodeInteger(poolp
, &(signerinfo
->version
), (long)version
);
250 if (SECOID_SetAlgorithmID(poolp
, &signerinfo
->digestAlg
, digestalgtag
, NULL
) != SECSuccess
)
253 if (SecCmsSignedDataAddSignerInfo(sigd
, signerinfo
))
256 PORT_ArenaUnmark(poolp
, mark
);
260 PORT_ArenaRelease(poolp
, mark
);
265 * SecCmsSignerInfoDestroy - destroy a SignerInfo data structure
268 SecCmsSignerInfoDestroy(SecCmsSignerInfoRef si
)
270 if (si
->cert
!= NULL
) {
271 CERT_DestroyCertificate(si
->cert
);
274 if (si
->certList
!= NULL
) {
275 CFRelease(si
->certList
);
278 if (si
->hashAgilityAttrValue
!= NULL
) {
279 CFRelease(si
->hashAgilityAttrValue
);
282 if (si
->hashAgilityV2AttrValues
!= NULL
) {
283 CFRelease(si
->hashAgilityV2AttrValues
);
286 /* XXX storage ??? */
289 static SecAsn1AlgId
SecCertificateGetPublicKeyAlgorithmID(SecCertificateRef cert
)
291 const DERAlgorithmId
*length_data_swapped
= SecCertificateGetPublicKeyAlgorithm(cert
);
292 SecAsn1AlgId temp
= {
293 { length_data_swapped
->oid
.length
, length_data_swapped
->oid
.data
},
294 { length_data_swapped
->params
.length
, length_data_swapped
->params
.data
} };
300 * SecCmsSignerInfoSign - sign something
304 SecCmsSignerInfoSign(SecCmsSignerInfoRef signerinfo
, SecAsn1Item
* digest
, SecAsn1Item
* contentType
)
306 SecCertificateRef cert
;
307 SecPrivateKeyRef privkey
= NULL
;
308 SECOidTag digestalgtag
;
309 SECOidTag pubkAlgTag
;
310 SecAsn1Item signature
= { 0 };
312 PLArenaPool
*poolp
, *tmppoolp
= NULL
;
313 const SECAlgorithmID
*algID
= NULL
;
314 //CERTSubjectPublicKeyInfo *spki;
316 PORT_Assert (digest
!= NULL
);
318 poolp
= signerinfo
->signedData
->contentInfo
.cmsg
->poolp
;
322 switch (signerinfo
->signerIdentifier
.identifierType
) {
323 case SecCmsSignerIDIssuerSN
:
324 privkey
= signerinfo
->signingKey
;
325 signerinfo
->signingKey
= NULL
;
326 cert
= signerinfo
->cert
;
328 if (SecCertificateGetAlgorithmID(cert
,&algID
)) {
329 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM
);
333 _algID
= SecCertificateGetPublicKeyAlgorithmID(cert
);
337 case SecCmsSignerIDSubjectKeyID
:
338 privkey
= signerinfo
->signingKey
;
339 signerinfo
->signingKey
= NULL
;
341 spki
= SECKEY_CreateSubjectPublicKeyInfo(signerinfo
->pubKey
);
342 SECKEY_DestroyPublicKey(signerinfo
->pubKey
);
343 signerinfo
->pubKey
= NULL
;
344 SECOID_CopyAlgorithmID(NULL
, &freeAlgID
, &spki
->algorithm
);
345 SECKEY_DestroySubjectPublicKeyInfo(spki
);
349 if (SecKeyGetAlgorithmID(signerinfo
->pubKey
,&algID
)) {
350 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM
);
355 CFRelease(signerinfo
->pubKey
);
356 signerinfo
->pubKey
= NULL
;
359 PORT_SetError(SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE
);
362 digestalgtag
= SecCmsSignerInfoGetDigestAlgTag(signerinfo
);
363 pubkAlgTag
= SECOID_GetAlgorithmTag(algID
);
365 /* we no longer support signing with MD5 */
366 if (digestalgtag
== SEC_OID_MD5
) {
367 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM
);
372 if (signerinfo
->signerIdentifier
.identifierType
== SecCmsSignerIDSubjectKeyID
) {
373 SECOID_DestroyAlgorithmID(&freeAlgID
, PR_FALSE
);
378 /* Fortezza MISSI have weird signature formats.
379 * Map them to standard DSA formats
381 pubkAlgTag
= PK11_FortezzaMapSig(pubkAlgTag
);
384 if (signerinfo
->authAttr
!= NULL
) {
385 SecAsn1Item encoded_attrs
;
387 /* find and fill in the message digest attribute. */
388 rv
= SecCmsAttributeArraySetAttr(poolp
, &(signerinfo
->authAttr
),
389 SEC_OID_PKCS9_MESSAGE_DIGEST
, digest
, PR_FALSE
);
390 if (rv
!= SECSuccess
)
393 if (contentType
!= NULL
) {
394 /* if the caller wants us to, find and fill in the content type attribute. */
395 rv
= SecCmsAttributeArraySetAttr(poolp
, &(signerinfo
->authAttr
),
396 SEC_OID_PKCS9_CONTENT_TYPE
, contentType
, PR_FALSE
);
397 if (rv
!= SECSuccess
)
401 if ((tmppoolp
= PORT_NewArena (1024)) == NULL
) {
402 PORT_SetError(SEC_ERROR_NO_MEMORY
);
407 * Before encoding, reorder the attributes so that when they
408 * are encoded, they will be conforming DER, which is required
409 * to have a specific order and that is what must be used for
410 * the hash/signature. We do this here, rather than building
411 * it into EncodeAttributes, because we do not want to do
412 * such reordering on incoming messages (which also uses
413 * EncodeAttributes) or our old signatures (and other "broken"
414 * implementations) will not verify. So, we want to guarantee
415 * that we send out good DER encodings of attributes, but not
416 * to expect to receive them.
418 if (SecCmsAttributeArrayReorder(signerinfo
->authAttr
) != SECSuccess
)
421 encoded_attrs
.Data
= NULL
;
422 encoded_attrs
.Length
= 0;
423 if (SecCmsAttributeArrayEncode(tmppoolp
, &(signerinfo
->authAttr
),
424 &encoded_attrs
) == NULL
)
428 rv
= SEC_SignData(&signature
, encoded_attrs
.Data
, encoded_attrs
.Length
,
429 privkey
, digestalgtag
, pubkAlgTag
);
431 signature
.Length
= SecKeyGetSize(privkey
, kSecKeySignatureSize
);
432 signature
.Data
= PORT_ZAlloc(signature
.Length
);
433 if (!signature
.Data
) {
434 signature
.Length
= 0;
437 rv
= SecKeyDigestAndSign(privkey
, &signerinfo
->digestAlg
, encoded_attrs
.Data
, encoded_attrs
.Length
, signature
.Data
, &signature
.Length
);
439 PORT_ZFree(signature
.Data
, signature
.Length
);
440 signature
.Length
= 0;
444 PORT_FreeArena(tmppoolp
, PR_FALSE
); /* awkward memory management :-( */
447 signature
.Length
= SecKeyGetSize(privkey
, kSecKeySignatureSize
);
448 signature
.Data
= PORT_ZAlloc(signature
.Length
);
449 if (!signature
.Data
) {
450 signature
.Length
= 0;
453 rv
= SecKeySignDigest(privkey
, &signerinfo
->digestAlg
, digest
->Data
, digest
->Length
,
454 signature
.Data
, &signature
.Length
);
456 PORT_ZFree(signature
.Data
, signature
.Length
);
457 signature
.Length
= 0;
460 SECKEY_DestroyPrivateKey(privkey
);
463 if (rv
!= SECSuccess
)
466 if (SECITEM_CopyItem(poolp
, &(signerinfo
->encDigest
), &signature
)
470 SECITEM_FreeItem(&signature
, PR_FALSE
);
472 if (SECOID_SetAlgorithmID(poolp
, &(signerinfo
->digestEncAlg
), pubkAlgTag
,
479 if (signature
.Length
!= 0)
480 SECITEM_FreeItem (&signature
, PR_FALSE
);
482 SECKEY_DestroyPrivateKey(privkey
);
484 PORT_FreeArena(tmppoolp
, PR_FALSE
);
490 SecCmsSignerInfoCopySigningCertificates(SecCmsSignerInfoRef signerinfo
)
492 CFMutableArrayRef certs
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
493 SecAsn1Item
**cert_datas
= signerinfo
->signedData
->rawCerts
;
494 SecAsn1Item
*cert_data
;
495 if (cert_datas
) while ((cert_data
= *cert_datas
) != NULL
) {
496 SecCertificateRef cert
= SecCertificateCreateWithBytes(NULL
, cert_data
->Data
, cert_data
->Length
);
498 switch (signerinfo
->signerIdentifier
.identifierType
) {
499 case SecCmsSignerIDIssuerSN
:
500 if (CERT_CheckIssuerAndSerial(cert
,
501 &(signerinfo
->signerIdentifier
.id
.issuerAndSN
->derIssuer
),
502 &(signerinfo
->signerIdentifier
.id
.issuerAndSN
->serialNumber
)))
503 CFArrayInsertValueAtIndex(certs
, 0, cert
);
505 CFArrayAppendValue(certs
, cert
);
507 case SecCmsSignerIDSubjectKeyID
:
509 CFDataRef cert_keyid
= SecCertificateGetSubjectKeyID(cert
);
510 SecAsn1Item
*tbf_keyid
= signerinfo
->signerIdentifier
.id
.subjectKeyID
;
511 if (tbf_keyid
->Length
== (size_t)CFDataGetLength(cert_keyid
) &&
512 !memcmp(tbf_keyid
->Data
, CFDataGetBytePtr(cert_keyid
), tbf_keyid
->Length
))
513 CFArrayInsertValueAtIndex(certs
, 0, cert
);
515 CFArrayAppendValue(certs
, cert
);
524 if ((CFArrayGetCount(certs
) == 0) &&
525 (signerinfo
->signerIdentifier
.identifierType
== SecCmsSignerIDIssuerSN
))
527 SecCertificateRef cert
= CERT_FindCertificateByIssuerAndSN(signerinfo
->signedData
->certs
, signerinfo
->signerIdentifier
.id
.issuerAndSN
);
529 CFArrayAppendValue(certs
, cert
);
534 if ((CFArrayGetCount(certs
) == 0) &&
535 (signerinfo
->signerIdentifier
.identifierType
== SecCmsSignerIDSubjectKeyID
))
537 SecCertificateRef cert
= CERT_FindCertificateBySubjectKeyID(signerinfo
->signedData
->certs
,
538 signerinfo
->signerIdentifier
.id
.subjectKeyID
);
540 CFArrayAppendValue(certs
, cert
);
549 SecCmsSignerInfoVerifyCertificate(SecCmsSignerInfoRef signerinfo
, SecKeychainRef keychainOrArray
,
550 CFTypeRef policies
, SecTrustRef
*trustRef
)
552 CFAbsoluteTime stime
;
556 SecCertificateRef cert
;
558 if ((cert
= SecCmsSignerInfoGetSigningCertificate(signerinfo
, keychainOrArray
)) == NULL
) {
562 if ((certs
= SecCmsSignerInfoCopySigningCertificates(signerinfo
)) == NULL
) {
564 signerinfo
->verificationStatus
= SecCmsVSSigningCertNotFound
;
568 * Get and convert the signing time; if available, it will be used
569 * both on the cert verification and for importing the sender
572 if (SecCmsSignerInfoGetSigningTime(signerinfo
, &stime
) != SECSuccess
)
573 stime
= CFAbsoluteTimeGetCurrent();
577 rv
= CERT_VerifyCert(keychainOrArray
, cert
, policies
, stime
, trustRef
);
579 rv
= CERT_VerifyCert(keychainOrArray
, certs
, policies
, stime
, trustRef
);
584 if (PORT_GetError() == SEC_ERROR_UNTRUSTED_CERT
)
586 /* Signature or digest level verificationStatus errors should supercede certificate level errors, so only change the verificationStatus if the status was GoodSignature. */
588 #warning DEBUG - SecCmsSignerInfoVerifyCertificate trusts everything!
589 if (signerinfo
->verificationStatus
== SecCmsVSGoodSignature
) {
590 syslog(LOG_ERR
, "SecCmsSignerInfoVerifyCertificate ignoring SEC_ERROR_UNTRUSTED_CERT");
594 if (signerinfo
->verificationStatus
== SecCmsVSGoodSignature
)
595 signerinfo
->verificationStatus
= SecCmsVSSigningCertNotTrusted
;
604 * SecCmsSignerInfoVerify - verify the signature of a single SignerInfo
606 * Just verifies the signature. The assumption is that verification of the certificate
610 SecCmsSignerInfoVerify(SecCmsSignerInfoRef signerinfo
, SecAsn1Item
* digest
, SecAsn1Item
* contentType
)
612 SecPublicKeyRef publickey
= NULL
;
613 SecCmsAttribute
*attr
;
614 SecAsn1Item encoded_attrs
;
615 SecCertificateRef cert
;
616 SecCmsVerificationStatus vs
= SecCmsVSUnverified
;
619 if (signerinfo
== NULL
)
622 /* SecCmsSignerInfoGetSigningCertificate will fail if 2nd parm is NULL and */
623 /* cert has not been verified */
624 if ((cert
= SecCmsSignerInfoGetSigningCertificate(signerinfo
, NULL
)) == NULL
) {
625 vs
= SecCmsVSSigningCertNotFound
;
629 publickey
= SecCertificateCopyKey(cert
);
630 if (publickey
== NULL
)
633 if (!SecCmsArrayIsEmpty((void **)signerinfo
->authAttr
)) {
638 * RFC2630 sez that if there are any authenticated attributes,
639 * then there must be one for content type which matches the
640 * content type of the content being signed, and there must
641 * be one for message digest which matches our message digest.
642 * So check these things first.
644 if ((attr
= SecCmsAttributeArrayFindAttrByOidTag(signerinfo
->authAttr
,
645 SEC_OID_PKCS9_CONTENT_TYPE
, PR_TRUE
)) == NULL
)
647 vs
= SecCmsVSMalformedSignature
;
651 if (SecCmsAttributeCompareValue(attr
, contentType
) == PR_FALSE
) {
652 vs
= SecCmsVSMalformedSignature
;
660 if ((attr
= SecCmsAttributeArrayFindAttrByOidTag(signerinfo
->authAttr
, SEC_OID_PKCS9_MESSAGE_DIGEST
, PR_TRUE
)) == NULL
)
662 vs
= SecCmsVSMalformedSignature
;
665 if (SecCmsAttributeCompareValue(attr
, digest
) == PR_FALSE
) {
666 vs
= SecCmsVSDigestMismatch
;
670 if ((poolp
= PORT_NewArena (1024)) == NULL
) {
671 vs
= SecCmsVSProcessingError
;
678 * The signature is based on a digest of the DER-encoded authenticated
679 * attributes. So, first we encode and then we digest/verify.
680 * we trust the decoder to have the attributes in the right (sorted) order
682 encoded_attrs
.Data
= NULL
;
683 encoded_attrs
.Length
= 0;
685 if (SecCmsAttributeArrayEncode(poolp
, &(signerinfo
->authAttr
), &encoded_attrs
) == NULL
||
686 encoded_attrs
.Data
== NULL
|| encoded_attrs
.Length
== 0)
688 vs
= SecCmsVSProcessingError
;
691 if (errSecSuccess
== SecKeyDigestAndVerify(publickey
, &signerinfo
->digestAlg
, encoded_attrs
.Data
, encoded_attrs
.Length
, signerinfo
->encDigest
.Data
, signerinfo
->encDigest
.Length
))
692 vs
= SecCmsVSGoodSignature
;
694 vs
= SecCmsVSBadSignature
;
696 PORT_FreeArena(poolp
, PR_FALSE
); /* awkward memory management :-( */
701 /* No authenticated attributes. The signature is based on the plain message digest. */
702 sig
= &(signerinfo
->encDigest
);
703 if (sig
->Length
== 0)
706 if (SecKeyVerifyDigest(publickey
, &signerinfo
->digestAlg
, digest
->Data
, digest
->Length
, sig
->Data
, sig
->Length
))
707 vs
= SecCmsVSBadSignature
;
709 vs
= SecCmsVSGoodSignature
;
712 if (vs
== SecCmsVSBadSignature
) {
714 * XXX Change the generic error into our specific one, because
715 * in that case we get a better explanation out of the Security
716 * Advisor. This is really a bug in our error strings (the
717 * "generic" error has a lousy/wrong message associated with it
718 * which assumes the signature verification was done for the
719 * purposes of checking the issuer signature on a certificate)
720 * but this is at least an easy workaround and/or in the
721 * Security Advisor, which specifically checks for the error
722 * SEC_ERROR_PKCS7_BAD_SIGNATURE and gives more explanation
723 * in that case but does not similarly check for
724 * SEC_ERROR_BAD_SIGNATURE. It probably should, but then would
725 * probably say the wrong thing in the case that it *was* the
726 * certificate signature check that failed during the cert
727 * verification done above. Our error handling is really a mess.
729 if (PORT_GetError() == SEC_ERROR_BAD_SIGNATURE
)
730 PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE
);
733 if (publickey
!= NULL
)
734 CFRelease(publickey
);
736 signerinfo
->verificationStatus
= vs
;
738 return (vs
== SecCmsVSGoodSignature
) ? SECSuccess
: SECFailure
;
741 if (publickey
!= NULL
)
742 SECKEY_DestroyPublicKey (publickey
);
744 signerinfo
->verificationStatus
= vs
;
746 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE
);
750 SecCmsVerificationStatus
751 SecCmsSignerInfoGetVerificationStatus(SecCmsSignerInfoRef signerinfo
)
753 return signerinfo
->verificationStatus
;
757 SecCmsSignerInfoGetDigestAlg(SecCmsSignerInfoRef signerinfo
)
759 return SECOID_FindOID (&(signerinfo
->digestAlg
.algorithm
));
763 SecCmsSignerInfoGetDigestAlgTag(SecCmsSignerInfoRef signerinfo
)
767 algdata
= SECOID_FindOID (&(signerinfo
->digestAlg
.algorithm
));
769 return algdata
->offset
;
771 return SEC_OID_UNKNOWN
;
775 SecCmsSignerInfoGetCertList(SecCmsSignerInfoRef signerinfo
)
777 return signerinfo
->certList
;
781 SecCmsSignerInfoGetVersion(SecCmsSignerInfoRef signerinfo
)
783 unsigned long version
;
785 /* always take apart the SecAsn1Item */
786 if (SEC_ASN1DecodeInteger(&(signerinfo
->version
), &version
) != SECSuccess
)
793 * SecCmsSignerInfoGetSigningTime - return the signing time,
794 * in UTCTime format, of a CMS signerInfo.
796 * sinfo - signerInfo data for this signer
798 * Returns a pointer to XXXX (what?)
799 * A return value of NULL is an error.
802 SecCmsSignerInfoGetSigningTime(SecCmsSignerInfoRef sinfo
, CFAbsoluteTime
*stime
)
804 SecCmsAttribute
*attr
;
810 if (sinfo
->signingTime
!= 0) {
811 *stime
= sinfo
->signingTime
; /* cached copy */
815 attr
= SecCmsAttributeArrayFindAttrByOidTag(sinfo
->authAttr
, SEC_OID_PKCS9_SIGNING_TIME
, PR_TRUE
);
816 /* XXXX multi-valued attributes NIH */
817 if (attr
== NULL
|| (value
= SecCmsAttributeGetValue(attr
)) == NULL
)
819 if (DER_UTCTimeToCFDate(value
, stime
) != SECSuccess
)
821 sinfo
->signingTime
= *stime
; /* make cached copy */
827 @abstract Return the data in the signed Codesigning Hash Agility attribute.
828 @param sinfo SignerInfo data for this signer, pointer to a CFDataRef for attribute value
829 @discussion Returns a CFDataRef containing the value of the attribute
830 @result A return value of errSecInternal is an error trying to look up the oid.
831 A status value of success with null result data indicates the attribute was not present.
834 SecCmsSignerInfoGetAppleCodesigningHashAgility(SecCmsSignerInfoRef sinfo
, CFDataRef
*sdata
)
836 SecCmsAttribute
*attr
;
839 if (sinfo
== NULL
|| sdata
== NULL
)
844 if (sinfo
->hashAgilityAttrValue
!= NULL
) {
845 *sdata
= sinfo
->hashAgilityAttrValue
; /* cached copy */
849 attr
= SecCmsAttributeArrayFindAttrByOidTag(sinfo
->authAttr
, SEC_OID_APPLE_HASH_AGILITY
, PR_TRUE
);
851 /* attribute not found */
852 if (attr
== NULL
|| (value
= SecCmsAttributeGetValue(attr
)) == NULL
)
855 sinfo
->hashAgilityAttrValue
= CFDataCreate(NULL
, value
->Data
, value
->Length
); /* make cached copy */
856 if (sinfo
->hashAgilityAttrValue
) {
857 *sdata
= sinfo
->hashAgilityAttrValue
;
860 return errSecAllocate
;
863 /* AgileHash ::= SEQUENCE {
864 hashType OBJECT IDENTIFIER,
865 hashValues OCTET STRING }
868 SecAsn1Item digestOID
;
869 SecAsn1Item digestValue
;
872 static const SecAsn1Template CMSAppleAgileHashTemplate
[] = {
874 0, NULL
, sizeof(CMSAppleAgileHash
) },
875 { SEC_ASN1_OBJECT_ID
,
876 offsetof(CMSAppleAgileHash
, digestOID
), },
877 { SEC_ASN1_OCTET_STRING
,
878 offsetof(CMSAppleAgileHash
, digestValue
), },
882 static OSStatus
CMSAddAgileHashToDictionary(CFMutableDictionaryRef dictionary
, SecAsn1Item
*DERAgileHash
) {
883 PLArenaPool
*tmppoolp
= NULL
;
884 OSStatus status
= errSecSuccess
;
885 CMSAppleAgileHash agileHash
;
886 CFDataRef digestValue
= NULL
;
887 CFNumberRef digestTag
= NULL
;
889 tmppoolp
= PORT_NewArena(1024);
890 if (tmppoolp
== NULL
) {
891 return errSecAllocate
;
894 if ((status
= SEC_ASN1DecodeItem(tmppoolp
, &agileHash
, CMSAppleAgileHashTemplate
, DERAgileHash
)) != errSecSuccess
) {
898 int64_t tag
= SECOID_FindOIDTag(&agileHash
.digestOID
);
899 digestTag
= CFNumberCreate(NULL
, kCFNumberSInt64Type
, &tag
);
900 digestValue
= CFDataCreate(NULL
, agileHash
.digestValue
.Data
, agileHash
.digestValue
.Length
);
901 CFDictionaryAddValue(dictionary
, digestTag
, digestValue
);
904 CFReleaseNull(digestValue
);
905 CFReleaseNull(digestTag
);
907 PORT_FreeArena(tmppoolp
, PR_FALSE
);
914 @abstract Return the data in the signed Codesigning Hash Agility V2 attribute.
915 @param sinfo SignerInfo data for this signer, pointer to a CFDictionaryRef for attribute values
916 @discussion Returns a CFDictionaryRef containing the values of the attribute
917 @result A return value of errSecInternal is an error trying to look up the oid.
918 A status value of success with null result data indicates the attribute was not present.
921 SecCmsSignerInfoGetAppleCodesigningHashAgilityV2(SecCmsSignerInfoRef sinfo
, CFDictionaryRef
*sdict
)
923 SecCmsAttribute
*attr
;
925 if (sinfo
== NULL
|| sdict
== NULL
) {
931 if (sinfo
->hashAgilityV2AttrValues
!= NULL
) {
932 *sdict
= sinfo
->hashAgilityV2AttrValues
; /* cached copy */
936 attr
= SecCmsAttributeArrayFindAttrByOidTag(sinfo
->authAttr
, SEC_OID_APPLE_HASH_AGILITY_V2
, PR_TRUE
);
938 /* attribute not found */
943 /* attrValues SET OF AttributeValue
944 * AttributeValue ::= ANY
946 SecAsn1Item
**values
= attr
->values
;
947 if (values
== NULL
) { /* There must be values */
951 CFMutableDictionaryRef agileHashValues
= CFDictionaryCreateMutable(NULL
, SecCmsArrayCount((void **)values
),
952 &kCFTypeDictionaryKeyCallBacks
,
953 &kCFTypeDictionaryValueCallBacks
);
954 while (*values
!= NULL
) {
955 (void)CMSAddAgileHashToDictionary(agileHashValues
, *values
++);
957 if (CFDictionaryGetCount(agileHashValues
) != SecCmsArrayCount((void **)attr
->values
)) {
958 CFReleaseNull(agileHashValues
);
962 sinfo
->hashAgilityV2AttrValues
= agileHashValues
; /* make cached copy */
963 if (sinfo
->hashAgilityV2AttrValues
) {
964 *sdict
= sinfo
->hashAgilityV2AttrValues
;
967 return errSecAllocate
;
971 * SecCmsSignerInfoGetAppleExpirationTime - return the expiration time,
972 * in UTCTime format, of a CMS signerInfo.
974 * sinfo - signerInfo data for this signer
976 * Returns a pointer to XXXX (what?)
977 * A return value of NULL is an error.
980 SecCmsSignerInfoGetAppleExpirationTime(SecCmsSignerInfoRef sinfo
, CFAbsoluteTime
*etime
)
982 SecCmsAttribute
*attr
= NULL
;
983 SecAsn1Item
* value
= NULL
;
985 if (sinfo
== NULL
|| etime
== NULL
) {
989 if (sinfo
->expirationTime
!= 0) {
990 *etime
= sinfo
->expirationTime
; /* cached copy */
994 attr
= SecCmsAttributeArrayFindAttrByOidTag(sinfo
->authAttr
, SEC_OID_APPLE_EXPIRATION_TIME
, PR_TRUE
);
995 if (attr
== NULL
|| (value
= SecCmsAttributeGetValue(attr
)) == NULL
) {
998 if (DER_UTCTimeToCFDate(value
, etime
) != SECSuccess
) {
1001 sinfo
->expirationTime
= *etime
; /* make cached copy */
1006 * Return the signing cert of a CMS signerInfo.
1008 * the certs in the enclosing SignedData must have been imported already
1011 SecCmsSignerInfoGetSigningCertificate(SecCmsSignerInfoRef signerinfo
, SecKeychainRef keychainOrArray
)
1013 SecCertificateRef cert
= NULL
;
1015 if (signerinfo
->cert
!= NULL
)
1016 return signerinfo
->cert
;
1018 /* @@@ Make sure we search though all the certs in the cms message itself as well, it's silly
1019 to require them to be added to a keychain first. */
1022 SecCmsSignerIdentifier
*sid
;
1025 * This cert will also need to be freed, but since we save it
1026 * in signerinfo for later, we do not want to destroy it when
1027 * we leave this function -- we let the clean-up of the entire
1028 * cinfo structure later do the destroy of this cert.
1030 sid
= &signerinfo
->signerIdentifier
;
1031 switch (sid
->identifierType
) {
1032 case SecCmsSignerIDIssuerSN
:
1033 cert
= CERT_FindCertByIssuerAndSN(keychainOrArray
, sid
->id
.issuerAndSN
);
1035 case SecCmsSignerIDSubjectKeyID
:
1036 cert
= CERT_FindCertBySubjectKeyID(keychainOrArray
, sid
->id
.subjectKeyID
);
1043 /* cert can be NULL at that point */
1044 signerinfo
->cert
= cert
; /* earmark it */
1046 SecAsn1Item
**cert_datas
= signerinfo
->signedData
->rawCerts
;
1047 SecAsn1Item
*cert_data
;
1048 if (cert_datas
) while ((cert_data
= *cert_datas
) != NULL
) {
1049 cert
= SecCertificateCreateWithBytes(NULL
, cert_data
->Data
, cert_data
->Length
);
1051 switch (signerinfo
->signerIdentifier
.identifierType
) {
1052 case SecCmsSignerIDIssuerSN
:
1053 if (CERT_CheckIssuerAndSerial(cert
,
1054 &(signerinfo
->signerIdentifier
.id
.issuerAndSN
->derIssuer
),
1055 &(signerinfo
->signerIdentifier
.id
.issuerAndSN
->serialNumber
)))
1056 signerinfo
->cert
= cert
;
1058 case SecCmsSignerIDSubjectKeyID
: {
1059 CFDataRef cert_keyid
= SecCertificateGetSubjectKeyID(cert
);
1060 SecAsn1Item
*tbf_keyid
= signerinfo
->signerIdentifier
.id
.subjectKeyID
;
1061 if (tbf_keyid
->Length
== (size_t)CFDataGetLength(cert_keyid
) &&
1062 !memcmp(tbf_keyid
->Data
, CFDataGetBytePtr(cert_keyid
), tbf_keyid
->Length
))
1063 signerinfo
->cert
= cert
;
1066 if (signerinfo
->cert
)
1068 CFReleaseNull(cert
);
1073 if (!signerinfo
->cert
&& (signerinfo
->signerIdentifier
.identifierType
== SecCmsSignerIDIssuerSN
)) {
1074 cert
= CERT_FindCertificateByIssuerAndSN(signerinfo
->signedData
->certs
, signerinfo
->signerIdentifier
.id
.issuerAndSN
);
1075 signerinfo
->cert
= cert
;
1077 if (!signerinfo
->cert
&& (signerinfo
->signerIdentifier
.identifierType
== SecCmsSignerIDSubjectKeyID
)) {
1078 cert
= CERT_FindCertificateBySubjectKeyID(signerinfo
->signedData
->certs
, signerinfo
->signerIdentifier
.id
.subjectKeyID
);
1079 signerinfo
->cert
= cert
;
1088 * SecCmsSignerInfoGetSignerCommonName - return the common name of the signer
1090 * sinfo - signerInfo data for this signer
1092 * Returns a CFStringRef containing the common name of the signer.
1093 * A return value of NULL is an error.
1096 SecCmsSignerInfoGetSignerCommonName(SecCmsSignerInfoRef sinfo
)
1098 SecCertificateRef signercert
;
1099 CFStringRef commonName
= NULL
;
1101 /* will fail if cert is not verified */
1102 if ((signercert
= SecCmsSignerInfoGetSigningCertificate(sinfo
, NULL
)) == NULL
)
1106 SecCertificateGetCommonName(signercert
, &commonName
);
1108 CFArrayRef commonNames
= SecCertificateCopyCommonNames(signercert
);
1110 /* SecCertificateCopyCommonNames doesn't return empty arrays */
1111 commonName
= (CFStringRef
)CFArrayGetValueAtIndex(commonNames
, CFArrayGetCount(commonNames
) - 1);
1112 CFRetain(commonName
);
1113 CFRelease(commonNames
);
1121 * SecCmsSignerInfoGetSignerEmailAddress - return the email address of the signer
1123 * sinfo - signerInfo data for this signer
1125 * Returns a CFStringRef containing the name of the signer.
1126 * A return value of NULL is an error.
1129 SecCmsSignerInfoGetSignerEmailAddress(SecCmsSignerInfoRef sinfo
)
1131 SecCertificateRef signercert
;
1132 CFStringRef emailAddress
= NULL
;
1134 if ((signercert
= SecCmsSignerInfoGetSigningCertificate(sinfo
, NULL
)) == NULL
)
1138 SecCertificateGetEmailAddress(signercert
, &emailAddress
);
1140 CFArrayRef names
= SecCertificateCopyRFC822Names(signercert
);
1142 if (CFArrayGetCount(names
) > 0)
1143 emailAddress
= (CFStringRef
)CFArrayGetValueAtIndex(names
, 0);
1145 CFRetain(emailAddress
);
1149 return emailAddress
;
1154 * SecCmsSignerInfoAddAuthAttr - add an attribute to the
1155 * authenticated (i.e. signed) attributes of "signerinfo".
1158 SecCmsSignerInfoAddAuthAttr(SecCmsSignerInfoRef signerinfo
, SecCmsAttribute
*attr
)
1160 return SecCmsAttributeArrayAddAttr(signerinfo
->signedData
->contentInfo
.cmsg
->poolp
, &(signerinfo
->authAttr
), attr
);
1164 * SecCmsSignerInfoAddUnauthAttr - add an attribute to the
1165 * unauthenticated attributes of "signerinfo".
1168 SecCmsSignerInfoAddUnauthAttr(SecCmsSignerInfoRef signerinfo
, SecCmsAttribute
*attr
)
1170 return SecCmsAttributeArrayAddAttr(signerinfo
->signedData
->contentInfo
.cmsg
->poolp
, &(signerinfo
->unAuthAttr
), attr
);
1174 * SecCmsSignerInfoAddSigningTime - add the signing time to the
1175 * authenticated (i.e. signed) attributes of "signerinfo".
1177 * This is expected to be included in outgoing signed
1178 * messages for email (S/MIME) but is likely useful in other situations.
1180 * This should only be added once; a second call will do nothing.
1182 * XXX This will probably just shove the current time into "signerinfo"
1183 * but it will not actually get signed until the entire item is
1184 * processed for encoding. Is this (expected to be small) delay okay?
1187 SecCmsSignerInfoAddSigningTime(SecCmsSignerInfoRef signerinfo
, CFAbsoluteTime t
)
1189 SecCmsAttribute
*attr
;
1194 poolp
= signerinfo
->signedData
->contentInfo
.cmsg
->poolp
;
1196 mark
= PORT_ArenaMark(poolp
);
1198 /* create new signing time attribute */
1199 if (DER_CFDateToUTCTime(t
, &stime
) != SECSuccess
)
1202 if ((attr
= SecCmsAttributeCreate(poolp
, SEC_OID_PKCS9_SIGNING_TIME
, &stime
, PR_FALSE
)) == NULL
) {
1203 SECITEM_FreeItem (&stime
, PR_FALSE
);
1207 SECITEM_FreeItem (&stime
, PR_FALSE
);
1209 if (SecCmsSignerInfoAddAuthAttr(signerinfo
, attr
) != SECSuccess
)
1212 PORT_ArenaUnmark (poolp
, mark
);
1217 PORT_ArenaRelease (poolp
, mark
);
1222 * SecCmsSignerInfoAddSMIMECaps - add a SMIMECapabilities attribute to the
1223 * authenticated (i.e. signed) attributes of "signerinfo".
1225 * This is expected to be included in outgoing signed
1226 * messages for email (S/MIME).
1229 SecCmsSignerInfoAddSMIMECaps(SecCmsSignerInfoRef signerinfo
)
1231 SecCmsAttribute
*attr
;
1232 SecAsn1Item
* smimecaps
= NULL
;
1236 poolp
= signerinfo
->signedData
->contentInfo
.cmsg
->poolp
;
1238 mark
= PORT_ArenaMark(poolp
);
1240 smimecaps
= SECITEM_AllocItem(poolp
, NULL
, 0);
1241 if (smimecaps
== NULL
)
1244 /* create new signing time attribute */
1246 // @@@ We don't do Fortezza yet.
1247 if (SecSMIMECreateSMIMECapabilities(poolp
, smimecaps
, PR_FALSE
) != SECSuccess
)
1249 if (SecSMIMECreateSMIMECapabilities(poolp
, smimecaps
,
1250 PK11_FortezzaHasKEA(signerinfo
->cert
)) != SECSuccess
)
1254 if ((attr
= SecCmsAttributeCreate(poolp
, SEC_OID_PKCS9_SMIME_CAPABILITIES
, smimecaps
, PR_TRUE
)) == NULL
)
1257 if (SecCmsSignerInfoAddAuthAttr(signerinfo
, attr
) != SECSuccess
)
1260 PORT_ArenaUnmark (poolp
, mark
);
1264 PORT_ArenaRelease (poolp
, mark
);
1269 * SecCmsSignerInfoAddSMIMEEncKeyPrefs - add a SMIMEEncryptionKeyPreferences attribute to the
1270 * authenticated (i.e. signed) attributes of "signerinfo".
1272 * This is expected to be included in outgoing signed messages for email (S/MIME).
1275 SecCmsSignerInfoAddSMIMEEncKeyPrefs(SecCmsSignerInfoRef signerinfo
, SecCertificateRef cert
, SecKeychainRef keychainOrArray
)
1277 SecCmsAttribute
*attr
;
1278 SecAsn1Item
* smimeekp
= NULL
;
1285 /* verify this cert for encryption */
1286 policy
= CERT_PolicyForCertUsage(certUsageEmailRecipient
);
1287 if (CERT_VerifyCert(keychainOrArray
, cert
, policy
, CFAbsoluteTimeGetCurrent(), NULL
) != SECSuccess
) {
1294 poolp
= signerinfo
->signedData
->contentInfo
.cmsg
->poolp
;
1295 mark
= PORT_ArenaMark(poolp
);
1297 smimeekp
= SECITEM_AllocItem(poolp
, NULL
, 0);
1298 if (smimeekp
== NULL
)
1301 /* create new signing time attribute */
1302 if (SecSMIMECreateSMIMEEncKeyPrefs(poolp
, smimeekp
, cert
) != SECSuccess
)
1305 if ((attr
= SecCmsAttributeCreate(poolp
, SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE
, smimeekp
, PR_TRUE
)) == NULL
)
1308 if (SecCmsSignerInfoAddAuthAttr(signerinfo
, attr
) != SECSuccess
)
1311 PORT_ArenaUnmark (poolp
, mark
);
1315 PORT_ArenaRelease (poolp
, mark
);
1320 * SecCmsSignerInfoAddMSSMIMEEncKeyPrefs - add a SMIMEEncryptionKeyPreferences attribute to the
1321 * authenticated (i.e. signed) attributes of "signerinfo", using the OID preferred by Microsoft.
1323 * This is expected to be included in outgoing signed messages for email (S/MIME),
1324 * if compatibility with Microsoft mail clients is wanted.
1327 SecCmsSignerInfoAddMSSMIMEEncKeyPrefs(SecCmsSignerInfoRef signerinfo
, SecCertificateRef cert
, SecKeychainRef keychainOrArray
)
1329 SecCmsAttribute
*attr
;
1330 SecAsn1Item
* smimeekp
= NULL
;
1337 /* verify this cert for encryption */
1338 policy
= CERT_PolicyForCertUsage(certUsageEmailRecipient
);
1339 if (CERT_VerifyCert(keychainOrArray
, cert
, policy
, CFAbsoluteTimeGetCurrent(), NULL
) != SECSuccess
) {
1346 poolp
= signerinfo
->signedData
->contentInfo
.cmsg
->poolp
;
1347 mark
= PORT_ArenaMark(poolp
);
1349 smimeekp
= SECITEM_AllocItem(poolp
, NULL
, 0);
1350 if (smimeekp
== NULL
)
1353 /* create new signing time attribute */
1354 if (SecSMIMECreateMSSMIMEEncKeyPrefs(poolp
, smimeekp
, cert
) != SECSuccess
)
1357 if ((attr
= SecCmsAttributeCreate(poolp
, SEC_OID_MS_SMIME_ENCRYPTION_KEY_PREFERENCE
, smimeekp
, PR_TRUE
)) == NULL
)
1360 if (SecCmsSignerInfoAddAuthAttr(signerinfo
, attr
) != SECSuccess
)
1363 PORT_ArenaUnmark (poolp
, mark
);
1367 PORT_ArenaRelease (poolp
, mark
);
1372 * SecCmsSignerInfoAddCounterSignature - countersign a signerinfo
1374 * 1. digest the DER-encoded signature value of the original signerinfo
1375 * 2. create new signerinfo with correct version, sid, digestAlg
1376 * 3. add message-digest authAttr, but NO content-type
1377 * 4. sign the authAttrs
1378 * 5. DER-encode the new signerInfo
1379 * 6. add the whole thing to original signerInfo's unAuthAttrs
1380 * as a SEC_OID_PKCS9_COUNTER_SIGNATURE attribute
1382 * XXXX give back the new signerinfo?
1385 SecCmsSignerInfoAddCounterSignature(SecCmsSignerInfoRef signerinfo
,
1386 SECOidTag digestalg
, SecIdentityRef identity
)
1394 @abstract Add the Apple Codesigning Hash Agility attribute to the authenticated (i.e. signed) attributes of "signerinfo".
1395 @discussion This is expected to be included in outgoing Apple code signatures.
1398 SecCmsSignerInfoAddAppleCodesigningHashAgility(SecCmsSignerInfoRef signerinfo
, CFDataRef attrValue
)
1400 SecCmsAttribute
*attr
;
1401 PLArenaPool
*poolp
= signerinfo
->signedData
->contentInfo
.cmsg
->poolp
;
1402 void *mark
= PORT_ArenaMark(poolp
);
1403 OSStatus status
= SECFailure
;
1405 /* The value is required for this attribute. */
1407 status
= errSecParam
;
1412 * SecCmsAttributeCreate makes a copy of the data in value, so
1413 * we don't need to copy into the CSSM_DATA struct.
1416 value
.Length
= CFDataGetLength(attrValue
);
1417 value
.Data
= (uint8_t *)CFDataGetBytePtr(attrValue
);
1419 if ((attr
= SecCmsAttributeCreate(poolp
,
1420 SEC_OID_APPLE_HASH_AGILITY
,
1422 PR_FALSE
)) == NULL
) {
1423 status
= errSecAllocate
;
1427 if (SecCmsSignerInfoAddAuthAttr(signerinfo
, attr
) != SECSuccess
) {
1428 status
= errSecInternal
;
1432 PORT_ArenaUnmark(poolp
, mark
);
1436 PORT_ArenaRelease(poolp
, mark
);
1440 static OSStatus
CMSAddAgileHashToAttribute(PLArenaPool
*poolp
, SecCmsAttribute
*attr
, CFNumberRef cftag
, CFDataRef value
) {
1441 PLArenaPool
*tmppoolp
= NULL
;
1443 SECOidData
*digestOid
= NULL
;
1444 CMSAppleAgileHash agileHash
;
1445 SecAsn1Item attrValue
= { .Data
= NULL
, .Length
= 0 };
1446 OSStatus status
= errSecSuccess
;
1448 memset(&agileHash
, 0, sizeof(agileHash
));
1450 if(!CFNumberGetValue(cftag
, kCFNumberSInt64Type
, &tag
)) {
1453 digestOid
= SECOID_FindOIDByTag((SECOidTag
)tag
);
1455 agileHash
.digestValue
.Data
= (uint8_t *)CFDataGetBytePtr(value
);
1456 agileHash
.digestValue
.Length
= CFDataGetLength(value
);
1457 agileHash
.digestOID
.Data
= digestOid
->oid
.Data
;
1458 agileHash
.digestOID
.Length
= digestOid
->oid
.Length
;
1460 tmppoolp
= PORT_NewArena(1024);
1461 if (tmppoolp
== NULL
) {
1462 return errSecAllocate
;
1465 if (SEC_ASN1EncodeItem(tmppoolp
, &attrValue
, &agileHash
, CMSAppleAgileHashTemplate
) == NULL
) {
1466 status
= errSecParam
;
1470 status
= SecCmsAttributeAddValue(poolp
, attr
, &attrValue
);
1474 PORT_FreeArena(tmppoolp
, PR_FALSE
);
1481 @abstract Add the Apple Codesigning Hash Agility attribute to the authenticated (i.e. signed) attributes of "signerinfo".
1482 @discussion This is expected to be included in outgoing Apple code signatures.
1485 SecCmsSignerInfoAddAppleCodesigningHashAgilityV2(SecCmsSignerInfoRef signerinfo
, CFDictionaryRef attrValues
)
1487 __block SecCmsAttribute
*attr
;
1488 __block PLArenaPool
*poolp
= signerinfo
->signedData
->contentInfo
.cmsg
->poolp
;
1489 void *mark
= PORT_ArenaMark(poolp
);
1490 OSStatus status
= SECFailure
;
1492 /* The value is required for this attribute. */
1494 status
= errSecParam
;
1498 if ((attr
= SecCmsAttributeCreate(poolp
, SEC_OID_APPLE_HASH_AGILITY_V2
,
1499 NULL
, PR_TRUE
)) == NULL
) {
1500 status
= errSecAllocate
;
1504 CFDictionaryForEach(attrValues
, ^(const void *key
, const void *value
) {
1505 if (!isNumber(key
) || !isData(value
)) {
1508 (void)CMSAddAgileHashToAttribute(poolp
, attr
, (CFNumberRef
)key
, (CFDataRef
)value
);
1511 if (SecCmsSignerInfoAddAuthAttr(signerinfo
, attr
) != SECSuccess
) {
1512 status
= errSecInternal
;
1516 PORT_ArenaUnmark(poolp
, mark
);
1520 PORT_ArenaRelease(poolp
, mark
);
1525 * SecCmsSignerInfoAddAppleExpirationTime - add the expiration time to the
1526 * authenticated (i.e. signed) attributes of "signerinfo".
1528 * This is expected to be included in outgoing signed
1529 * messages for Asset Receipts but is likely useful in other situations.
1531 * This should only be added once; a second call will do nothing.
1534 SecCmsSignerInfoAddAppleExpirationTime(SecCmsSignerInfoRef signerinfo
, CFAbsoluteTime t
)
1536 SecCmsAttribute
*attr
= NULL
;
1537 PLArenaPool
*poolp
= signerinfo
->signedData
->contentInfo
.cmsg
->poolp
;
1538 void *mark
= PORT_ArenaMark(poolp
);
1540 /* create new expiration time attribute */
1542 if (DER_CFDateToUTCTime(t
, &etime
) != SECSuccess
) {
1546 if ((attr
= SecCmsAttributeCreate(poolp
, SEC_OID_APPLE_EXPIRATION_TIME
, &etime
, PR_FALSE
)) == NULL
) {
1547 SECITEM_FreeItem (&etime
, PR_FALSE
);
1551 SECITEM_FreeItem(&etime
, PR_FALSE
);
1553 if (SecCmsSignerInfoAddAuthAttr(signerinfo
, attr
) != SECSuccess
) {
1557 PORT_ArenaUnmark(poolp
, mark
);
1561 PORT_ArenaRelease(poolp
, mark
);
1565 SecCertificateRef
SecCmsSignerInfoCopyCertFromEncryptionKeyPreference(SecCmsSignerInfoRef signerinfo
) {
1566 SecCertificateRef cert
= NULL
;
1567 SecCmsAttribute
*attr
;
1570 /* sanity check - see if verification status is ok (unverified does not count...) */
1571 if (signerinfo
->verificationStatus
!= SecCmsVSGoodSignature
)
1574 /* Prep the rawCerts */
1575 SecAsn1Item
**rawCerts
= NULL
;
1576 if (signerinfo
->signedData
) {
1577 rawCerts
= signerinfo
->signedData
->rawCerts
;
1580 /* find preferred encryption cert */
1581 if (!SecCmsArrayIsEmpty((void **)signerinfo
->authAttr
) &&
1582 (attr
= SecCmsAttributeArrayFindAttrByOidTag(signerinfo
->authAttr
,
1583 SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE
, PR_TRUE
)) != NULL
)
1584 { /* we have a SMIME_ENCRYPTION_KEY_PREFERENCE attribute! Find the cert. */
1585 ekp
= SecCmsAttributeGetValue(attr
);
1588 cert
= SecSMIMEGetCertFromEncryptionKeyPreference(rawCerts
, ekp
);
1590 if (cert
) return cert
;
1592 if (!SecCmsArrayIsEmpty((void **)signerinfo
->authAttr
) &&
1593 (attr
= SecCmsAttributeArrayFindAttrByOidTag(signerinfo
->authAttr
,
1594 SEC_OID_MS_SMIME_ENCRYPTION_KEY_PREFERENCE
, PR_TRUE
)) != NULL
)
1595 { /* we have a MS_SMIME_ENCRYPTION_KEY_PREFERENCE attribute! Find the cert. */
1596 ekp
= SecCmsAttributeGetValue(attr
);
1599 cert
= SecSMIMEGetCertFromEncryptionKeyPreference(rawCerts
, ekp
);
1605 * XXXX the following needs to be done in the S/MIME layer code
1606 * after signature of a signerinfo is verified
1609 SecCmsSignerInfoSaveSMIMEProfile(SecCmsSignerInfoRef signerinfo
)
1611 return -4 /*unImp*/;
1615 * SecCmsSignerInfoIncludeCerts - set cert chain inclusion mode for this signer
1618 SecCmsSignerInfoIncludeCerts(SecCmsSignerInfoRef signerinfo
, SecCmsCertChainMode cm
, SECCertUsage usage
)
1620 if (signerinfo
->cert
== NULL
) {
1624 /* don't leak if we get called twice */
1625 if (signerinfo
->certList
!= NULL
) {
1626 CFRelease(signerinfo
->certList
);
1627 signerinfo
->certList
= NULL
;
1632 signerinfo
->certList
= NULL
;
1634 case SecCmsCMCertOnly
:
1635 signerinfo
->certList
= CERT_CertListFromCert(signerinfo
->cert
);
1637 case SecCmsCMCertChain
:
1638 signerinfo
->certList
= CERT_CertChainFromCert(signerinfo
->cert
, usage
, PR_FALSE
, PR_FALSE
);
1640 case SecCmsCMCertChainWithRoot
:
1641 signerinfo
->certList
= CERT_CertChainFromCert(signerinfo
->cert
, usage
, PR_TRUE
, PR_FALSE
);
1643 case SecCmsCMCertChainWithRootOrFail
:
1644 signerinfo
->certList
= CERT_CertChainFromCert(signerinfo
->cert
, usage
, PR_TRUE
, PR_TRUE
);
1648 if (cm
!= SecCmsCMNone
&& signerinfo
->certList
== NULL
) {