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 signedData methods. 
  38 #include <Security/SecCmsSignedData.h> 
  40 #include <Security/SecCmsContentInfo.h> 
  41 #include <Security/SecCmsDigestContext.h> 
  42 #include <Security/SecCmsSignerInfo.h> 
  49 #include "tsaTemplates.h" 
  51 #include <security_asn1/secasn1.h> 
  52 #include <security_asn1/secerr.h> 
  53 #include <Security/SecBase.h> 
  54 #include <CommonCrypto/CommonRandomSPI.h> 
  55 #include <Security/SecPolicyPriv.h> 
  56 #include <utilities/SecCFWrappers.h> 
  59 #define SIGDATA_DEBUG   1 
  63 #define dprintf(args...)      printf(args) 
  65 #define dprintf(args...) 
  69 SecCmsSignedDataCreate(SecCmsMessageRef cmsg
) 
  72     SecCmsSignedDataRef sigd
; 
  77     mark 
= PORT_ArenaMark(poolp
); 
  79     sigd 
= (SecCmsSignedDataRef
)PORT_ArenaZAlloc (poolp
, sizeof(SecCmsSignedData
)); 
  85     /* signerInfos, certs, certlists, crls are all empty */ 
  86     /* version is set in SecCmsSignedDataFinalize() */ 
  88     PORT_ArenaUnmark(poolp
, mark
); 
  92     PORT_ArenaRelease(poolp
, mark
); 
  97 SecCmsSignedDataDestroy(SecCmsSignedDataRef sigd
) 
  99     SecCmsSignerInfoRef 
*signerinfos
, si
; 
 104     if (sigd
->certs 
!= NULL
) 
 105         CFRelease(sigd
->certs
); 
 107     signerinfos 
