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(); 
 614     rv 
= CERT_VerifyCert(keychainOrArray
, cert
, policies
, stime
, trustRef
); 
 616     rv 
= CERT_VerifyCert(keychainOrArray
, certs
, policies
, stime
, trustRef
); 
 621         if (PORT_GetError() == SEC_ERROR_UNTRUSTED_CERT
) 
 623                 /* Signature or digest level verificationStatus errors should supercede certificate level errors, so only change the verificationStatus if the status was GoodSignature. */ 
 625 #warning DEBUG - SecCmsSignerInfoVerifyCertificate trusts everything! 
 626                 if (signerinfo
->verificationStatus 
== SecCmsVSGoodSignature
) { 
 627                          syslog(LOG_ERR
, "SecCmsSignerInfoVerifyCertificate ignoring SEC_ERROR_UNTRUSTED_CERT"); 
 631                 if (signerinfo
->verificationStatus 
== SecCmsVSGoodSignature
) 
 632                         signerinfo
->verificationStatus 
= SecCmsVSSigningCertNotTrusted
; 
 641  * SecCmsSignerInfoVerify - verify the signature of a single SignerInfo 
 643  * Just verifies the signature. The assumption is that verification of the certificate 
 647 SecCmsSignerInfoVerify(SecCmsSignerInfoRef signerinfo
, SecAsn1Item 
* digest
, SecAsn1Item 
* contentType
) 
 649     SecPublicKeyRef publickey 
= NULL
; 
 650     SecCmsAttribute 
*attr
; 
 651     SecAsn1Item encoded_attrs
; 
 652     SecCertificateRef cert
; 
 653     SecCmsVerificationStatus vs 
= SecCmsVSUnverified
; 
 656     if (signerinfo 
== NULL
) 
 659     /* SecCmsSignerInfoGetSigningCertificate will fail if 2nd parm is NULL and */ 
 660     /* cert has not been verified */ 
 661     if ((cert 
= SecCmsSignerInfoGetSigningCertificate(signerinfo
, NULL
)) == NULL
) { 
 662         vs 
= SecCmsVSSigningCertNotFound
; 
 666     publickey 
= SecCertificateCopyKey(cert
); 
 667     if (publickey 
== NULL
) 
 670     if (!SecCmsArrayIsEmpty((void **)signerinfo
->authAttr
)) { 
 675              * RFC2630 sez that if there are any authenticated attributes, 
 676              * then there must be one for content type which matches the 
 677              * content type of the content being signed, and there must 
 678              * be one for message digest which matches our message digest. 
 679              * So check these things first. 
 681             if ((attr 
= SecCmsAttributeArrayFindAttrByOidTag(signerinfo
->authAttr
, 
 682                                                              SEC_OID_PKCS9_CONTENT_TYPE
, PR_TRUE
)) == NULL
) 
 684                 vs 
= SecCmsVSMalformedSignature
; 
 688             if (SecCmsAttributeCompareValue(attr
, contentType
) == PR_FALSE
) { 
 689                 vs 
= SecCmsVSMalformedSignature
; 
 697         if ((attr 
= SecCmsAttributeArrayFindAttrByOidTag(signerinfo
->authAttr
, SEC_OID_PKCS9_MESSAGE_DIGEST
, PR_TRUE
)) == NULL
) 
 699             vs 
= SecCmsVSMalformedSignature
; 
 702         if (SecCmsAttributeCompareValue(attr
, digest
) == PR_FALSE
) { 
 703             vs 
= SecCmsVSDigestMismatch
; 
 707         if ((poolp 
= PORT_NewArena (1024)) == NULL
) { 
 708             vs 
= SecCmsVSProcessingError
; 
 715          * The signature is based on a digest of the DER-encoded authenticated 
 716          * attributes.  So, first we encode and then we digest/verify. 
 717          * we trust the decoder to have the attributes in the right (sorted) order 
 719         encoded_attrs
.Data 
= NULL
; 
 720         encoded_attrs
.Length 
= 0; 
 722         if (SecCmsAttributeArrayEncode(poolp
, &(signerinfo
->authAttr
), &encoded_attrs
) == NULL 
|| 
 723             encoded_attrs
.Data 
== NULL 
|| encoded_attrs
.Length 
== 0) 
 725             vs 
= SecCmsVSProcessingError
; 
 728         if (errSecSuccess 
== SecKeyDigestAndVerify(publickey
, &signerinfo
->digestAlg
, encoded_attrs
.Data
, encoded_attrs
.Length
, signerinfo
->encDigest
.Data
, signerinfo
->encDigest
.Length
)) 
 729             vs 
= SecCmsVSGoodSignature
; 
 731             vs 
= SecCmsVSBadSignature
; 
 733         PORT_FreeArena(poolp
, PR_FALSE
);        /* awkward memory management :-( */ 
 738         /* No authenticated attributes. The signature is based on the plain message digest. */ 
 739         sig 
= &(signerinfo
->encDigest
); 
 740         if (sig
->Length 
== 0) 
 743         if (SecKeyVerifyDigest(publickey
, &signerinfo
->digestAlg
, digest
->Data
, digest
->Length
, sig
->Data
, sig
->Length
)) 
 744             vs 
= SecCmsVSBadSignature
; 
 746             vs 
= SecCmsVSGoodSignature
; 
 749     if (vs 
== SecCmsVSBadSignature
) { 
 751          * XXX Change the generic error into our specific one, because 
 752          * in that case we get a better explanation out of the Security 
 753          * Advisor.  This is really a bug in our error strings (the 
 754          * "generic" error has a lousy/wrong message associated with it 
 755          * which assumes the signature verification was done for the 
 756          * purposes of checking the issuer signature on a certificate) 
 757          * but this is at least an easy workaround and/or in the 
 758          * Security Advisor, which specifically checks for the error 
 759          * SEC_ERROR_PKCS7_BAD_SIGNATURE and gives more explanation 
 760          * in that case but does not similarly check for 
 761          * SEC_ERROR_BAD_SIGNATURE.  It probably should, but then would 
 762          * probably say the wrong thing in the case that it *was* the 
 763          * certificate signature check that failed during the cert 
 764          * verification done above.  Our error handling is really a mess. 
 766         if (PORT_GetError() == SEC_ERROR_BAD_SIGNATURE
) 
 767             PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE
); 
 770     if (publickey 
!= NULL
) 
 771         CFRelease(publickey
); 
 773     signerinfo
->verificationStatus 
= vs
; 
 775     return (vs 
== SecCmsVSGoodSignature
) ? SECSuccess 
: SECFailure
; 
 778     if (publickey 
!= NULL
) 
 779         SECKEY_DestroyPublicKey (publickey
); 
 781     signerinfo
->verificationStatus 
= vs
; 
 783     PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE
); 
 787 SecCmsVerificationStatus
 
 788 SecCmsSignerInfoGetVerificationStatus(SecCmsSignerInfoRef signerinfo
) 
 790     return signerinfo
->verificationStatus
; 
 794 SecCmsSignerInfoGetDigestAlg(SecCmsSignerInfoRef signerinfo
) 
 796     return SECOID_FindOID (&(signerinfo
->digestAlg
.algorithm
)); 
 800 SecCmsSignerInfoGetDigestAlgTag(SecCmsSignerInfoRef signerinfo
) 
 804     algdata 
= SECOID_FindOID (&(signerinfo
->digestAlg
.algorithm
)); 
 806         return algdata
->offset
; 
 808         return SEC_OID_UNKNOWN
; 
 812 SecCmsSignerInfoGetCertList(SecCmsSignerInfoRef signerinfo
) 
 814     return signerinfo
->certList
; 
 818 SecCmsSignerInfoGetVersion(SecCmsSignerInfoRef signerinfo
) 
 820     unsigned long version
; 
 822     /* always take apart the SecAsn1Item */ 
 823     if (SEC_ASN1DecodeInteger(&(signerinfo
->version
), &version
) != SECSuccess
) 
 830  * SecCmsSignerInfoGetSigningTime - return the signing time, 
 831  *                                    in UTCTime format, of a CMS signerInfo. 
 833  * sinfo - signerInfo data for this signer 
 835  * Returns a pointer to XXXX (what?) 
 836  * A return value of NULL is an error. 
 839 SecCmsSignerInfoGetSigningTime(SecCmsSignerInfoRef sinfo
, CFAbsoluteTime 
*stime
) 
 841     SecCmsAttribute 
*attr
; 
 847     if (sinfo
->signingTime 
!= 0) { 
 848         *stime 
= sinfo
->signingTime
;    /* cached copy */ 
 852     attr 
= SecCmsAttributeArrayFindAttrByOidTag(sinfo
->authAttr
, SEC_OID_PKCS9_SIGNING_TIME
, PR_TRUE
); 
 853     /* XXXX multi-valued attributes NIH */ 
 854     if (attr 
== NULL 
|| (value 
= SecCmsAttributeGetValue(attr
)) == NULL
) 
 856     if (DER_UTCTimeToCFDate(value
, stime
) != SECSuccess
) 
 858     sinfo
->signingTime 
= *stime
;        /* make cached copy */ 
 864      @abstract Return the data in the signed Codesigning Hash Agility attribute. 
 865      @param sinfo SignerInfo data for this signer, pointer to a CFDataRef for attribute value 
 866      @discussion Returns a CFDataRef containing the value of the attribute 
 867      @result A return value of errSecInternal is an error trying to look up the oid. 
 868              A status value of success with null result data indicates the attribute was not present. 
 871 SecCmsSignerInfoGetAppleCodesigningHashAgility(SecCmsSignerInfoRef sinfo
, CFDataRef 
*sdata
) 
 873     SecCmsAttribute 
*attr
; 
 876     if (sinfo 
== NULL 
|| sdata 
== NULL
) 
 881     if (sinfo
->hashAgilityAttrValue 
!= NULL
) { 
 882         *sdata 
= sinfo
->hashAgilityAttrValue
;   /* cached copy */ 
 886     attr 
= SecCmsAttributeArrayFindAttrByOidTag(sinfo
->authAttr
, SEC_OID_APPLE_HASH_AGILITY
, PR_TRUE
); 
 888     /* attribute not found */ 
 889     if (attr 
== NULL 
|| (value 
= SecCmsAttributeGetValue(attr
)) == NULL
) 
 892     sinfo
->hashAgilityAttrValue 
= CFDataCreate(NULL
, value
->Data
, value
->Length
);       /* make cached copy */ 
 893     if (sinfo
->hashAgilityAttrValue
) { 
 894         *sdata 
= sinfo
->hashAgilityAttrValue
; 
 897     return errSecAllocate
; 
 900 /* AgileHash ::= SEQUENCE { 
 901      hashType OBJECT IDENTIFIER, 
 902      hashValues OCTET STRING } 
 905     SecAsn1Item digestOID
; 
 906     SecAsn1Item digestValue
; 
 909 static const SecAsn1Template CMSAppleAgileHashTemplate
[] = { 
 911         0, NULL
, sizeof(CMSAppleAgileHash
) }, 
 912     { SEC_ASN1_OBJECT_ID
, 
 913         offsetof(CMSAppleAgileHash
, digestOID
), }, 
 914     { SEC_ASN1_OCTET_STRING
, 
 915         offsetof(CMSAppleAgileHash
, digestValue
), }, 
 919 static OSStatus 
CMSAddAgileHashToDictionary(CFMutableDictionaryRef dictionary
, SecAsn1Item 
*DERAgileHash
) { 
 920     PLArenaPool 
*tmppoolp 
= NULL
; 
 921     OSStatus status 
= errSecSuccess
; 
 922     CMSAppleAgileHash agileHash
; 
 923     CFDataRef digestValue 
= NULL
; 
 924     CFNumberRef digestTag 
= NULL
; 
 926     tmppoolp 
= PORT_NewArena(1024); 
 927     if (tmppoolp 
== NULL
) { 
 928         return errSecAllocate
; 
 931     if ((status 
= SEC_ASN1DecodeItem(tmppoolp
, &agileHash
, CMSAppleAgileHashTemplate
, DERAgileHash
)) != errSecSuccess
) { 
 935     int64_t tag 
= SECOID_FindOIDTag(&agileHash
.digestOID
); 
 936     digestTag 
= CFNumberCreate(NULL
, kCFNumberSInt64Type
, &tag
); 
 937     digestValue 
= CFDataCreate(NULL
, agileHash
.digestValue
.Data
, agileHash
.digestValue
.Length
); 
 938     CFDictionaryAddValue(dictionary
, digestTag
, digestValue
); 
 941     CFReleaseNull(digestValue
); 
 942     CFReleaseNull(digestTag
); 
 944         PORT_FreeArena(tmppoolp
, PR_FALSE
); 
 951  @abstract Return the data in the signed Codesigning Hash Agility V2 attribute. 
 952  @param sinfo SignerInfo data for this signer, pointer to a CFDictionaryRef for attribute values 
 953  @discussion Returns a CFDictionaryRef containing the values of the attribute 
 954  @result A return value of errSecInternal is an error trying to look up the oid. 
 955  A status value of success with null result data indicates the attribute was not present. 
 958 SecCmsSignerInfoGetAppleCodesigningHashAgilityV2(SecCmsSignerInfoRef sinfo
, CFDictionaryRef 
*sdict
) 
 960     SecCmsAttribute 
*attr
; 
 962     if (sinfo 
== NULL 
|| sdict 
== NULL
) { 
 968     if (sinfo
->hashAgilityV2AttrValues 
!= NULL
) { 
 969         *sdict 
= sinfo
->hashAgilityV2AttrValues
;    /* cached copy */ 
 973     attr 
= SecCmsAttributeArrayFindAttrByOidTag(sinfo
->authAttr
, SEC_OID_APPLE_HASH_AGILITY_V2
, PR_TRUE
); 
 975     /* attribute not found */ 
 980     /* attrValues SET OF AttributeValue 
 981      * AttributeValue ::= ANY 
 983     SecAsn1Item 
**values 
= attr
->values
; 
 984     if (values 
== NULL
) { /* There must be values */ 
 988     CFMutableDictionaryRef agileHashValues 
= CFDictionaryCreateMutable(NULL
, SecCmsArrayCount((void **)values
), 
 989                                                                        &kCFTypeDictionaryKeyCallBacks
, 
 990                                                                        &kCFTypeDictionaryValueCallBacks
); 
 991     while (*values 
!= NULL
) { 
 992         (void)CMSAddAgileHashToDictionary(agileHashValues
, *values
++); 
 994     if (CFDictionaryGetCount(agileHashValues
) != SecCmsArrayCount((void **)attr
->values
)) { 
 995         CFReleaseNull(agileHashValues
); 
 999     sinfo
->hashAgilityV2AttrValues 
= agileHashValues
;    /* make cached copy */ 
1000     if (sinfo
->hashAgilityV2AttrValues
) { 
1001         *sdict 
= sinfo
->hashAgilityV2AttrValues
; 
1004     return errSecAllocate
; 
1008  * SecCmsSignerInfoGetAppleExpirationTime - return the expiration time, 
1009  *                      in UTCTime format, of a CMS signerInfo. 
1011  * sinfo - signerInfo data for this signer 
1013  * Returns a pointer to XXXX (what?) 
1014  * A return value of NULL is an error. 
1017 SecCmsSignerInfoGetAppleExpirationTime(SecCmsSignerInfoRef sinfo
, CFAbsoluteTime 
*etime
) 
1019     SecCmsAttribute 
*attr 
= NULL
; 
1020     SecAsn1Item 
* value 
= NULL
; 
1022     if (sinfo 
== NULL 
|| etime 
== NULL
) { 
1026     if (sinfo
->expirationTime 
!= 0) { 
1027         *etime 
= sinfo
->expirationTime
;    /* cached copy */ 
1031     attr 
= SecCmsAttributeArrayFindAttrByOidTag(sinfo
->authAttr
, SEC_OID_APPLE_EXPIRATION_TIME
, PR_TRUE
); 
1032     if (attr 
== NULL 
|| (value 
= SecCmsAttributeGetValue(attr
)) == NULL
) { 
1035     if (DER_UTCTimeToCFDate(value
, etime
) != SECSuccess
) { 
1038     sinfo
->expirationTime 
= *etime
;    /* make cached copy */ 
1043  * Return the signing cert of a CMS signerInfo. 
1045  * the certs in the enclosing SignedData must have been imported already 
1048 SecCmsSignerInfoGetSigningCertificate(SecCmsSignerInfoRef signerinfo
, SecKeychainRef keychainOrArray
) 
1050     SecCertificateRef cert 
= NULL
; 
1052     if (signerinfo
->cert 
!= NULL
) 
1053         return signerinfo
->cert
; 
1055     /* @@@ Make sure we search though all the certs in the cms message itself as well, it's silly 
1056        to require them to be added to a keychain first. */ 
1059     SecCmsSignerIdentifier 
*sid
; 
1062      * This cert will also need to be freed, but since we save it 
1063      * in signerinfo for later, we do not want to destroy it when 
1064      * we leave this function -- we let the clean-up of the entire 
1065      * cinfo structure later do the destroy of this cert. 
1067     sid 
= &signerinfo
->signerIdentifier
; 
1068     switch (sid
->identifierType
) { 
1069     case SecCmsSignerIDIssuerSN
: 
1070         cert 
= CERT_FindCertByIssuerAndSN(keychainOrArray
, sid
->id
.issuerAndSN
); 
1072     case SecCmsSignerIDSubjectKeyID
: 
1073         cert 
= CERT_FindCertBySubjectKeyID(keychainOrArray
, sid
->id
.subjectKeyID
); 
1080     /* cert can be NULL at that point */ 
1081     signerinfo
->cert 
= cert
;    /* earmark it */ 
1083     SecAsn1Item 
**cert_datas 
= signerinfo
->signedData
->rawCerts
; 
1084     SecAsn1Item 
*cert_data
; 
1085     if (cert_datas
) while ((cert_data 
= *cert_datas
) != NULL
) { 
1086         cert 
= SecCertificateCreateWithBytes(NULL
, cert_data
->Data
, cert_data
->Length
); 
1088             switch (signerinfo
->signerIdentifier
.identifierType
) { 
1089             case SecCmsSignerIDIssuerSN
:  
1090                 if (CERT_CheckIssuerAndSerial(cert
, 
1091                     &(signerinfo
->signerIdentifier
.id
.issuerAndSN
->derIssuer
), 
1092                     &(signerinfo
->signerIdentifier
.id
.issuerAndSN
->serialNumber
))) 
1093                         signerinfo
->cert 
= cert
; 
1095             case SecCmsSignerIDSubjectKeyID
: { 
1096                 CFDataRef cert_keyid 
= SecCertificateGetSubjectKeyID(cert
); 
1097                 SecAsn1Item 
*tbf_keyid 
= signerinfo
->signerIdentifier
.id
.subjectKeyID
; 
1098                 if (tbf_keyid
->Length 
== (size_t)CFDataGetLength(cert_keyid
) && 
1099                     !memcmp(tbf_keyid
->Data
, CFDataGetBytePtr(cert_keyid
), tbf_keyid
->Length
)) 
1100                         signerinfo
->cert 
= cert
; 
1103             if (signerinfo
->cert
) 
1105             CFReleaseNull(cert
);  
1110     if (!signerinfo
->cert 
&& (signerinfo
->signerIdentifier
.identifierType 
== SecCmsSignerIDIssuerSN
)) { 
1111         cert 
= CERT_FindCertificateByIssuerAndSN(signerinfo
->signedData
->certs
, signerinfo
->signerIdentifier
.id
.issuerAndSN
); 
1112         signerinfo
->cert 
= cert
; 
1114     if (!signerinfo
->cert 
&& (signerinfo
->signerIdentifier
.identifierType 
== SecCmsSignerIDSubjectKeyID
)) { 
1115         cert 
= CERT_FindCertificateBySubjectKeyID(signerinfo
->signedData
->certs
, signerinfo
->signerIdentifier
.id
.subjectKeyID
); 
1116         signerinfo
->cert 
= cert
; 
1125  * SecCmsSignerInfoGetSignerCommonName - return the common name of the signer 
1127  * sinfo - signerInfo data for this signer 
1129  * Returns a CFStringRef containing the common name of the signer. 
1130  * A return value of NULL is an error. 
1133 SecCmsSignerInfoGetSignerCommonName(SecCmsSignerInfoRef sinfo
) 
1135     SecCertificateRef signercert
; 
1136     CFStringRef commonName 
= NULL
; 
1138     /* will fail if cert is not verified */ 
1139     if ((signercert 
= SecCmsSignerInfoGetSigningCertificate(sinfo
, NULL
)) == NULL
) 
1143     SecCertificateGetCommonName(signercert
, &commonName
); 
1145     CFArrayRef commonNames 
= SecCertificateCopyCommonNames(signercert
); 
1147         /* SecCertificateCopyCommonNames doesn't return empty arrays */ 
1148         commonName 
= (CFStringRef
)CFArrayGetValueAtIndex(commonNames
, CFArrayGetCount(commonNames
) - 1); 
1149         CFRetain(commonName
); 
1150         CFRelease(commonNames
); 
1158  * SecCmsSignerInfoGetSignerEmailAddress - return the email address of the signer 
1160  * sinfo - signerInfo data for this signer 
1162  * Returns a CFStringRef containing the name of the signer. 
1163  * A return value of NULL is an error. 
1166 SecCmsSignerInfoGetSignerEmailAddress(SecCmsSignerInfoRef sinfo
) 
1168     SecCertificateRef signercert
; 
1169     CFStringRef emailAddress 
= NULL
; 
1171     if ((signercert 
= SecCmsSignerInfoGetSigningCertificate(sinfo
, NULL
)) == NULL
) 
1175     SecCertificateGetEmailAddress(signercert
, &emailAddress
); 
1177     CFArrayRef names 
= SecCertificateCopyRFC822Names(signercert
); 
1179         if (CFArrayGetCount(names
) > 0) 
1180             emailAddress 
= (CFStringRef
)CFArrayGetValueAtIndex(names
, 0); 
1182             CFRetain(emailAddress
); 
1186     return emailAddress
; 
1191  * SecCmsSignerInfoAddAuthAttr - add an attribute to the 
1192  * authenticated (i.e. signed) attributes of "signerinfo".  
1195 SecCmsSignerInfoAddAuthAttr(SecCmsSignerInfoRef signerinfo
, SecCmsAttribute 
*attr
) 
1197     return SecCmsAttributeArrayAddAttr(signerinfo
->signedData
->contentInfo
.cmsg
->poolp
, &(signerinfo
->authAttr
), attr
); 
1201  * SecCmsSignerInfoAddUnauthAttr - add an attribute to the 
1202  * unauthenticated attributes of "signerinfo".  
1205 SecCmsSignerInfoAddUnauthAttr(SecCmsSignerInfoRef signerinfo
, SecCmsAttribute 
*attr
) 
1207     return SecCmsAttributeArrayAddAttr(signerinfo
->signedData
->contentInfo
.cmsg
->poolp
, &(signerinfo
->unAuthAttr
), attr
); 
1211  * SecCmsSignerInfoAddSigningTime - add the signing time to the 
1212  * authenticated (i.e. signed) attributes of "signerinfo".  
1214  * This is expected to be included in outgoing signed 
1215  * messages for email (S/MIME) but is likely useful in other situations. 
1217  * This should only be added once; a second call will do nothing. 
1219  * XXX This will probably just shove the current time into "signerinfo" 
1220  * but it will not actually get signed until the entire item is 
1221  * processed for encoding.  Is this (expected to be small) delay okay? 
1224 SecCmsSignerInfoAddSigningTime(SecCmsSignerInfoRef signerinfo
, CFAbsoluteTime t
) 
1226     SecCmsAttribute 
*attr
; 
1231     poolp 
= signerinfo
->signedData
->contentInfo
.cmsg
->poolp
; 
1233     mark 
= PORT_ArenaMark(poolp
); 
1235     /* create new signing time attribute */ 
1236     if (DER_CFDateToUTCTime(t
, &stime
) != SECSuccess
) 
1239     if ((attr 
= SecCmsAttributeCreate(poolp
, SEC_OID_PKCS9_SIGNING_TIME
, &stime
, PR_FALSE
)) == NULL
) { 
1240         SECITEM_FreeItem (&stime
, PR_FALSE
); 
1244     SECITEM_FreeItem (&stime
, PR_FALSE
); 
1246     if (SecCmsSignerInfoAddAuthAttr(signerinfo
, attr
) != SECSuccess
) 
1249     PORT_ArenaUnmark (poolp
, mark
); 
1254     PORT_ArenaRelease (poolp
, mark
); 
1259  * SecCmsSignerInfoAddSMIMECaps - add a SMIMECapabilities attribute to the 
1260  * authenticated (i.e. signed) attributes of "signerinfo".  
1262  * This is expected to be included in outgoing signed 
1263  * messages for email (S/MIME). 
1266 SecCmsSignerInfoAddSMIMECaps(SecCmsSignerInfoRef signerinfo
) 
1268     SecCmsAttribute 
*attr
; 
1269     SecAsn1Item 
* smimecaps 
= NULL
; 
1273     poolp 
= signerinfo
->signedData
->contentInfo
.cmsg
->poolp
; 
1275     mark 
= PORT_ArenaMark(poolp
); 
1277     smimecaps 
= SECITEM_AllocItem(poolp
, NULL
, 0); 
1278     if (smimecaps 
== NULL
) 
1281     /* create new signing time attribute */ 
1283     // @@@ We don't do Fortezza yet. 
1284     if (SecSMIMECreateSMIMECapabilities(poolp
, smimecaps
, PR_FALSE
) != SECSuccess
) 
1286     if (SecSMIMECreateSMIMECapabilities(poolp
, smimecaps
, 
1287                             PK11_FortezzaHasKEA(signerinfo
->cert
)) != SECSuccess
) 
1291     if ((attr 
= SecCmsAttributeCreate(poolp
, SEC_OID_PKCS9_SMIME_CAPABILITIES
, smimecaps
, PR_TRUE
)) == NULL
) 
1294     if (SecCmsSignerInfoAddAuthAttr(signerinfo
, attr
) != SECSuccess
) 
1297     PORT_ArenaUnmark (poolp
, mark
); 
1301     PORT_ArenaRelease (poolp
, mark
); 
1306  * SecCmsSignerInfoAddSMIMEEncKeyPrefs - add a SMIMEEncryptionKeyPreferences attribute to the 
1307  * authenticated (i.e. signed) attributes of "signerinfo".  
1309  * This is expected to be included in outgoing signed messages for email (S/MIME). 
1312 SecCmsSignerInfoAddSMIMEEncKeyPrefs(SecCmsSignerInfoRef signerinfo
, SecCertificateRef cert
, SecKeychainRef keychainOrArray
) 
1314     SecCmsAttribute 
*attr
; 
1315     SecAsn1Item 
* smimeekp 
= NULL
; 
1322     /* verify this cert for encryption */ 
1323     policy 
= CERT_PolicyForCertUsage(certUsageEmailRecipient
); 
1324     if (CERT_VerifyCert(keychainOrArray
, cert
, policy
, CFAbsoluteTimeGetCurrent(), NULL
) != SECSuccess
) { 
1331     poolp 
= signerinfo
->signedData
->contentInfo
.cmsg
->poolp
; 
1332     mark 
= PORT_ArenaMark(poolp
); 
1334     smimeekp 
= SECITEM_AllocItem(poolp
, NULL
, 0); 
1335     if (smimeekp 
== NULL
) 
1338     /* create new signing time attribute */ 
1339     if (SecSMIMECreateSMIMEEncKeyPrefs(poolp
, smimeekp
, cert
) != SECSuccess
) 
1342     if ((attr 
= SecCmsAttributeCreate(poolp
, SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE
, smimeekp
, PR_TRUE
)) == NULL
) 
1345     if (SecCmsSignerInfoAddAuthAttr(signerinfo
, attr
) != SECSuccess
) 
1348     PORT_ArenaUnmark (poolp
, mark
); 
1352     PORT_ArenaRelease (poolp
, mark
); 
1357  * SecCmsSignerInfoAddMSSMIMEEncKeyPrefs - add a SMIMEEncryptionKeyPreferences attribute to the 
1358  * authenticated (i.e. signed) attributes of "signerinfo", using the OID preferred by Microsoft. 
1360  * This is expected to be included in outgoing signed messages for email (S/MIME), 
1361  * if compatibility with Microsoft mail clients is wanted. 
1364 SecCmsSignerInfoAddMSSMIMEEncKeyPrefs(SecCmsSignerInfoRef signerinfo
, SecCertificateRef cert
, SecKeychainRef keychainOrArray
) 
1366     SecCmsAttribute 
*attr
; 
1367     SecAsn1Item 
* smimeekp 
= NULL
; 
1374     /* verify this cert for encryption */ 
1375     policy 
= CERT_PolicyForCertUsage(certUsageEmailRecipient
); 
1376     if (CERT_VerifyCert(keychainOrArray
, cert
, policy
, CFAbsoluteTimeGetCurrent(), NULL
) != SECSuccess
) { 
1383     poolp 
= signerinfo
->signedData
->contentInfo
.cmsg
->poolp
; 
1384     mark 
= PORT_ArenaMark(poolp
); 
1386     smimeekp 
= SECITEM_AllocItem(poolp
, NULL
, 0); 
1387     if (smimeekp 
== NULL
) 
1390     /* create new signing time attribute */ 
1391     if (SecSMIMECreateMSSMIMEEncKeyPrefs(poolp
, smimeekp
, cert
) != SECSuccess
) 
1394     if ((attr 
= SecCmsAttributeCreate(poolp
, SEC_OID_MS_SMIME_ENCRYPTION_KEY_PREFERENCE
, smimeekp
, PR_TRUE
)) == NULL
) 
1397     if (SecCmsSignerInfoAddAuthAttr(signerinfo
, attr
) != SECSuccess
) 
1400     PORT_ArenaUnmark (poolp
, mark
); 
1404     PORT_ArenaRelease (poolp
, mark
); 
1409  * SecCmsSignerInfoAddCounterSignature - countersign a signerinfo 
1411  * 1. digest the DER-encoded signature value of the original signerinfo 
1412  * 2. create new signerinfo with correct version, sid, digestAlg 
1413  * 3. add message-digest authAttr, but NO content-type 
1414  * 4. sign the authAttrs 
1415  * 5. DER-encode the new signerInfo 
1416  * 6. add the whole thing to original signerInfo's unAuthAttrs 
1417  *    as a SEC_OID_PKCS9_COUNTER_SIGNATURE attribute 
1419  * XXXX give back the new signerinfo? 
1422 SecCmsSignerInfoAddCounterSignature(SecCmsSignerInfoRef signerinfo
, 
1423                                     SECOidTag digestalg
, SecIdentityRef identity
) 
1431      @abstract Add the Apple Codesigning Hash Agility attribute to the authenticated (i.e. signed) attributes of "signerinfo". 
1432      @discussion This is expected to be included in outgoing Apple code signatures. 
1435 SecCmsSignerInfoAddAppleCodesigningHashAgility(SecCmsSignerInfoRef signerinfo
, CFDataRef attrValue
) 
1437     SecCmsAttribute 
*attr
; 
1438     PLArenaPool 
*poolp 
= signerinfo
->signedData
->contentInfo
.cmsg
->poolp
; 
1439     void *mark 
= PORT_ArenaMark(poolp
); 
1440     OSStatus status 
= SECFailure
; 
1442     /* The value is required for this attribute. */ 
1444         status 
= errSecParam
; 
1449      * SecCmsAttributeCreate makes a copy of the data in value, so 
1450      * we don't need to copy into the CSSM_DATA struct. 
1453     value
.Length 
= CFDataGetLength(attrValue
); 
1454     value
.Data 
= (uint8_t *)CFDataGetBytePtr(attrValue
); 
1456     if ((attr 
= SecCmsAttributeCreate(poolp
, 
1457                                       SEC_OID_APPLE_HASH_AGILITY
, 
1459                                       PR_FALSE
)) == NULL
) { 
1460         status 
= errSecAllocate
; 
1464     if (SecCmsSignerInfoAddAuthAttr(signerinfo
, attr
) != SECSuccess
) { 
1465         status 
= errSecInternal
; 
1469     PORT_ArenaUnmark(poolp
, mark
); 
1473     PORT_ArenaRelease(poolp
, mark
); 
1477 static OSStatus 
CMSAddAgileHashToAttribute(PLArenaPool 
*poolp
, SecCmsAttribute 
*attr
, CFNumberRef cftag
, CFDataRef value
) { 
1478     PLArenaPool 
*tmppoolp 
= NULL
; 
1480     SECOidData 
*digestOid 
= NULL
; 
1481     CMSAppleAgileHash agileHash
; 
1482     SecAsn1Item attrValue 
= { .Data 
= NULL
, .Length 
= 0 }; 
1483     OSStatus status 
= errSecSuccess
; 
1485     memset(&agileHash
, 0, sizeof(agileHash
)); 
1487     if(!CFNumberGetValue(cftag
, kCFNumberSInt64Type
, &tag
)) { 
1490     digestOid 
= SECOID_FindOIDByTag((SECOidTag
)tag
); 
1492     agileHash
.digestValue
.Data 
= (uint8_t *)CFDataGetBytePtr(value
); 
1493     agileHash
.digestValue
.Length 
= CFDataGetLength(value
); 
1494     agileHash
.digestOID
.Data 
= digestOid
->oid
.Data
; 
1495     agileHash
.digestOID
.Length 
= digestOid
->oid
.Length
; 
1497     tmppoolp 
= PORT_NewArena(1024); 
1498     if (tmppoolp 
== NULL
) { 
1499         return errSecAllocate
; 
1502     if (SEC_ASN1EncodeItem(tmppoolp
, &attrValue
, &agileHash
, CMSAppleAgileHashTemplate
) == NULL
) { 
1503         status 
= errSecParam
; 
1507     status 
= SecCmsAttributeAddValue(poolp
, attr
, &attrValue
); 
1511         PORT_FreeArena(tmppoolp
, PR_FALSE
); 
1518  @abstract Add the Apple Codesigning Hash Agility attribute to the authenticated (i.e. signed) attributes of "signerinfo". 
1519  @discussion This is expected to be included in outgoing Apple code signatures. 
1522 SecCmsSignerInfoAddAppleCodesigningHashAgilityV2(SecCmsSignerInfoRef signerinfo
, CFDictionaryRef attrValues
) 
1524     __block SecCmsAttribute 
*attr
; 
1525     __block PLArenaPool 
*poolp 
= signerinfo
->signedData
->contentInfo
.cmsg
->poolp
; 
1526     void *mark 
= PORT_ArenaMark(poolp
); 
1527     OSStatus status 
= SECFailure
; 
1529     /* The value is required for this attribute. */ 
1531         status 
= errSecParam
; 
1535     if ((attr 
= SecCmsAttributeCreate(poolp
, SEC_OID_APPLE_HASH_AGILITY_V2
, 
1536                                       NULL
, PR_TRUE
)) == NULL
) { 
1537         status 
= errSecAllocate
; 
1541     CFDictionaryForEach(attrValues
, ^(const void *key
, const void *value
) { 
1542         if (!isNumber(key
) || !isData(value
)) { 
1545         (void)CMSAddAgileHashToAttribute(poolp
, attr
, (CFNumberRef
)key
, (CFDataRef
)value
); 
1548     if (SecCmsSignerInfoAddAuthAttr(signerinfo
, attr
) != SECSuccess
) { 
1549         status 
= errSecInternal
; 
1553     PORT_ArenaUnmark(poolp
, mark
); 
1557     PORT_ArenaRelease(poolp
, mark
); 
1562  * SecCmsSignerInfoAddAppleExpirationTime - add the expiration time to the 
1563  * authenticated (i.e. signed) attributes of "signerinfo". 
1565  * This is expected to be included in outgoing signed 
1566  * messages for Asset Receipts but is likely useful in other situations. 
1568  * This should only be added once; a second call will do nothing. 
1571 SecCmsSignerInfoAddAppleExpirationTime(SecCmsSignerInfoRef signerinfo
, CFAbsoluteTime t
) 
1573     SecCmsAttribute 
*attr 
= NULL
; 
1574     PLArenaPool 
*poolp 
= signerinfo
->signedData
->contentInfo
.cmsg
->poolp
; 
1575     void *mark 
= PORT_ArenaMark(poolp
); 
1577     /* create new expiration time attribute */ 
1579     if (DER_CFDateToUTCTime(t
, &etime
) != SECSuccess
) { 
1583     if ((attr 
= SecCmsAttributeCreate(poolp
, SEC_OID_APPLE_EXPIRATION_TIME
, &etime
, PR_FALSE
)) == NULL
) { 
1584         SECITEM_FreeItem (&etime
, PR_FALSE
); 
1588     SECITEM_FreeItem(&etime
, PR_FALSE
); 
1590     if (SecCmsSignerInfoAddAuthAttr(signerinfo
, attr
) != SECSuccess
) { 
1594     PORT_ArenaUnmark(poolp
, mark
); 
1598     PORT_ArenaRelease(poolp
, mark
); 
1602 SecCertificateRef 
SecCmsSignerInfoCopyCertFromEncryptionKeyPreference(SecCmsSignerInfoRef signerinfo
) { 
1603     SecCertificateRef cert 
= NULL
; 
1604     SecCmsAttribute 
*attr
; 
1607     /* sanity check - see if verification status is ok (unverified does not count...) */ 
1608     if (signerinfo
->verificationStatus 
!= SecCmsVSGoodSignature
) 
1611     /* Prep the rawCerts */ 
1612     SecAsn1Item 
**rawCerts 
= NULL
; 
1613     if (signerinfo
->signedData
) { 
1614         rawCerts 
= signerinfo
->signedData
->rawCerts
; 
1617     /* find preferred encryption cert */ 
1618     if (!SecCmsArrayIsEmpty((void **)signerinfo
->authAttr
) && 
1619         (attr 
= SecCmsAttributeArrayFindAttrByOidTag(signerinfo
->authAttr
, 
1620                                                      SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE
, PR_TRUE
)) != NULL
) 
1621     { /* we have a SMIME_ENCRYPTION_KEY_PREFERENCE attribute! Find the cert. */ 
1622         ekp 
= SecCmsAttributeGetValue(attr
); 
1625         cert 
= SecSMIMEGetCertFromEncryptionKeyPreference(rawCerts
, ekp
); 
1627     if (cert
) return cert
; 
1629     if (!SecCmsArrayIsEmpty((void **)signerinfo
->authAttr
) && 
1630         (attr 
= SecCmsAttributeArrayFindAttrByOidTag(signerinfo
->authAttr
, 
1631                                                      SEC_OID_MS_SMIME_ENCRYPTION_KEY_PREFERENCE
, PR_TRUE
)) != NULL
) 
1632     { /* we have a MS_SMIME_ENCRYPTION_KEY_PREFERENCE attribute! Find the cert. */ 
1633         ekp 
= SecCmsAttributeGetValue(attr
); 
1636         cert 
= SecSMIMEGetCertFromEncryptionKeyPreference(rawCerts
, ekp
); 
1642  * XXXX the following needs to be done in the S/MIME layer code 
1643  * after signature of a signerinfo is verified 
1646 SecCmsSignerInfoSaveSMIMEProfile(SecCmsSignerInfoRef signerinfo
) 
1648     return -4 /*unImp*/; 
1652  * SecCmsSignerInfoIncludeCerts - set cert chain inclusion mode for this signer 
1655     SecCmsSignerInfoIncludeCerts(SecCmsSignerInfoRef signerinfo
, SecCmsCertChainMode cm
, SECCertUsage usage
) 
1657         if (signerinfo
->cert 
== NULL
) { 
1661         /* don't leak if we get called twice */ 
1662         if (signerinfo
->certList 
!= NULL
) { 
1663             CFRelease(signerinfo
->certList
); 
1664             signerinfo
->certList 
= NULL
; 
1669             signerinfo
->certList 
= NULL
; 
1671         case SecCmsCMCertOnly
: 
1672             signerinfo
->certList 
= CERT_CertListFromCert(signerinfo
->cert
); 
1674         case SecCmsCMCertChain
: 
1675             signerinfo
->certList 
= CERT_CertChainFromCert(signerinfo
->cert
, usage
, PR_FALSE
, PR_FALSE
); 
1677         case SecCmsCMCertChainWithRoot
: 
1678             signerinfo
->certList 
= CERT_CertChainFromCert(signerinfo
->cert
, usage
, PR_TRUE
, PR_FALSE
); 
1680         case SecCmsCMCertChainWithRootOrFail
: 
1681             signerinfo
->certList 
= CERT_CertChainFromCert(signerinfo
->cert
, usage
, PR_TRUE
, PR_TRUE
); 
1685         if (cm 
!= SecCmsCMNone 
&& signerinfo
->certList 
== NULL
) {