= sigd
->signerInfos
; 
 108     if (signerinfos 
!= NULL
) { 
 109         while ((si 
= *signerinfos
++) != NULL
) 
 110             SecCmsSignerInfoDestroy(si
); 
 113     /* everything's in a pool, so don't worry about the storage */ 
 114    SecCmsContentInfoDestroy(&(sigd
->contentInfo
)); 
 118  * SecCmsSignedDataEncodeBeforeStart - do all the necessary things to a SignedData 
 119  *     before start of encoding. 
 122  *  - find out about the right value to put into sigd->version 
 123  *  - come up with a list of digestAlgorithms (which should be the union of the algorithms 
 124  *         in the signerinfos). 
 125  *         If we happen to have a pre-set list of algorithms (and digest values!), we 
 126  *         check if we have all the signerinfos' algorithms. If not, this is an error. 
 129 SecCmsSignedDataEncodeBeforeStart(SecCmsSignedDataRef sigd
) 
 131     SecCmsSignerInfoRef signerinfo
; 
 132     SECOidTag digestalgtag
; 
 136     Boolean haveDigests 
= PR_FALSE
; 
 140     poolp 
= sigd
->cmsg
->poolp
; 
 142     /* we assume that we have precomputed digests if there is a list of algorithms, and */ 
 143     /* a chunk of data for each of those algorithms */ 
 144     if (sigd
->digestAlgorithms 
!= NULL 
&& sigd
->digests 
!= NULL
) { 
 145         for (i
=0; sigd
->digestAlgorithms
[i
] != NULL
; i
++) { 
 146             if (sigd
->digests
[i
] == NULL
) 
 149         if (sigd
->digestAlgorithms
[i
] == NULL
)  /* reached the end of the array? */ 
 150             haveDigests 
= PR_TRUE
;              /* yes: we must have all the digests */ 
 153     version 
= SEC_CMS_SIGNED_DATA_VERSION_BASIC
; 
 155     /* RFC2630 5.1 "version is the syntax version number..." */ 
 156     if (SecCmsContentInfoGetContentTypeTag(&(sigd
->contentInfo
)) != SEC_OID_PKCS7_DATA
) 
 157         version 
= SEC_CMS_SIGNED_DATA_VERSION_EXT
; 
 159     /* prepare all the SignerInfos (there may be none) */ 
 160     for (i
=0; i 
< SecCmsSignedDataSignerInfoCount(sigd
); i
++) { 
 161         signerinfo 
= SecCmsSignedDataGetSignerInfo(sigd
, i
); 
 163         /* RFC2630 5.1 "version is the syntax version number..." */ 
 164         if (SecCmsSignerInfoGetVersion(signerinfo
) != SEC_CMS_SIGNER_INFO_VERSION_ISSUERSN
) 
 165             version 
= SEC_CMS_SIGNED_DATA_VERSION_EXT
; 
 167         /* collect digestAlgorithms from SignerInfos */ 
 168         /* (we need to know which algorithms we have when the content comes in) */ 
 169         /* do not overwrite any existing digestAlgorithms (and digest) */ 
 170         digestalgtag 
= SecCmsSignerInfoGetDigestAlgTag(signerinfo
); 
 172         n 
= SecCmsAlgArrayGetIndexByAlgTag(sigd
->digestAlgorithms
, digestalgtag
); 
 173         if (n 
< 0 && haveDigests
) { 
 174             /* oops, there is a digestalg we do not have a digest for */ 
 175             /* but we were supposed to have all the digests already... */ 
 178             /* add the digestAlgorithm & a NULL digest */ 
 179             rv 
= SecCmsSignedDataAddDigest((SecArenaPoolRef
)poolp
, sigd
, digestalgtag
, NULL
); 
 180             if (rv 
!= SECSuccess
) 
 183             /* found it, nothing to do */ 
 187     dummy 
= SEC_ASN1EncodeInteger(poolp
, &(sigd
->version
), (long)version
); 
 191     /* this is a SET OF, so we need to sort them guys */ 
 192     rv 
= SecCmsArraySortByDER((void **)sigd
->digestAlgorithms
,  
 193                                 SEC_ASN1_GET(SECOID_AlgorithmIDTemplate
), 
 194                                 (void **)sigd
->digests
); 
 195     if (rv 
!= SECSuccess
) 
 205 SecCmsSignedDataEncodeBeforeData(SecCmsSignedDataRef sigd
) 
 207     /* set up the digests */ 
 208     if (sigd
->digestAlgorithms 
!= NULL
) { 
 209         sigd
->contentInfo
.digcx 
= SecCmsDigestContextStartMultiple(sigd
->digestAlgorithms
); 
 210         if (sigd
->contentInfo
.digcx 
== NULL
) 
 216 #include <AssertMacros.h> 
 217 #include "tsaSupport.h" 
 218 #include "tsaSupportPriv.h" 
 219 #include "tsaTemplates.h" 
 220 #include <security_keychain/tsaDERUtilities.h> 
 222 extern const SecAsn1Template kSecAsn1TSATSTInfoTemplate
; 
 224 OSStatus 
createTSAMessageImprint(SecCmsSignedDataRef signedData
, CSSM_DATA_PTR encDigest
,  
 225     SecAsn1TSAMessageImprint 
*messageImprint
) 
 227     // Calculate hash of encDigest and put in messageImprint.hashedMessage 
 228     // We pass in encDigest, since in the verification case, it comes from a different signedData 
 230     OSStatus status 
= SECFailure
; 
 232     require(signedData 
&& messageImprint
, xit
); 
 234     SECAlgorithmID 
**digestAlgorithms 
= SecCmsSignedDataGetDigestAlgs(signedData
); 
 235     require(digestAlgorithms
, xit
); 
 237     SecCmsDigestContextRef digcx 
= SecCmsDigestContextStartMultiple(digestAlgorithms
); 
 239     require(encDigest
, xit
); 
 241     SecCmsSignerInfoRef signerinfo 
= SecCmsSignedDataGetSignerInfo(signedData
, 0);  // NB - assume 1 signer only! 
 242     messageImprint
->hashAlgorithm 
= signerinfo
->digestAlg
; 
 244     SecCmsDigestContextUpdate(digcx
, encDigest
->Data
, encDigest
->Length
); 
 246     require_noerr(SecCmsDigestContextFinishSingle(digcx
, (SecArenaPoolRef
)signedData
->cmsg
->poolp
, 
 247         &messageImprint
->hashedMessage
), xit
); 
 254 #include <Security/SecAsn1Templates.h> 
 257 static OSStatus 
decodeDERUTF8String(const CSSM_DATA_PTR content
, char *statusstr
, size_t strsz
) 
 259     // The statusString should use kSecAsn1SequenceOfUTF8StringTemplate, but doesn't 
 260     OSStatus status 
= SECFailure
; 
 261     SecAsn1CoderRef coder 
= NULL
; 
 262     CSSM_DATA statusString
; 
 265     require(content 
&& statusstr
, xit
); 
 267     require_noerr(SecAsn1CoderCreate(&coder
), xit
); 
 268     require_noerr(SecAsn1Decode(coder
, content
->Data
, content
->Length
, kSecAsn1UTF8StringTemplate
, &statusString
), xit
); 
 270     len 
= (statusString
.Length 
< strsz
)?(int)statusString
.Length
:strsz
; 
 271     if (statusstr 
&& statusString
.Data
) 
 272         strncpy(statusstr
, (const char *)statusString
.Data
, len
); 
 276         SecAsn1CoderRelease(coder
); 
 281 static OSStatus 
validateTSAResponseAndAddTimeStamp(SecCmsSignerInfoRef signerinfo
, CSSM_DATA_PTR tsaResponse
, 
 282     uint64_t expectedNonce
) 
 284     OSStatus status 
= SECFailure
; 
 285     SecAsn1CoderRef coder 
= NULL
; 
 286     SecAsn1TimeStampRespDER respDER 
= {{{0}},}; 
 287     SecAsn1TSAPKIStatusInfo 
*tsastatus 
= NULL
; 
 293     require_action(tsaResponse 
&& tsaResponse
->Data 
&& tsaResponse
->Length
, xit
, status 
= errSecTimestampMissing
); 
 295     require_noerr(SecAsn1CoderCreate(&coder
), xit
); 
 296     require_noerr(SecTSAResponseCopyDEREncoding(coder
, tsaResponse
, &respDER
), xit
); 
 299     tsaWriteFileX("/tmp/tsa-timeStampToken.der", respDER
.timeStampTokenDER
.Data
, respDER
.timeStampTokenDER
.Length
); 
 302     tsastatus 
= (SecAsn1TSAPKIStatusInfo 
*)&respDER
.status
; 
 303     require_action(tsastatus
->status
.Data
, xit
, status 
= errSecTimestampBadDataFormat
); 
 304     respstatus 
= (int)tsaDER_ToInt(&tsastatus
->status
); 
 308     if (tsastatus
->failInfo
.Data
)   // e.g. FI_BadRequest 
 309         failinfo 
= (int)tsaDER_ToInt(&tsastatus
->failInfo
); 
 311     if (tsastatus
->statusString
.Data 
&& tsastatus
->statusString
.Length
) 
 313         OSStatus strrx 
= decodeDERUTF8String(&tsastatus
->statusString
, buf
, sizeof(buf
)); 
 314         dprintf("decodeDERUTF8String status: %d\n", (int)strrx
); 
 317     dprintf("validateTSAResponse: status: %d, failinfo: %d, %s\n", respstatus
, failinfo
, buf
); 
 323     case PKIS_GrantedWithMods
:  // Success 
 327         status 
= errSecTimestampRejection
; 
 330         status 
= errSecTimestampWaiting
; 
 332     case PKIS_RevocationWarning
: 
 333         status 
= errSecTimestampRevocationWarning
; 
 335     case PKIS_RevocationNotification
: 
 336         status 
= errSecTimestampRevocationNotification
; 
 339         status 
= errSecTimestampSystemFailure
; 
 342     require_noerr(status
, xit
); 
 344     // If we succeeded, then we must have a TimeStampToken 
 346     require_action(respDER
.timeStampTokenDER
.Data 
&& respDER
.timeStampTokenDER
.Length
, xit
, status 
= errSecTimestampBadDataFormat
); 
 348     dprintf("timestamp full expected nonce: %lld\n", expectedNonce
); 
 351         The bytes in respDER are a full CMS message, which we need to check now for validity. 
 352         The code for this is essentially the same code taht is done during a timestamp 
 353         verify, except that we also need to check the nonce. 
 355     require_noerr(status 
= decodeTimeStampToken(signerinfo
, &respDER
.timeStampTokenDER
, NULL
, expectedNonce
), xit
); 
 357     status 
= SecCmsSignerInfoAddTimeStamp(signerinfo
, &respDER
.timeStampTokenDER
); 
 361         SecAsn1CoderRelease(coder
); 
 365 static OSStatus 
getRandomNonce(uint64_t *nonce
) 
 367     return nonce 
? CCRandomCopyBytes(kCCRandomDevRandom
, (void *)nonce
, sizeof(*nonce
)) : SECFailure
; 
 370 static OSStatus 
remapTimestampError(OSStatus inStatus
) 
 373         Since communicating with the timestamp server is perhaps an unexpected 
 374         dependency on the network, map unknown errors into something to indicate 
 375         that signing without a timestamp may be a workaround. In particular, the 
 376         private CFURL errors (see CFNetworkErrorsPriv.i) 
 378         kCFURLErrorTimedOut               = -1001, 
 379         kCFURLErrorNotConnectedToInternet = -1009, 
 381         are remapped to errSecTimestampServiceNotAvailable. 
 386     case errSecTimestampMissing
: 
 387     case errSecTimestampInvalid
: 
 388     case errSecTimestampNotTrusted
: 
 389     case errSecTimestampServiceNotAvailable
: 
 390     case errSecTimestampBadAlg
: 
 391     case errSecTimestampBadRequest
: 
 392     case errSecTimestampBadDataFormat
: 
 393     case errSecTimestampTimeNotAvailable
: 
 394     case errSecTimestampUnacceptedPolicy
: 
 395     case errSecTimestampUnacceptedExtension
: 
 396     case errSecTimestampAddInfoNotAvailable
: 
 397     case errSecTimestampSystemFailure
: 
 398     case errSecSigningTimeMissing
: 
 399     case errSecTimestampRejection
: 
 400     case errSecTimestampWaiting
: 
 401     case errSecTimestampRevocationWarning
: 
 402     case errSecTimestampRevocationNotification
: 
 405         return errSecTimestampServiceNotAvailable
; 
 407     return errSecTimestampServiceNotAvailable
; 
 411  * SecCmsSignedDataEncodeAfterData - do all the necessary things to a SignedData 
 412  *     after all the encapsulated data was passed through the encoder. 
 415  *  - create the signatures in all the SignerInfos 
 417  * Please note that nothing is done to the Certificates and CRLs in the message - this 
 418  * is entirely the responsibility of our callers. 
 421 SecCmsSignedDataEncodeAfterData(SecCmsSignedDataRef sigd
) 
 423     SecCmsSignerInfoRef 
*signerinfos
, signerinfo
; 
 424     SecCmsContentInfoRef cinfo
; 
 425     SECOidTag digestalgtag
; 
 426     OSStatus ret 
= SECFailure
; 
 428     CSSM_DATA_PTR contentType
; 
 430     int i
, ci
, n
, rci
, si
; 
 433     extern const SecAsn1Template SecCmsSignerInfoTemplate
[]; 
 435     poolp 
= sigd
->cmsg
->poolp
; 
 436     cinfo 
= &(sigd
->contentInfo
); 
 438     /* did we have digest calculation going on? */ 
 440         rv 
= SecCmsDigestContextFinishMultiple(cinfo
->digcx
, (SecArenaPoolRef
)poolp
, &(sigd
->digests
)); 
 441         if (rv 
!= SECSuccess
) 
 442             goto loser
;         /* error has been set by SecCmsDigestContextFinishMultiple */ 
 446     signerinfos 
= sigd
->signerInfos
; 
 449     /* prepare all the SignerInfos (there may be none) */ 
 450     for (i
=0; i 
< SecCmsSignedDataSignerInfoCount(sigd
); i
++) { 
 451         signerinfo 
= SecCmsSignedDataGetSignerInfo(sigd
, i
); 
 453         /* find correct digest for this signerinfo */ 
 454         digestalgtag 
= SecCmsSignerInfoGetDigestAlgTag(signerinfo
); 
 455         n 
= SecCmsAlgArrayGetIndexByAlgTag(sigd
->digestAlgorithms
, digestalgtag
); 
 456         if (n 
< 0 || sigd
->digests 
== NULL 
|| sigd
->digests
[n
] == NULL
) { 
 457             /* oops - digest not found */ 
 458             PORT_SetError(SEC_ERROR_DIGEST_NOT_FOUND
); 
 462         /* XXX if our content is anything else but data, we need to force the 
 463          * presence of signed attributes (RFC2630 5.3 "signedAttributes is a 
 466         /* pass contentType here as we want a contentType attribute */ 
 467         if ((contentType 
= SecCmsContentInfoGetContentTypeOID(cinfo
)) == NULL
) 
 471         rv 
= SecCmsSignerInfoSign(signerinfo
, sigd
->digests
[n
], contentType
); 
 472         if (rv 
!= SECSuccess
) 
 475         /* while we're at it, count number of certs in certLists */ 
 476         certlist 
= SecCmsSignerInfoGetCertList(signerinfo
); 
 478             certcount 
+= CFArrayGetCount(certlist
); 
 481     /* Now we can get a timestamp, since we have all the digests */ 
 483     // We force the setting of a callback, since this is the most usual case 
 484     if (!sigd
->cmsg
->tsaCallback
) 
 485         SecCmsMessageSetTSACallback(sigd
->cmsg
, (SecCmsTSACallback
)SecCmsTSADefaultCallback
); 
 487     if (sigd
->cmsg
->tsaCallback 
&& sigd
->cmsg
->tsaContext
) 
 489         CSSM_DATA tsaResponse 
= {0,}; 
 490         SecAsn1TSAMessageImprint messageImprint 
= {{{0},},{0,}}; 
 491         // <rdar://problem/11073466> Add nonce support for timestamping client 
 495         require_noerr(getRandomNonce(&nonce
), tsxit
); 
 496         dprintf("SecCmsSignedDataSignerInfoCount: %d\n", SecCmsSignedDataSignerInfoCount(sigd
)); 
 498         // Calculate hash of encDigest and put in messageImprint.hashedMessage 
 499         SecCmsSignerInfoRef signerinfo 
= SecCmsSignedDataGetSignerInfo(sigd
, 0);    // NB - assume 1 signer only! 
 500         CSSM_DATA 
*encDigest 
= SecCmsSignerInfoGetEncDigest(signerinfo
); 
 501         require_noerr(createTSAMessageImprint(sigd
, encDigest
, &messageImprint
), tsxit
); 
 503         // Callback to fire up XPC service to talk to TimeStamping server, etc. 
 504         require_noerr(rv 
=(*sigd
->cmsg
->tsaCallback
)(sigd
->cmsg
->tsaContext
, &messageImprint
, 
 505                                                      nonce
, &tsaResponse
), tsxit
); 
 507         require_noerr(rv 
= validateTSAResponseAndAddTimeStamp(signerinfo
, &tsaResponse
, nonce
), tsxit
); 
 510             It is likely that every occurrence of "goto loser" in this file should 
 511             also do a PORT_SetError. Since it is not clear what might depend on this 
 512             behavior, we just do this in the timestamping case. 
 517             dprintf("Original timestamp error: %d\n", (int)rv
); 
 518             rv 
= remapTimestampError(rv
); 
 524     /* this is a SET OF, so we need to sort them guys */ 
 525     rv 
= SecCmsArraySortByDER((void **)signerinfos
, SecCmsSignerInfoTemplate
, NULL
); 
 526     if (rv 
!= SECSuccess
) 
 530      * now prepare certs & crls 
 533     /* count the rest of the certs */ 
 534     if (sigd
->certs 
!= NULL
) 
 535         certcount 
+= CFArrayGetCount(sigd
->certs
); 
 537     if (certcount 
== 0) { 
 538         sigd
->rawCerts 
= NULL
; 
 541          * Combine all of the certs and cert chains into rawcerts. 
 542          * Note: certcount is an upper bound; we may not need that many slots 
 543          * but we will allocate anyway to avoid having to do another pass. 
 544          * (The temporary space saving is not worth it.) 
 546          * XXX ARGH - this NEEDS to be fixed. need to come up with a decent 
 547          *  SetOfDERcertficates implementation 
 549         sigd
->rawCerts 
= (CSSM_DATA_PTR 
*)PORT_ArenaAlloc(poolp
, (certcount 
+ 1) * sizeof(CSSM_DATA_PTR
)); 
 550         if (sigd
->rawCerts 
== NULL
) 
 554          * XXX Want to check for duplicates and not add *any* cert that is 
 555          * already in the set.  This will be more important when we start 
 556          * dealing with larger sets of certs, dual-key certs (signing and 
 557          * encryption), etc.  For the time being we can slide by... 
 559          * XXX ARGH - this NEEDS to be fixed. need to come up with a decent 
 560          *  SetOfDERcertficates implementation 
 563         if (signerinfos 
!= NULL
) { 
 564             for (si 
= 0; signerinfos
[si
] != NULL
; si
++) { 
 565                 signerinfo 
= signerinfos
[si
]; 
 566                 for (ci 
= 0; ci 
< CFArrayGetCount(signerinfo
->certList
); ci
++) { 
 567                     sigd
->rawCerts
[rci
] = PORT_ArenaZAlloc(poolp
, sizeof(CSSM_DATA
)); 
 568                     SecCertificateRef cert 
= (SecCertificateRef
)CFArrayGetValueAtIndex(signerinfo
->certList
, ci
); 
 569                     SecCertificateGetData(cert
, sigd
->rawCerts
[rci
++]); 
 574         if (sigd
->certs 
!= NULL
) { 
 575             for (ci 
= 0; ci 
< CFArrayGetCount(sigd
->certs
); ci
++) { 
 576                 sigd
->rawCerts
[rci
] = PORT_ArenaZAlloc(poolp
, sizeof(CSSM_DATA
)); 
 577                 SecCertificateRef cert 
= (SecCertificateRef
)CFArrayGetValueAtIndex(sigd
->certs
, ci
); 
 578                 SecCertificateGetData(cert
, sigd
->rawCerts
[rci
++]); 
 582         sigd
->rawCerts
[rci
] = NULL
; 
 584         /* this is a SET OF, so we need to sort them guys - we have the DER already, though */ 
 585         SecCmsArraySort((void **)sigd
->rawCerts
, SecCmsUtilDERCompare
, NULL
, NULL
); 
 592     dprintf("SecCmsSignedDataEncodeAfterData: ret: %ld, rv: %ld\n", (long)ret
, (long)rv
); 
 597 SecCmsSignedDataDecodeBeforeData(SecCmsSignedDataRef sigd
) 
 599     /* set up the digests */ 
 600     if (sigd
->digestAlgorithms 
!= NULL 
&& sigd
->digests 
== NULL
) { 
 601         /* if digests are already there, do nothing */ 
 602         sigd
->contentInfo
.digcx 
= SecCmsDigestContextStartMultiple(sigd
->digestAlgorithms
); 
 603         if (sigd
->contentInfo
.digcx 
== NULL
) 
 610  * SecCmsSignedDataDecodeAfterData - do all the necessary things to a SignedData 
 611  *     after all the encapsulated data was passed through the decoder. 
 614 SecCmsSignedDataDecodeAfterData(SecCmsSignedDataRef sigd
) 
 616     /* did we have digest calculation going on? */ 
 617     if (sigd
->contentInfo
.digcx
) { 
 618         if (SecCmsDigestContextFinishMultiple(sigd
->contentInfo
.digcx
, (SecArenaPoolRef
)sigd
->cmsg
->poolp
, &(sigd
->digests
)) != SECSuccess
) 
 619             return SECFailure
;  /* error has been set by SecCmsDigestContextFinishMultiple */ 
 620         sigd
->contentInfo
.digcx 
= NULL
; 
 626  * SecCmsSignedDataDecodeAfterEnd - do all the necessary things to a SignedData 
 627  *     after all decoding is finished. 
 630 SecCmsSignedDataDecodeAfterEnd(SecCmsSignedDataRef sigd
) 
 632     SecCmsSignerInfoRef 
*signerinfos
; 
 635     signerinfos 
= sigd
->signerInfos
; 
 637     /* set cmsg and sigd backpointers for all the signerinfos */ 
 639         for (i 
= 0; signerinfos
[i
] != NULL
; i
++) { 
 640             signerinfos
[i
]->cmsg 
= sigd
->cmsg
; 
 641             signerinfos
[i
]->sigd 
= sigd
; 
 649  * SecCmsSignedDataGetSignerInfos - retrieve the SignedData's signer list 
 651 SecCmsSignerInfoRef 
* 
 652 SecCmsSignedDataGetSignerInfos(SecCmsSignedDataRef sigd
) 
 654     return sigd
->signerInfos
; 
 658 SecCmsSignedDataSignerInfoCount(SecCmsSignedDataRef sigd
) 
 660     return SecCmsArrayCount((void **)sigd
->signerInfos
); 
 664 SecCmsSignedDataGetSignerInfo(SecCmsSignedDataRef sigd
, int i
) 
 666     return sigd
->signerInfos
[i
]; 
 670  * SecCmsSignedDataGetDigestAlgs - retrieve the SignedData's digest algorithm list 
 673 SecCmsSignedDataGetDigestAlgs(SecCmsSignedDataRef sigd
) 
 675     return sigd
->digestAlgorithms
; 
 679  * SecCmsSignedDataGetContentInfo - return pointer to this signedData's contentinfo 
 682 SecCmsSignedDataGetContentInfo(SecCmsSignedDataRef sigd
) 
 684     return &(sigd
->contentInfo
); 
 688  * SecCmsSignedDataGetCertificateList - retrieve the SignedData's certificate list 
 691 SecCmsSignedDataGetCertificateList(SecCmsSignedDataRef sigd
) 
 693     return sigd
->rawCerts
; 
 697 SecCmsSignedDataImportCerts(SecCmsSignedDataRef sigd
, SecKeychainRef keychain
, 
 698                                 SECCertUsage certusage
, Boolean keepcerts
) 
 704     certcount 
= SecCmsArrayCount((void **)sigd
->rawCerts
); 
 706     rv 
= CERT_ImportCerts(keychain
, certusage
, certcount
, sigd
->rawCerts
, NULL
, 
 707                           keepcerts
, PR_FALSE
, NULL
); 
 709     /* XXX CRL handling */ 
 711     if (sigd
->signerInfos 
!= NULL
) { 
 712         /* fill in all signerinfo's certs */ 
 713         for (i 
= 0; sigd
->signerInfos
[i
] != NULL
; i
++) 
 714             (void)SecCmsSignerInfoGetSigningCertificate(sigd
->signerInfos
[i
], keychain
); 
 721  * XXX the digests need to be passed in BETWEEN the decoding and the verification in case 
 722  *     of external signatures! 
 726  * SecCmsSignedDataVerifySignerInfo - check the signatures. 
 728  * The digests were either calculated during decoding (and are stored in the 
 729  * signedData itself) or set after decoding using SecCmsSignedDataSetDigests. 
 731  * The verification checks if the signing cert is valid and has a trusted chain 
 732  * for the purpose specified by "policies". 
 734  * If trustRef is NULL the cert chain is verified and the VerificationStatus is set accordingly. 
 735  * Otherwise a SecTrust object is returned for the caller to evaluate using SecTrustEvaluate(). 
 738 SecCmsSignedDataVerifySignerInfo(SecCmsSignedDataRef sigd
, int i
,  
 739                             SecKeychainRef keychainOrArray
, CFTypeRef policies
, SecTrustRef 
*trustRef
) 
 741     SecCmsSignerInfoRef signerinfo
; 
 742     SecCmsContentInfoRef cinfo
; 
 743     SECOidData 
*algiddata
; 
 744     CSSM_DATA_PTR contentType
, digest
; 
 745     OSStatus status
, status2
; 
 747     cinfo 
= &(sigd
->contentInfo
); 
 749     signerinfo 
= sigd
->signerInfos
[i
]; 
 751     /* Signature or digest level verificationStatus errors should supercede 
 752        certificate level errors, so check the digest and signature first.  */ 
 754     /* Find digest and contentType for signerinfo */ 
 755     algiddata 
= SecCmsSignerInfoGetDigestAlg(signerinfo
); 
 756     if (algiddata 
== NULL
) { 
 757         return errSecInternalError
; // shouldn't have happened, this is likely due to corrupted data 
 760     digest 
= SecCmsSignedDataGetDigestByAlgTag(sigd
, algiddata
->offset
); 
 763                  * No digests; this probably had detached content the caller has to  
 765                  * FIXME: need some error return for this (as well as many  
 766                  * other places in this library). 
 768                 return errSecDataNotAvailable
; 
 770     contentType 
= SecCmsContentInfoGetContentTypeOID(cinfo
); 
 772     /* verify signature */ 
 773     CFTypeRef timeStampPolicies
=SecPolicyCreateAppleTimeStampingAndRevocationPolicies(policies
); 
 774     status 
= SecCmsSignerInfoVerifyWithPolicy(signerinfo
, timeStampPolicies
, digest
, contentType
); 
 775     CFReleaseSafe(timeStampPolicies
); 
 777     /* Now verify the certificate.  We do this even if the signature failed to verify so we can 
 778        return a trustRef to the caller for display purposes.  */ 
 779     status2 
= SecCmsSignerInfoVerifyCertificate(signerinfo
, keychainOrArray
, 
 781     dprintf("SecCmsSignedDataVerifySignerInfo: status %d status2 %d\n", (int) status
, (int)status2
); 
 782     /* The error from SecCmsSignerInfoVerify() supercedes error from SecCmsSignerInfoVerifyCertificate(). */ 
 790  * SecCmsSignedDataVerifyCertsOnly - verify the certs in a certs-only message 
 793 SecCmsSignedDataVerifyCertsOnly(SecCmsSignedDataRef sigd
,  
 794                                   SecKeychainRef keychainOrArray
,  
 797     SecCertificateRef cert
; 
 798     OSStatus rv 
= SECSuccess
; 
 802     if (!sigd 
|| !keychainOrArray 
|| !sigd
->rawCerts
) { 
 803         PORT_SetError(SEC_ERROR_INVALID_ARGS
); 
 807     count 
= SecCmsArrayCount((void**)sigd
->rawCerts
); 
 808     for (i
=0; i 
< count
; i
++) { 
 809         if (sigd
->certs 
&& CFArrayGetCount(sigd
->certs
) > i
) { 
 810             cert 
= (SecCertificateRef
)CFArrayGetValueAtIndex(sigd
->certs
, i
); 
 813             cert 
= CERT_FindCertByDERCert(keychainOrArray
, sigd
->rawCerts
[i
]); 
 819         rv 
|= CERT_VerifyCert(keychainOrArray
, cert
, sigd
->rawCerts
, 
 820             policies
, CFAbsoluteTimeGetCurrent(), NULL
); 
 828  * SecCmsSignedDataHasDigests - see if we have digests in place 
 831 SecCmsSignedDataHasDigests(SecCmsSignedDataRef sigd
) 
 833     return (sigd
->digests 
!= NULL
); 
 837 SecCmsSignedDataAddCertList(SecCmsSignedDataRef sigd
, CFArrayRef certlist
) 
 839     PORT_Assert(certlist 
!= NULL
); 
 841     if (certlist 
== NULL
) 
 845         sigd
->certs 
= CFArrayCreateMutableCopy(NULL
, 0, certlist
); 
 848         CFRange certlistRange 
= { 0, CFArrayGetCount(certlist
) }; 
 849         CFArrayAppendArray(sigd
->certs
, certlist
, certlistRange
); 
 856  * SecCmsSignedDataAddCertChain - add cert and its entire chain to the set of certs  
 859 SecCmsSignedDataAddCertChain(SecCmsSignedDataRef sigd
, SecCertificateRef cert
) 
 865     usage 
= certUsageEmailSigner
; 
 867     /* do not include root */ 
 868     certlist 
= CERT_CertChainFromCert(cert
, usage
, PR_FALSE
); 
 869     if (certlist 
== NULL
) 
 872     rv 
= SecCmsSignedDataAddCertList(sigd
, certlist
); 
 879 SecCmsSignedDataAddCertificate(SecCmsSignedDataRef sigd
, SecCertificateRef cert
) 
 881     PORT_Assert(cert 
!= NULL
); 
 887         sigd
->certs 
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
); 
 889     CFArrayAppendValue(sigd
->certs
, cert
); 
 895 SecCmsSignedDataContainsCertsOrCrls(SecCmsSignedDataRef sigd
) 
 897     if (sigd
->rawCerts 
!= NULL 
&& sigd
->rawCerts
[0] != NULL
) 
 899     else if (sigd
->rawCrls 
!= NULL 
&& sigd
->rawCrls
[0] != NULL
) 
 906 SecCmsSignedDataAddSignerInfo(SecCmsSignedDataRef sigd
, 
 907                                 SecCmsSignerInfoRef signerinfo
) 
 911     SECOidTag digestalgtag
; 
 914     poolp 
= sigd
->cmsg
->poolp
; 
 916     mark 
= PORT_ArenaMark(poolp
); 
 919     rv 
= SecCmsArrayAdd(poolp
, (void ***)&(sigd
->signerInfos
), (void *)signerinfo
); 
 920     if (rv 
!= SECSuccess
) 
 923     signerinfo
->sigd 
= sigd
; 
 927      * Empty because we don't have it yet. Either it gets created during encoding 
 928      * (if the data is present) or has to be set externally. 
 929      * XXX maybe pass it in optionally? 
 931     digestalgtag 
= SecCmsSignerInfoGetDigestAlgTag(signerinfo
); 
 932     rv 
= SecCmsSignedDataSetDigestValue(sigd
, digestalgtag
, NULL
); 
 933     if (rv 
!= SECSuccess
) 
 937      * The last thing to get consistency would be adding the digest. 
 940     PORT_ArenaUnmark(poolp
, mark
); 
 944     PORT_ArenaRelease (poolp
, mark
); 
 949 SecCmsSignedDataGetDigestByAlgTag(SecCmsSignedDataRef sigd
, SECOidTag algtag
) 
 953         if(sigd
->digests 
== NULL
) { 
 956     idx 
= SecCmsAlgArrayGetIndexByAlgTag(sigd
->digestAlgorithms
, algtag
); 
 957     return sigd
->digests
[idx
]; 
 961  * SecCmsSignedDataSetDigests - set a signedData's digests member 
 963  * "digestalgs" - array of digest algorithm IDs 
 964  * "digests"    - array of digests corresponding to the digest algorithms 
 967 SecCmsSignedDataSetDigests(SecCmsSignedDataRef sigd
, 
 968                                 SECAlgorithmID 
**digestalgs
, 
 969                                 CSSM_DATA_PTR 
*digests
) 
 973     if (sigd
->digestAlgorithms 
== NULL
) { 
 974         PORT_SetError(SEC_ERROR_INVALID_ARGS
); 
 978     /* we assume that the digests array is just not there yet */ 
 979     PORT_Assert(sigd
->digests 
== NULL
); 
 980     if (sigd
->digests 
!= NULL
) { 
 981         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE
); 
 985     /* now allocate one (same size as digestAlgorithms) */ 
 986     cnt 
= SecCmsArrayCount((void **)sigd
->digestAlgorithms
); 
 987     sigd
->digests 
= PORT_ArenaZAlloc(sigd
->cmsg
->poolp
, (cnt 
+ 1) * sizeof(CSSM_DATA_PTR
)); 
 988     if (sigd
->digests 
== NULL
) { 
 989         PORT_SetError(SEC_ERROR_NO_MEMORY
); 
 993     for (i 
= 0; sigd
->digestAlgorithms
[i
] != NULL
; i
++) { 
 994         /* try to find the sigd's i'th digest algorithm in the array we passed in */ 
 995         idx 
= SecCmsAlgArrayGetIndexByAlgID(digestalgs
, sigd
->digestAlgorithms
[i
]); 
 997             PORT_SetError(SEC_ERROR_DIGEST_NOT_FOUND
); 
1001         /* found it - now set it */ 
1002         if ((sigd
->digests
[i
] = SECITEM_AllocItem(sigd
->cmsg
->poolp
, NULL
, 0)) == NULL 
|| 
1003             SECITEM_CopyItem(sigd
->cmsg
->poolp
, sigd
->digests
[i
], digests
[idx
]) != SECSuccess
) 
1005             PORT_SetError(SEC_ERROR_NO_MEMORY
); 
1013 SecCmsSignedDataSetDigestValue(SecCmsSignedDataRef sigd
, 
1014                                 SECOidTag digestalgtag
, 
1015                                 CSSM_DATA_PTR digestdata
) 
1017     CSSM_DATA_PTR digest 
= NULL
; 
1022     poolp 
= sigd
->cmsg
->poolp
; 
1024     mark 
= PORT_ArenaMark(poolp
); 
1028         digest 
= (CSSM_DATA_PTR
) PORT_ArenaZAlloc(poolp
,sizeof(CSSM_DATA
)); 
1030         /* copy digestdata item to arena (in case we have it and are not only making room) */ 
1031         if (SECITEM_CopyItem(poolp
, digest
, digestdata
) != SECSuccess
) 
1035     /* now allocate one (same size as digestAlgorithms) */ 
1036     if (sigd
->digests 
== NULL
) { 
1037         cnt 
= SecCmsArrayCount((void **)sigd
->digestAlgorithms
); 
1038         sigd
->digests 
= PORT_ArenaZAlloc(sigd
->cmsg
->poolp
, (cnt 
+ 1) * sizeof(CSSM_DATA_PTR
)); 
1039         if (sigd
->digests 
== NULL
) { 
1040                 PORT_SetError(SEC_ERROR_NO_MEMORY
); 
1046     if (sigd
->digestAlgorithms 
!= NULL
) 
1047         n 
= SecCmsAlgArrayGetIndexByAlgTag(sigd
->digestAlgorithms
, digestalgtag
); 
1049     /* if not found, add a digest */ 
1051         if (SecCmsSignedDataAddDigest((SecArenaPoolRef
)poolp
, sigd
, digestalgtag
, digest
) != SECSuccess
) 
1054         /* replace NULL pointer with digest item (and leak previous value) */ 
1055         sigd
->digests
[n
] = digest
; 
1058     PORT_ArenaUnmark(poolp
, mark
); 
1062     PORT_ArenaRelease(poolp
, mark
); 
1067 SecCmsSignedDataAddDigest(SecArenaPoolRef pool
, 
1068                                 SecCmsSignedDataRef sigd
, 
1069                                 SECOidTag digestalgtag
, 
1070                                 CSSM_DATA_PTR digest
) 
1072     PRArenaPool 
*poolp 
= (PRArenaPool 
*)pool
; 
1073     SECAlgorithmID 
*digestalg
; 
1076     mark 
= PORT_ArenaMark(poolp
); 
1078     digestalg 
= PORT_ArenaZAlloc(poolp
, sizeof(SECAlgorithmID
)); 
1079     if (digestalg 
== NULL
) 
1082     if (SECOID_SetAlgorithmID (poolp
, digestalg
, digestalgtag
, NULL
) != SECSuccess
) /* no params */ 
1085     if (SecCmsArrayAdd(poolp
, (void ***)&(sigd
->digestAlgorithms
), (void *)digestalg
) != SECSuccess 
|| 
1086         /* even if digest is NULL, add dummy to have same-size array */ 
1087         SecCmsArrayAdd(poolp
, (void ***)&(sigd
->digests
), (void *)digest
) != SECSuccess
) 
1092     PORT_ArenaUnmark(poolp
, mark
); 
1096     PORT_ArenaRelease(poolp
, mark
); 
1101 SecCmsSignedDataGetDigestValue(SecCmsSignedDataRef sigd
, SECOidTag digestalgtag
) 
1105     if (sigd
->digestAlgorithms 
== NULL
) 
1108     n 
= SecCmsAlgArrayGetIndexByAlgTag(sigd
->digestAlgorithms
, digestalgtag
); 
1110     return (n 
< 0) ? NULL 
: sigd
->digests
[n
]; 
1113 /* ============================================================================= 
1114  * Misc. utility functions 
1118  * SecCmsSignedDataCreateCertsOnly - create a certs-only SignedData. 
1120  * cert          - base certificates that will be included 
1121  * include_chain - if true, include the complete cert chain for cert 
1123  * More certs and chains can be added via AddCertificate and AddCertChain. 
1125  * An error results in a return value of NULL and an error set. 
1130 SecCmsSignedDataCreateCertsOnly(SecCmsMessageRef cmsg
, SecCertificateRef cert
, Boolean include_chain
) 
1132     SecCmsSignedDataRef sigd
; 
1137     poolp 
= cmsg
->poolp
; 
1138     mark 
= PORT_ArenaMark(poolp
); 
1140     sigd 
= SecCmsSignedDataCreate(cmsg
); 
1144     /* no signerinfos, thus no digestAlgorithms */ 
1147     if (include_chain
) { 
1148         rv 
= SecCmsSignedDataAddCertChain(sigd
, cert
); 
1150         rv 
= SecCmsSignedDataAddCertificate(sigd
, cert
); 
1152     if (rv 
!= SECSuccess
) 
1156      * In the degenerate case where there are no signers, the 
1157      * EncapsulatedContentInfo value being "signed" is irrelevant.  In this 
1158      * case, the content type within the EncapsulatedContentInfo value being 
1159      * "signed" should be id-data (as defined in section 4), and the content 
1160      * field of the EncapsulatedContentInfo value should be omitted. 
1162     rv 
= SecCmsContentInfoSetContentData(cmsg
, &(sigd
->contentInfo
), NULL
, PR_TRUE
); 
1163     if (rv 
!= SECSuccess
) 
1166     PORT_ArenaUnmark(poolp
, mark
); 
1171         SecCmsSignedDataDestroy(sigd
); 
1172     PORT_ArenaRelease(poolp
, mark
); 
1177  * Get SecCmsSignedDataRawCerts - obtain raw certs as a NULL_terminated array  
1180 extern OSStatus 
SecCmsSignedDataRawCerts(SecCmsSignedDataRef sigd
, 
1181     CSSM_DATA_PTR 
**rawCerts
) 
1183     *rawCerts 
= sigd
->rawCerts
; 
1188  * SecCmsSignerInfoGetReceiptRequest() 
1189  * SecCmsSignedDataHasReceiptRequest() 
1190  * easy way to iterate over signers