2  * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. Please obtain a copy of the License at 
  10  * http://www.opensource.apple.com/apsl/ and read it before using this 
  13  * The Original Code and all software distributed under the License are 
  14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  18  * Please see the License for the specific language governing rights and 
  19  * limitations under the License. 
  21  * @APPLE_LICENSE_HEADER_END@ 
  23  * tsaSupport.c -  ASN1 templates Time Stamping Authority requests and responses 
  27 #include <Security/SecCmsDigestContext.h> 
  28 #include <Security/SecCmsMessage.h> 
  29 #include <security_asn1/secasn1.h> 
  30 #include <security_asn1/secerr.h> 
  33 #include <security_utilities/debugging.h> 
  34 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h> 
  36 #include <Security/SecCmsDecoder.h> 
  37 #include <Security/SecCmsMessage.h> 
  38 #include <Security/SecCmsContentInfo.h> 
  39 #include <Security/SecCmsSignedData.h> 
  40 #include <Security/SecCmsSignerInfo.h> 
  41 #include "tsaTemplates.h" 
  42 #include <Security/SecAsn1Coder.h> 
  43 #include <AssertMacros.h> 
  44 #include <Security/SecPolicy.h> 
  45 #include <Security/SecTrustPriv.h> 
  46 #include <Security/SecImportExport.h> 
  47 #include <Security/SecCertificatePriv.h> 
  48 #include <security_keychain/SecCertificateP.h> 
  49 #include <security_keychain/SecCertificatePrivP.h> 
  50 #include <utilities/SecCFRelease.h> 
  52 #include "tsaSupport.h" 
  53 #include "tsaSupportPriv.h" 
  54 #include "tsaTemplates.h" 
  61 const CFStringRef kTSAContextKeyURL 
= CFSTR("ServerURL"); 
  62 const CFStringRef kTSAContextKeyNoCerts 
= CFSTR("NoCerts"); 
  63 const CFStringRef kTSADebugContextKeyBadReq 
= CFSTR("DebugBadReq"); 
  64 const CFStringRef kTSADebugContextKeyBadNonce 
= CFSTR("DebugBadNonce"); 
  66 extern const SecAsn1Template kSecAsn1TSATSTInfoTemplate
[]; 
  68 extern OSStatus 
impExpImportCertCommon( 
  69         const CSSM_DATA         
*cdata
, 
  70         SecKeychainRef          importKeychain
, // optional 
  71         CFMutableArrayRef       outArray
);              // optional, append here 
  73 #pragma mark ----- Debug Logs ----- 
  76 #define TSA_USE_SYSLOG 1 
  83     #define tsaDebug(fmt, ...) \ 
  86             struct timeval time_now;   \ 
  87             gettimeofday(&time_now, NULL);  \ 
  88             struct tm* time_info = localtime(&time_now.tv_sec);    \ 
  89             strftime(buf, sizeof(buf), "[%Y-%m-%d %H:%M:%S]", time_info);   \ 
  90                     fprintf(stderr, "%s " fmt, buf, ## __VA_ARGS__); \ 
  91                     syslog(LOG_ERR, " " fmt, ## __VA_ARGS__); \ 
  93     #define tsa_secdebug(scope, format...) \ 
  95         syslog(LOG_NOTICE, format); \ 
  96         secdebug(scope, format); \ 
 100     #define tsaDebug(args...)                   tsa_secdebug("tsa", ## args) 
 101 #define tsa_secdebug(scope, format...) \ 
 102         secdebug(scope, format) 
 106 #define TSTINFO_DEBUG   1   //jch 
 110 #define dtprintf(args...)    tsaDebug(args) 
 112 #define dtprintf(args...) 
 115 #define kHTTPResponseCodeContinue               100 
 116 #define kHTTPResponseCodeOK                     200 
 117 #define kHTTPResponseCodeNoContent              204 
 118 #define kHTTPResponseCodeBadRequest             400 
 119 #define kHTTPResponseCodeUnauthorized           401 
 120 #define kHTTPResponseCodeForbidden              403 
 121 #define kHTTPResponseCodeNotFound               404 
 122 #define kHTTPResponseCodeConflict               409 
 123 #define kHTTPResponseCodeExpectationFailed      417 
 124 #define kHTTPResponseCodeServFail               500 
 125 #define kHTTPResponseCodeServiceUnavailable     503 
 126 #define kHTTPResponseCodeInsufficientStorage    507 
 128 #pragma mark ----- Debug/Utilities ----- 
 130 static OSStatus 
remapHTTPErrorCodes(OSStatus status
) 
 134     case kHTTPResponseCodeOK
: 
 135     case kHTTPResponseCodeContinue
: 
 137     case kHTTPResponseCodeBadRequest
: 
 138         return errSecTimestampBadRequest
; 
 139     case kHTTPResponseCodeNoContent
: 
 140     case kHTTPResponseCodeUnauthorized
: 
 141     case kHTTPResponseCodeForbidden
: 
 142     case kHTTPResponseCodeNotFound
: 
 143     case kHTTPResponseCodeConflict
: 
 144     case kHTTPResponseCodeExpectationFailed
: 
 145     case kHTTPResponseCodeServFail
: 
 146     case kHTTPResponseCodeInsufficientStorage
: 
 147     case kHTTPResponseCodeServiceUnavailable
: 
 148         return errSecTimestampServiceNotAvailable
; 
 156 static void printDataAsHex(const char *title
, const CSSM_DATA 
*d
, unsigned maxToPrint
) // 0 means print it all 
 161     uint32 len 
= (uint32
)d
->Length
; 
 166     const int wrapwid 
= 24;     // large enough so SHA-1 hashes fit on one line... 
 168     if ((maxToPrint 
!= 0) && (len 
> maxToPrint
)) 
 174     bufferSize 
= wrapwid
+3*len
; 
 175     buffer 
= (char *)malloc(bufferSize
); 
 177     offset 
= sprintf(buffer
, "%s [len = %u]\n", title
, len
); 
 178     dtprintf("%s", buffer
); 
 181     for (i
=0; (i 
< len
) && (offset
+3 < bufferSize
); i
++, offset 
+= sz
) 
 183         sz 
= sprintf(buffer 
+ offset
, " %02x", (unsigned int)cp
[i
] & 0xff); 
 184         if ((i 
% wrapwid
) == (wrapwid
-1)) 
 186             dtprintf("%s", buffer
); 
 192     sz
=sprintf(buffer 
+ offset
, more
?" ...\n":"\n"); 
 196 //    fprintf(stderr, "%s", buffer); 
 197     dtprintf("%s", buffer
); 
 204 int tsaWriteFileX(const char *fileName
, const unsigned char *bytes
, size_t numBytes
) 
 209     fd 
= open(fileName
, O_RDWR 
| O_CREAT 
| O_TRUNC
, 0600); 
 213     rtn 
= (int)write(fd
, bytes
, numBytes
); 
 214     if(rtn 
!= (int)numBytes
) 
 217             fprintf(stderr
, "writeFile: short write\n"); 
 228 char *cfStringToChar(CFStringRef inStr
) 
 232     const char *str 
= NULL
; 
 235         return strdup("");     // return a null string 
 238         if ((str 
= CFStringGetCStringPtr(inStr
, kCFStringEncodingUTF8
))) { 
 239         result 
= strdup(str
); 
 241         // need to extract into buffer 
 242         CFIndex length 
= CFStringGetLength(inStr
);  // in 16-bit character units 
 243         CFIndex bytesToAllocate 
= CFStringGetMaximumSizeForEncoding(length
, kCFStringEncodingUTF8
) + 1; 
 244         result 
= malloc(bytesToAllocate
); 
 245         if (!CFStringGetCString(inStr
, result
, bytesToAllocate
, kCFStringEncodingUTF8
)) 
 252 /* Oids longer than this are considered invalid. */ 
 253 #define MAX_OID_SIZE                            32 
 256 /* FIXME: There are other versions of this in SecCertifcate.c and SecCertificateP.c */ 
 257 static CFStringRef 
SecDERItemCopyOIDDecimalRepresentation(CFAllocatorRef allocator
, const CSSM_OID 
*oid
) 
 259         if (oid
->Length 
== 0) 
 260         return CFSTR("<NULL>"); 
 262         if (oid
->Length 
> MAX_OID_SIZE
) 
 263         return CFSTR("Oid too long"); 
 265     CFMutableStringRef result 
= CFStringCreateMutable(allocator
, 0); 
 267         // The first two levels are encoded into one byte, since the root levelq 
 268         // has only 3 nodes (40*x + y).  However if x = joint-iso-itu-t(2) then 
 269         // y may be > 39, so we have to add special-case handling for this. 
 270         uint32_t x 
= oid
->Data
[0] / 40; 
 271         uint32_t y 
= oid
->Data
[0] % 40; 
 274                 // Handle special case for large y if x = 2 
 278     CFStringAppendFormat(result
, NULL
, CFSTR("%u.%u"), x
, y
); 
 281         for (x 
= 1; x 
< oid
->Length
; ++x
) 
 283                 value 
= (value 
<< 7) | (oid
->Data
[x
] & 0x7F); 
 284         /* @@@ value may not span more than 4 bytes. */ 
 285         /* A max number of 20 values is allowed. */ 
 286                 if (!(oid
->Data
[x
] & 0x80)) 
 288             CFStringAppendFormat(result
, NULL
, CFSTR(".%lu"), (unsigned long)value
); 
 296 static void debugSaveCertificates(CSSM_DATA 
**outCerts
) 
 301         CSSM_DATA_PTR 
*certp
; 
 303         const char *certNameBase 
= "/tmp/tsa-resp-cert-"; 
 304         char fname
[PATH_MAX
]; 
 305         unsigned certCount 
= SecCmsArrayCount((void **)outCerts
); 
 306         dtprintf("Found %d certs\n",certCount
); 
 308         for (certp
=outCerts
;*certp
;certp
++, ++jx
) 
 311             strncpy(fname
, certNameBase
, strlen(certNameBase
)+1); 
 312             sprintf(numstr
,"%u", jx
); 
 313             strcat(fname
,numstr
); 
 314             tsaWriteFileX(fname
, (*certp
)->Data
, (*certp
)->Length
); 
 316                 break;  //something wrong 
 322 static void debugShowSignerInfo(SecCmsSignedDataRef signedData
) 
 325     int numberOfSigners 
= SecCmsSignedDataSignerInfoCount (signedData
); 
 326     dtprintf("numberOfSigners : %d\n", numberOfSigners
); 
 328     for (ix
=0;ix 
< numberOfSigners
;ix
++) 
 330         SecCmsSignerInfoRef sigi 
= SecCmsSignedDataGetSignerInfo(signedData
,ix
); 
 333             CFStringRef commonName 
= SecCmsSignerInfoGetSignerCommonName(sigi
); 
 334             const char *signerhdr 
= "      signer    : "; 
 337                 char *cn 
= cfStringToChar(commonName
); 
 338                 dtprintf("%s%s\n", signerhdr
, cn
); 
 341                 CFReleaseNull(commonName
); 
 344                 dtprintf("%s<NULL>\n", signerhdr
); 
 350 static void debugShowContentTypeOID(SecCmsContentInfoRef contentInfo
) 
 354     CSSM_OID 
*typeOID 
= SecCmsContentInfoGetContentTypeOID(contentInfo
); 
 357         CFStringRef oidCFStr 
= SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault
, typeOID
); 
 358         char *oidstr 
= cfStringToChar(oidCFStr
); 
 359         printDataAsHex("oid:", typeOID
, (unsigned int)typeOID
->Length
); 
 360         dtprintf("\toid: %s\n", oidstr
); 
 369 uint64_t tsaDER_ToInt(const CSSM_DATA 
*DER_Data
) 
 374         while(i 
< DER_Data
->Length
) { 
 375                 rtn 
|= DER_Data
->Data
[i
]; 
 376                 if(++i 
== DER_Data
->Length
) { 
 384 void displayTSTInfo(SecAsn1TSATSTInfo 
*tstInfo
) 
 387     dtprintf("--- TSTInfo ---\n"); 
 391     if (tstInfo
->version
.Data
) 
 393         uint64_t vers 
= tsaDER_ToInt(&tstInfo
->version
); 
 394         dtprintf("Version:\t\t%u\n", (int)vers
); 
 397     if (tstInfo
->serialNumber
.Data
) 
 399         uint64_t sn 
= tsaDER_ToInt(&tstInfo
->serialNumber
); 
 400         dtprintf("SerialNumber:\t%llu\n", sn
); 
 403     if (tstInfo
->ordering
.Data
) 
 405         uint64_t ord 
= tsaDER_ToInt(&tstInfo
->ordering
); 
 406         dtprintf("Ordering:\t\t%s\n", ord
?"yes":"no"); 
 409     if (tstInfo
->nonce
.Data
) 
 411         uint64_t nonce 
= tsaDER_ToInt(&tstInfo
->nonce
); 
 412         dtprintf("Nonce:\t\t%llu\n", nonce
); 
 415         dtprintf("Nonce:\t\tnot specified\n"); 
 417     if (tstInfo
->genTime
.Data
) 
 419         char buf
[tstInfo
->genTime
.Length
+1]; 
 420         memcpy(buf
, (const char *)tstInfo
->genTime
.Data
, tstInfo
->genTime
.Length
); 
 421         buf
[tstInfo
->genTime
.Length
]=0; 
 422         dtprintf("GenTime:\t\t%s\n", buf
); 
 425     dtprintf("-- MessageImprint --\n"); 
 426     if (true)   // SecAsn1TSAMessageImprint 
 428         printDataAsHex(" Algorithm:",&tstInfo
->messageImprint
.hashAlgorithm
.algorithm
, 0); 
 429         printDataAsHex(" Message  :", &tstInfo
->messageImprint
.hashedMessage
, 0);//tstInfo->messageImprint.hashedMessage.Length); 
 434 #pragma mark ----- TimeStamp Response using XPC ----- 
 436 #include <xpc/private.h> 
 438 static OSStatus 
checkForNonDERResponse(const unsigned char *resp
, size_t respLen
) 
 441         Good start is something like 30 82 0c 03 30 15 02 01  00 30 10 0c 0e 4f 70 65 
 443         URL:    http://timestamp-int.corp.apple.com/signserver/process?TimeStampSigner 
 444         Resp:   Http/1.1 Service Unavailable 
 446         URL:    http://timestamp-int.corp.apple.com/ts01 
 449         URL:    http://cutandtaste.com/404 (or other forced 404 site) 
 453     OSStatus status 
= noErr
; 
 454     const char ader
[2] = { 0x30, 0x82 }; 
 455     char *respStr 
= NULL
; 
 457     size_t badResponseCount
; 
 459     const char *badResponses
[] = 
 462         "Http/1.1 Service Unavailable", 
 466     require_action(resp 
&& respLen
, xit
, status 
= errSecTimestampServiceNotAvailable
); 
 468     // This is usual case 
 469     if ((respLen 
> 1) && (memcmp(resp
, ader
, 2)==0))    // might be good; pass on to DER decoder 
 472     badResponseCount 
= sizeof(badResponses
)/sizeof(char *); 
 474     for (ix 
= 0; ix 
< badResponseCount
; ++ix
) 
 475         if (strlen(badResponses
[ix
]) > maxlen
) 
 476             maxlen 
= strlen(badResponses
[ix
]); 
 478     // Prevent a large response from allocating a ton of memory 
 479     if (respLen 
> maxlen
) 
 482     respStr 
= (char *)malloc(respLen
+1); 
 483     strlcpy(respStr
, (const char *)resp
, respLen
); 
 485     for (ix 
= 0; ix 
< badResponseCount
; ++ix
) 
 486         if (strcmp(respStr
, badResponses
[ix
])==0) 
 487             return errSecTimestampServiceNotAvailable
; 
 491         free((void *)respStr
); 
 496 static OSStatus 
sendTSARequestWithXPC(const unsigned char *tsaReq
, size_t tsaReqLength
, const unsigned char *tsaURL
, unsigned char **tsaResp
, size_t *tsaRespLength
) 
 498     __block OSStatus result 
= noErr
; 
 499     int timeoutInSeconds 
= 15; 
 500     extern xpc_object_t 
xpc_create_with_format(const char * format
, ...); 
 502         dispatch_queue_t xpc_queue 
= dispatch_queue_create("com.apple.security.XPCTimeStampingService", DISPATCH_QUEUE_SERIAL
); 
 503     __block dispatch_semaphore_t waitSemaphore 
= dispatch_semaphore_create(0); 
 504     dispatch_time_t finishTime 
= dispatch_time(DISPATCH_TIME_NOW
, timeoutInSeconds 
* NSEC_PER_SEC
); 
 506     xpc_connection_t con 
= xpc_connection_create("com.apple.security.XPCTimeStampingService", xpc_queue
); 
 508     xpc_connection_set_event_handler(con
, ^(xpc_object_t event
) { 
 509         xpc_type_t xtype 
= xpc_get_type(event
); 
 510         if (XPC_TYPE_ERROR 
== xtype
) 
 511         {    tsaDebug("default: connection error: %s\n", xpc_dictionary_get_string(event
, XPC_ERROR_KEY_DESCRIPTION
)); } 
 513          {   tsaDebug("default: unexpected connection event %p\n", event
); } 
 516     xpc_connection_resume(con
); 
 518     xpc_object_t tsaReqData 
= xpc_data_create(tsaReq
, tsaReqLength
); 
 519     const char *urlstr 
= (tsaURL
?(const char *)tsaURL
:""); 
 520     xpc_object_t url_as_xpc_string 
= xpc_string_create(urlstr
); 
 522     xpc_object_t message 
= xpc_create_with_format("{operation: TimeStampRequest, ServerURL: %value, TimeStampRequest: %value}", url_as_xpc_string
, tsaReqData
); 
 524     xpc_connection_send_message_with_reply(con
, message
, xpc_queue
, ^(xpc_object_t reply
) 
 526         tsaDebug("xpc_connection_send_message_with_reply handler called back\n"); 
 527         dispatch_retain(waitSemaphore
); 
 529     xpc_type_t xtype 
= xpc_get_type(reply
); 
 530         if (XPC_TYPE_ERROR 
== xtype
) 
 531             {   tsaDebug("message error: %s\n", xpc_dictionary_get_string(reply
, XPC_ERROR_KEY_DESCRIPTION
)); } 
 532         else if (XPC_TYPE_CONNECTION 
== xtype
) 
 533             { tsaDebug("received connection\n"); } 
 534         else if (XPC_TYPE_DICTIONARY 
== xtype
) 
 538          // This is useful for debugging. 
 539         char *debug = xpc_copy_description(reply); 
 540         tsaDebug("DEBUG %s\n", debug); 
 545         xpc_object_t xpcTimeStampReply 
= xpc_dictionary_get_value(reply
, "TimeStampReply"); 
 546         size_t xpcTSRLength 
= xpc_data_get_length(xpcTimeStampReply
); 
 547         tsaDebug("xpcTSRLength: %ld bytes of response\n", xpcTSRLength
); 
 549         xpc_object_t xpcTimeStampError 
= xpc_dictionary_get_value(reply
, "TimeStampError"); 
 550         xpc_object_t xpcTimeStampStatus 
= xpc_dictionary_get_value(reply
, "TimeStampStatus"); 
 552         if (xpcTimeStampError 
|| xpcTimeStampStatus
) 
 555             if (xpcTimeStampError
) 
 557                 size_t len 
= xpc_string_get_length(xpcTimeStampError
); 
 558                 char *buf 
= (char *)malloc(len
); 
 559                 strlcpy(buf
, xpc_string_get_string_ptr(xpcTimeStampError
), len
+1); 
 560                 tsaDebug("xpcTimeStampError: %s\n", buf
); 
 565             if (xpcTimeStampStatus
) 
 567                 result 
= (OSStatus
)xpc_int64_get_value(xpcTimeStampStatus
); 
 568                 tsaDebug("xpcTimeStampStatus: %d\n", (int)result
); 
 572         result 
= remapHTTPErrorCodes(result
); 
 574         if ((result 
== noErr
) && tsaResp 
&& tsaRespLength
) 
 576             *tsaRespLength 
= xpcTSRLength
; 
 577             *tsaResp 
= (unsigned char *)malloc(xpcTSRLength
); 
 579             size_t bytesCopied 
= xpc_data_get_bytes(xpcTimeStampReply
, *tsaResp
, 0, xpcTSRLength
); 
 580             if (bytesCopied 
!= xpcTSRLength
) 
 581             {    tsaDebug("length mismatch: copied: %ld, xpc: %ld\n", bytesCopied
, xpcTSRLength
); } 
 583             if ((result 
= checkForNonDERResponse(*tsaResp
,bytesCopied
))) 
 585                 tsaDebug("received non-DER response from timestamp server\n"); 
 590                 tsaDebug("copied: %ld bytes of response\n", bytesCopied
); 
 593         tsaDebug("releasing connection\n"); 
 597         { tsaDebug("unexpected message reply type %p\n", xtype
); } 
 599         dispatch_semaphore_signal(waitSemaphore
); 
 600         dispatch_release(waitSemaphore
); 
 603     { tsaDebug("waiting up to %d seconds for response from XPC\n", timeoutInSeconds
); } 
 604         dispatch_semaphore_wait(waitSemaphore
, finishTime
); 
 606         dispatch_release(waitSemaphore
); 
 607     xpc_release(tsaReqData
); 
 608     xpc_release(message
); 
 610     { tsaDebug("sendTSARequestWithXPC exit\n"); } 
 615 #pragma mark ----- TimeStamp request ----- 
 617 #include "tsaTemplates.h" 
 618 #include <security_asn1/SecAsn1Coder.h> 
 619 #include <Security/oidsalg.h> 
 620 #include <AssertMacros.h> 
 621 #include <libkern/OSByteOrder.h> 
 623 extern const SecAsn1Template kSecAsn1TSATimeStampReqTemplate
; 
 624 extern const SecAsn1Template kSecAsn1TSATimeStampRespTemplateDER
; 
 626 CFMutableDictionaryRef 
SecCmsTSAGetDefaultContext(CFErrorRef 
*error
) 
 628     // Caller responsible for retain/release 
 629     // <rdar://problem/11077440> Update SecCmsTSAGetDefaultContext with actual URL for Apple Timestamp server 
 630     //      URL will be in TimeStampingPrefs.plist 
 632     CFBundleRef secFWbundle 
= NULL
; 
 633     CFURLRef resourceURL 
= NULL
; 
 634     CFDataRef resourceData 
= NULL
; 
 635     CFPropertyListRef prefs 
= NULL
; 
 636     CFMutableDictionaryRef contextDict 
= NULL
; 
 637     SInt32 errorCode 
= 0; 
 638     CFOptionFlags options 
= 0; 
 639     CFPropertyListFormat format 
= 0; 
 640     OSStatus status 
= noErr
; 
 642     require_action(secFWbundle 
= CFBundleGetBundleWithIdentifier(CFSTR("com.apple.security")), xit
, status 
= errSecInternalError
); 
 643     require_action(resourceURL 
= CFBundleCopyResourceURL(secFWbundle
, CFSTR("TimeStampingPrefs"), CFSTR("plist"), NULL
), 
 644         xit
, status 
= errSecInvalidPrefsDomain
); 
 646     require(CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault
, resourceURL
, &resourceData
, 
 647         NULL
, NULL
, &errorCode
), xit
); 
 648     require_action(resourceData
, xit
, status 
= errSecDataNotAvailable
); 
 650     prefs 
= CFPropertyListCreateWithData(kCFAllocatorDefault
, resourceData
, options
, &format
, error
); 
 651     require_action(prefs 
&& (CFGetTypeID(prefs
)==CFDictionaryGetTypeID()), xit
, status 
= errSecInvalidPrefsDomain
); 
 653     contextDict 
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, prefs
); 
 661         *error 
= CFErrorCreate(kCFAllocatorDefault
, kCFErrorDomainOSStatus
, status
, NULL
); 
 663         CFRelease(secFWbundle
); 
 665         CFRelease(resourceURL
); 
 667         CFRelease(resourceData
); 
 674 static CFDataRef 
_SecTSARequestCopyDEREncoding(SecAsn1TSAMessageImprint 
*messageImprint
, bool noCerts
, uint64_t nonce
) 
 676     // Returns DER encoded TimeStampReq 
 677     // Modeled on _SecOCSPRequestCopyDEREncoding 
 678     // The Timestamp Authority supports 64 bit nonces (or more possibly) 
 680     SecAsn1CoderRef             coder 
= NULL
; 
 682     SecAsn1Item                 vers 
= {1, &version
}; 
 683     uint8_t                     creq 
= noCerts
?0:1; 
 684     SecAsn1Item                 certReq 
= {1, &creq
};   //jch - to request or not? 
 685     SecAsn1TSATimeStampReq      tsreq 
= {}; 
 686     CFDataRef                   der 
= NULL
; 
 687     uint64_t                    nonceVal 
= OSSwapHostToBigConstInt64(nonce
); 
 688     SecAsn1Item                 nonceItem 
= {sizeof(uint64_t), (unsigned char *)&nonceVal
}; 
 690     uint8_t OID_FakePolicy_Data
[] = { 0x2A, 0x03, 0x04, 0x05, 0x06}; 
 691     const CSSM_OID fakePolicyOID 
= {sizeof(OID_FakePolicy_Data
),OID_FakePolicy_Data
}; 
 693     tsreq
.version 
= vers
; 
 695     tsreq
.messageImprint 
= *messageImprint
; 
 696     tsreq
.certReq 
= certReq
; 
 698     // skip reqPolicy, extensions for now - FAKES - jch 
 699     tsreq
.reqPolicy 
= fakePolicyOID
;    //policyID; 
 701     tsreq
.nonce 
= nonceItem
; 
 703     // Encode the request 
 704     require_noerr(SecAsn1CoderCreate(&coder
), errOut
); 
 707     require_noerr(SecAsn1EncodeItem(coder
, &tsreq
, 
 708         &kSecAsn1TSATimeStampReqTemplate
, &encoded
), errOut
); 
 709     der 
= CFDataCreate(kCFAllocatorDefault
, encoded
.Data
, 
 714         SecAsn1CoderRelease(coder
); 
 719 OSStatus 
SecTSAResponseCopyDEREncoding(SecAsn1CoderRef coder
, const CSSM_DATA 
*tsaResponse
, SecAsn1TimeStampRespDER 
*respDER
) 
 721     // Partially decode the response 
 722     OSStatus status 
= paramErr
; 
 724     require(tsaResponse 
&& respDER
, errOut
); 
 725     require_noerr(SecAsn1DecodeData(coder
, tsaResponse
, 
 726         &kSecAsn1TSATimeStampRespTemplateDER
, respDER
), errOut
); 
 734 #pragma mark ----- TS Callback ----- 
 736 OSStatus 
SecCmsTSADefaultCallback(CFTypeRef context
, void *messageImprintV
, uint64_t nonce
, CSSM_DATA 
*signedDERBlob
) 
 738     OSStatus result 
= paramErr
; 
 739     const unsigned char *tsaReq 
= NULL
; 
 740     size_t tsaReqLength 
= 0; 
 741     CFDataRef cfreq 
= NULL
; 
 742     unsigned char *tsaURL 
= NULL
; 
 743     bool noCerts 
= false; 
 745     if (!context 
|| CFGetTypeID(context
)!=CFDictionaryGetTypeID()) 
 748     SecAsn1TSAMessageImprint 
*messageImprint 
= (SecAsn1TSAMessageImprint 
*)messageImprintV
; 
 749     if (!messageImprint 
|| !signedDERBlob
) 
 752     CFBooleanRef cfnocerts 
= (CFBooleanRef
)CFDictionaryGetValue((CFDictionaryRef
)context
, kTSAContextKeyNoCerts
); 
 755         tsaDebug("[TSA] Request noCerts\n"); 
 756         noCerts 
= CFBooleanGetValue(cfnocerts
); 
 759     // We must spoof the nonce here, before sending the request. 
 760     // If we tried to alter the reply, then the signature would break instead. 
 761     CFBooleanRef cfBadNonce 
= (CFBooleanRef
)CFDictionaryGetValue((CFDictionaryRef
)context
, kTSADebugContextKeyBadNonce
); 
 762     if (cfBadNonce 
&& CFBooleanGetValue(cfBadNonce
)) 
 764         tsaDebug("[TSA] Forcing bad TS Request by changing nonce\n"); 
 768     printDataAsHex("[TSA] hashToTimeStamp:", &messageImprint
->hashedMessage
,128); 
 769     cfreq 
= _SecTSARequestCopyDEREncoding(messageImprint
, noCerts
, nonce
); 
 772         tsaReq 
= CFDataGetBytePtr(cfreq
); 
 773         tsaReqLength 
= CFDataGetLength(cfreq
); 
 777         tsaWriteFileX("/tmp/tsareq.req", tsaReq
, tsaReqLength
); 
 781     CFStringRef url 
= (CFStringRef
)CFDictionaryGetValue((CFDictionaryRef
)context
, kTSAContextKeyURL
); 
 784         tsaDebug("[TSA] missing URL for TSA (key: %s)\n", "kTSAContextKeyURL"); 
 789         If debugging, look at special values in the context to mess things up 
 792     CFBooleanRef cfBadReq 
= (CFBooleanRef
)CFDictionaryGetValue((CFDictionaryRef
)context
, kTSADebugContextKeyBadReq
); 
 793     if (cfBadReq 
&& CFBooleanGetValue(cfBadReq
)) 
 795         tsaDebug("[TSA] Forcing bad TS Request by truncating length from %ld to %ld\n", tsaReqLength
, (tsaReqLength
-4)); 
 799     // need to extract into buffer 
 800     CFIndex length 
= CFStringGetLength(url
);        // in 16-bit character units 
 801     tsaURL 
= malloc(6 * length 
+ 1);                // pessimistic 
 802     if (!CFStringGetCString(url
, (char *)tsaURL
, 6 * length 
+ 1, kCFStringEncodingUTF8
)) 
 805     tsaDebug("[TSA] URL for timestamp server: %s\n", tsaURL
); 
 807     unsigned char *tsaResp 
= NULL
; 
 808     size_t tsaRespLength 
= 0; 
 809     tsaDebug("calling sendTSARequestWithXPC with %ld bytes of request\n", tsaReqLength
); 
 811     require_noerr(result 
= sendTSARequestWithXPC(tsaReq
, tsaReqLength
, tsaURL
, &tsaResp
, &tsaRespLength
), xit
); 
 813     tsaDebug("sendTSARequestWithXPC copied: %ld bytes of response\n", tsaRespLength
); 
 815     signedDERBlob
->Data 
= tsaResp
; 
 816     signedDERBlob
->Length 
= tsaRespLength
; 
 822         free((void *)tsaURL
); 
 829 #pragma mark ----- TimeStamp Verification ----- 
 831 static OSStatus 
convertGeneralizedTimeToCFAbsoluteTime(const char *timeStr
, CFAbsoluteTime 
*ptime
) 
 834         See http://userguide.icu-project.org/formatparse/datetime for date/time format. 
 835         The "Z" signal a GMT time, but CFDateFormatterGetAbsoluteTimeFromString returns 
 836         values based on local time. 
 839     OSStatus result 
= noErr
; 
 840     CFDateFormatterRef formatter 
= NULL
; 
 841     CFStringRef time_string 
= NULL
; 
 842     CFTimeZoneRef gmt 
= NULL
; 
 843     CFLocaleRef locale 
= NULL
; 
 844     CFRange 
*rangep 
= NULL
; 
 846     require(timeStr 
&& timeStr
[0] && ptime
, xit
); 
 847     require(formatter 
= CFDateFormatterCreate(kCFAllocatorDefault
, locale
, kCFDateFormatterNoStyle
, kCFDateFormatterNoStyle
), xit
); 
 848 //    CFRetain(formatter); 
 849     CFDateFormatterSetFormat(formatter
, CFSTR("yyyyMMddHHmmss'Z'"));    // GeneralizedTime 
 850     gmt 
= CFTimeZoneCreateWithTimeIntervalFromGMT(NULL
, 0); 
 851         CFDateFormatterSetProperty(formatter
, kCFDateFormatterTimeZone
, gmt
); 
 853     time_string 
= CFStringCreateWithCString(kCFAllocatorDefault
, timeStr
, kCFStringEncodingUTF8
); 
 854     if (!time_string 
|| !CFDateFormatterGetAbsoluteTimeFromString(formatter
, time_string
, rangep
, ptime
)) 
 856         dtprintf("%s is not a valid date\n", timeStr
); 
 862         CFRelease(formatter
); 
 864         CFRelease(time_string
); 
 871 static OSStatus 
SecTSAValidateTimestamp(const SecAsn1TSATSTInfo 
*tstInfo
, CSSM_DATA 
**signingCerts
, CFAbsoluteTime 
*timestampTime
) 
 873     // See <rdar://problem/11077708> Properly handle revocation information of timestamping certificate 
 874     OSStatus result 
= paramErr
; 
 875     CFAbsoluteTime genTime 
= 0; 
 876     char timeStr
[32] = {0,}; 
 877     SecCertificateRef signingCertificate 
= NULL
; 
 879     require(tstInfo 
&& signingCerts 
&& (tstInfo
->genTime
.Length 
< 16), xit
); 
 881     // Find the leaf signingCert 
 882     require_noerr(result 
= SecCertificateCreateFromData(*signingCerts
, 
 883         CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_DER
, &signingCertificate
), xit
); 
 885     memcpy(timeStr
, tstInfo
->genTime
.Data
, tstInfo
->genTime
.Length
); 
 886     timeStr
[tstInfo
->genTime
.Length
] = 0; 
 887     require_noerr(convertGeneralizedTimeToCFAbsoluteTime(timeStr
, &genTime
), xit
); 
 888     if (SecCertificateIsValidX(signingCertificate
, genTime
)) // iOS? 
 891         result 
= errSecTimestampInvalid
; 
 893         *timestampTime 
= genTime
; 
 895     if (signingCertificate
) 
 896         CFReleaseNull(signingCertificate
); 
 900 static OSStatus 
verifyTSTInfo(const CSSM_DATA_PTR content
, CSSM_DATA 
**signingCerts
, SecAsn1TSATSTInfo 
*tstInfo
, CFAbsoluteTime 
*timestampTime
, uint64_t expectedNonce
) 
 902     OSStatus status 
= paramErr
; 
 903     SecAsn1CoderRef coder 
= NULL
; 
 908     require_noerr(SecAsn1CoderCreate(&coder
), xit
); 
 909     require_noerr(SecAsn1Decode(coder
, content
->Data
, content
->Length
, 
 910                 kSecAsn1TSATSTInfoTemplate
, tstInfo
), xit
); 
 911     displayTSTInfo(tstInfo
); 
 914     if (tstInfo
->nonce
.Data 
&& expectedNonce
!=0) 
 916         uint64_t nonce 
= tsaDER_ToInt(&tstInfo
->nonce
); 
 917      //   if (expectedNonce!=nonce) 
 918             dtprintf("verifyTSTInfo nonce: actual: %lld, expected: %lld\n", nonce
, expectedNonce
); 
 919         require_action(expectedNonce
==nonce
, xit
, status 
= errSecTimestampRejection
); 
 922     status 
= SecTSAValidateTimestamp(tstInfo
, signingCerts
, timestampTime
); 
 923     dtprintf("SecTSAValidateTimestamp result: %ld\n", (long)status
); 
 927         SecAsn1CoderRelease(coder
); 
 931 static void debugShowExtendedTrustResult(int index
, CFDictionaryRef extendedResult
) 
 936         CFStringRef xresStr 
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, 
 937         CFSTR("Extended trust result for signer #%d : %@"), index
, extendedResult
); 
 948 extern const char *cssmErrorString(CSSM_RETURN error
); 
 950 static void statusBitTest(CSSM_TP_APPLE_CERT_STATUS certStatus
, uint32 bit
, const char *str
) 
 952         if (certStatus 
& bit
) 
 953                 dtprintf("%s  ", str
); 
 957 static void debugShowCertEvidenceInfo(uint16_t certCount
, const CSSM_TP_APPLE_EVIDENCE_INFO 
*info
) 
 960         CSSM_TP_APPLE_CERT_STATUS cs
; 
 961 //      const CSSM_TP_APPLE_EVIDENCE_INFO *pinfo = info; 
 963         for (ix
=0; info 
&& (ix
<certCount
); ix
++, ++info
) 
 965                 cs 
= info
->StatusBits
; 
 966                 dtprintf("   cert %u:\n", ix
); 
 967                 dtprintf("      StatusBits     : 0x%x", (unsigned)cs
); 
 971                         statusBitTest(cs
, CSSM_CERT_STATUS_EXPIRED
, "EXPIRED"); 
 972                         statusBitTest(cs
, CSSM_CERT_STATUS_NOT_VALID_YET
, 
 974                         statusBitTest(cs
, CSSM_CERT_STATUS_IS_IN_INPUT_CERTS
, 
 975                                 "IS_IN_INPUT_CERTS"); 
 976                         statusBitTest(cs
, CSSM_CERT_STATUS_IS_IN_ANCHORS
, 
 978                         statusBitTest(cs
, CSSM_CERT_STATUS_IS_ROOT
, "IS_ROOT"); 
 979                         statusBitTest(cs
, CSSM_CERT_STATUS_IS_FROM_NET
, "IS_FROM_NET"); 
 985                 dtprintf("      NumStatusCodes : %u ", info
->NumStatusCodes
); 
 986         CSSM_RETURN 
*pstatuscode 
= info
->StatusCodes
; 
 988         for (jx
=0; pstatuscode 
&& (jx
<info
->NumStatusCodes
); jx
++, ++pstatuscode
) 
 989             dtprintf("%s  ", cssmErrorString(*pstatuscode
)); 
 992                 dtprintf("      Index: %u\n", info
->Index
); 
 999 static const char *trustResultTypeString(SecTrustResultType trustResultType
) 
1001     switch (trustResultType
) 
1003     case kSecTrustResultProceed
:                    return "TrustResultProceed"; 
1004     case kSecTrustResultUnspecified
:                return "TrustResultUnspecified"; 
1005     case kSecTrustResultDeny
:                       return "TrustResultDeny";   // user reject 
1006     case kSecTrustResultInvalid
:                    return "TrustResultInvalid"; 
1007     case kSecTrustResultConfirm
:                    return "TrustResultConfirm"; 
1008     case kSecTrustResultRecoverableTrustFailure
:    return "TrustResultRecoverableTrustFailure"; 
1009     case kSecTrustResultFatalTrustFailure
:          return "TrustResultUnspecified"; 
1010     case kSecTrustResultOtherError
:                 return "TrustResultOtherError"; 
1011     default:                                        return "TrustResultUnknown"; 
1017 static OSStatus 
verifySigners(SecCmsSignedDataRef signedData
, int numberOfSigners
, CFTypeRef timeStampPolicy
) 
1019     // See <rdar://problem/11077588> Bubble up SecTrustEvaluate of timestamp response to high level callers 
1020     // Also <rdar://problem/11077708> Properly handle revocation information of timestamping certificate 
1022     SecTrustRef trustRef 
= NULL
; 
1023     CFTypeRef policy 
= CFRetainSafe(timeStampPolicy
); 
1024     int result
=errSecInternalError
; 
1028         require(policy 
= SecPolicyCreateWithOID(kSecPolicyAppleTimeStamping
), xit
); 
1032     for (jx 
= 0; jx 
< numberOfSigners
; ++jx
) 
1034         SecTrustResultType trustResultType
; 
1035         CFDictionaryRef extendedResult 
= NULL
; 
1036         CFArrayRef certChain 
= NULL
; 
1037         uint16_t certCount 
= 0; 
1039         CSSM_TP_APPLE_EVIDENCE_INFO 
*statusChain 
= NULL
; 
1041         // SecCmsSignedDataVerifySignerInfo returns trustRef, which we can call SecTrustEvaluate on 
1042         // usually (always?) if result is noErr, the SecTrust*Result calls will return errSecTrustNotAvailable 
1043         result 
= SecCmsSignedDataVerifySignerInfo (signedData
, jx
, NULL
, policy
, &trustRef
); 
1044         dtprintf("[%s] SecCmsSignedDataVerifySignerInfo: result: %d, signer: %d\n", 
1045             __FUNCTION__
, result
, jx
); 
1046          require_noerr(result
, xit
); 
1048         result 
= SecTrustEvaluate (trustRef
, &trustResultType
); 
1049         dtprintf("[%s] SecTrustEvaluate: result: %d, trustResult: %s (%d)\n", 
1050             __FUNCTION__
, result
, trustResultTypeString(trustResultType
), trustResultType
); 
1053         switch (trustResultType
) 
1055                 case kSecTrustResultProceed
: 
1056                 case kSecTrustResultUnspecified
: 
1058                 case kSecTrustResultDeny
:                   // user reject 
1059                         result 
= errSecTimestampNotTrusted
;     // SecCmsVSTimestampNotTrusted ? 
1061                 case kSecTrustResultInvalid
: 
1062                         assert(false);                          // should never happen 
1063                         result 
= errSecTimestampNotTrusted
;     // SecCmsVSTimestampNotTrusted ? 
1065         case kSecTrustResultConfirm
: 
1066         case kSecTrustResultRecoverableTrustFailure
: 
1067         case kSecTrustResultFatalTrustFailure
: 
1068         case kSecTrustResultOtherError
: 
1072                     There are two "errors" that need to be resolved externally: 
1073                     CSSMERR_TP_CERT_EXPIRED can be OK if the timestamp was made 
1074                     before the TSA chain expired; CSSMERR_TP_CERT_NOT_VALID_YET 
1075                     can happen in the case where the user's clock was set to 0. 
1076                     We don't want to prevent them using apps automatically, so 
1077                     return noErr and let codesign or whover decide. 
1079                                 OSStatus resultCode
; 
1080                                 require_action(SecTrustGetCssmResultCode(trustRef
, &resultCode
)==noErr
, xit
, result 
= errSecTimestampNotTrusted
); 
1081                                 result 
= (resultCode 
== CSSMERR_TP_CERT_EXPIRED 
|| resultCode 
== CSSMERR_TP_CERT_NOT_VALID_YET
)?noErr
:errSecTimestampNotTrusted
; 
1086         rx 
= SecTrustGetResult(trustRef
, &trustResultType
, &certChain
, &statusChain
); 
1087         dtprintf("[%s] SecTrustGetResult: result: %d, type: %d\n", __FUNCTION__
,rx
, trustResultType
); 
1088         certCount 
= certChain
?CFArrayGetCount(certChain
):0; 
1089         debugShowCertEvidenceInfo(certCount
, statusChain
); 
1090         CFReleaseNull(certChain
); 
1092         rx 
= SecTrustCopyExtendedResult(trustRef
, &extendedResult
); 
1093         dtprintf("[%s] SecTrustCopyExtendedResult: result: %d\n", __FUNCTION__
, rx
); 
1096             debugShowExtendedTrustResult(jx
, extendedResult
); 
1097             CFRelease(extendedResult
); 
1101             CFReleaseNull(trustRef
); 
1106         CFReleaseNull(trustRef
); 
1112 static OSStatus 
impExpImportCertUnCommon( 
1113         const CSSM_DATA         
*cdata
, 
1114         SecKeychainRef          importKeychain
, // optional 
1115         CFMutableArrayRef       outArray
)               // optional, append here 
1117     // The only difference between this and impExpImportCertCommon is that we append to outArray 
1118     // before attempting to add to the keychain 
1119         OSStatus status 
= noErr
; 
1120         SecCertificateRef certRef 
= NULL
; 
1122     require_action(cdata
, xit
, status 
= errSecUnsupportedFormat
); 
1124         /* Pass kCFAllocatorNull as bytesDeallocator to assure the bytes aren't freed */ 
1125         CFDataRef data 
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, (const UInt8 
*)cdata
->Data
, (CFIndex
)cdata
->Length
, kCFAllocatorNull
); 
1126     require_action(data
, xit
, status 
= errSecUnsupportedFormat
); 
1128         certRef 
= SecCertificateCreateWithData(kCFAllocatorDefault
, data
); 
1129         CFRelease(data
); /* certRef has its own copy of the data now */ 
1131                 dtprintf("impExpHandleCert error\n"); 
1132                 return errSecUnsupportedFormat
; 
1136                 CFArrayAppendValue(outArray
, certRef
); 
1140                 status 
= SecCertificateAddToKeychain(certRef
, importKeychain
); 
1141                 if (status
!=noErr 
&& status
!=errSecDuplicateItem
) 
1142             { dtprintf("SecCertificateAddToKeychain error: %ld\n", (long)status
); } 
1151 static void saveTSACertificates(CSSM_DATA 
**signingCerts
, CFMutableArrayRef     outArray
) 
1153     SecKeychainRef defaultKeychain 
= NULL
; 
1154     // Don't save certificates in keychain to avoid securityd issues 
1155 //  if (SecKeychainCopyDefault(&defaultKeychain)) 
1156 //     defaultKeychain = NULL; 
1158     unsigned certCount 
= SecCmsArrayCount((void **)signingCerts
); 
1160     for (dex
=0; dex
<certCount
; dex
++) 
1162         OSStatus rx 
= impExpImportCertUnCommon(signingCerts
[dex
], defaultKeychain
, outArray
); 
1163         if (rx
!=noErr 
&& rx
!=errSecDuplicateItem
) 
1164             dtprintf("impExpImportCertCommon failed: %ld\n", (long)rx
); 
1166     if (defaultKeychain
) 
1167         CFRelease(defaultKeychain
); 
1170 static const char *cfabsoluteTimeToString(CFAbsoluteTime abstime
) 
1172     CFGregorianDate greg 
= CFAbsoluteTimeGetGregorianDate(abstime
, NULL
); 
1174     if (19 != snprintf(str
, 20, "%4.4d-%2.2d-%2.2d_%2.2d:%2.2d:%2.2d", 
1175         (int)greg
.year
, greg
.month
, greg
.day
, greg
.hour
, greg
.minute
, (int)greg
.second
)) 
1177     char *data 
= (char *)malloc(20); 
1178     strncpy(data
, str
, 20); 
1182 static OSStatus 
setTSALeafValidityDates(SecCmsSignerInfoRef signerinfo
) 
1184     OSStatus status 
= noErr
; 
1186     if (!signerinfo
->timestampCertList 
|| (CFArrayGetCount(signerinfo
->timestampCertList
) == 0)) 
1187         return SecCmsVSSigningCertNotFound
; 
1189     SecCertificateRef tsaLeaf 
= (SecCertificateRef
)CFArrayGetValueAtIndex(signerinfo
->timestampCertList
, 0); 
1190     require_action(tsaLeaf
, xit
, status 
= errSecCertificateCannotOperate
); 
1192     signerinfo
->tsaLeafNotBefore 
= SecCertificateNotValidBefore(tsaLeaf
); /* Start date for Timestamp Authority leaf */ 
1193     signerinfo
->tsaLeafNotAfter 
= SecCertificateNotValidAfter(tsaLeaf
);   /* Expiration date for Timestamp Authority leaf */ 
1195     const char *nbefore 
= cfabsoluteTimeToString(signerinfo
->tsaLeafNotBefore
); 
1196     const char *nafter 
= cfabsoluteTimeToString(signerinfo
->tsaLeafNotAfter
); 
1197     if (nbefore 
&& nafter
) 
1199         dtprintf("Timestamp Authority leaf valid from %s to %s\n", nbefore
, nafter
); 
1200         free((void *)nbefore
);free((void *)nafter
); 
1205                         status = errSecCertificateNotValidYet; 
1207                         status = errSecCertificateExpired; 
1215     From RFC 3161: Time-Stamp Protocol (TSP),August 2001, APPENDIX B: 
1217     B) The validity of the digital signature may then be verified in the 
1220         1)  The time-stamp token itself MUST be verified and it MUST be 
1221             verified that it applies to the signature of the signer. 
1223         2)  The date/time indicated by the TSA in the TimeStampToken 
1226         3)  The certificate used by the signer MUST be identified and 
1229         4)  The date/time indicated by the TSA MUST be within the 
1230             validity period of the signer's certificate. 
1232         5)  The revocation information about that certificate, at the 
1233             date/time of the Time-Stamping operation, MUST be retrieved. 
1235         6)  Should the certificate be revoked, then the date/time of 
1236             revocation shall be later than the date/time indicated by 
1239     If all these conditions are successful, then the digital signature 
1240     shall be declared as valid. 
1244 OSStatus 
decodeTimeStampToken(SecCmsSignerInfoRef signerinfo
, CSSM_DATA_PTR inData
, CSSM_DATA_PTR encDigest
, uint64_t expectedNonce
) 
1246     return decodeTimeStampTokenWithPolicy(signerinfo
, NULL
, inData
, encDigest
, expectedNonce
); 
1249 OSStatus 
decodeTimeStampTokenWithPolicy(SecCmsSignerInfoRef signerinfo
, CFTypeRef timeStampPolicy
, CSSM_DATA_PTR inData
, CSSM_DATA_PTR encDigest
, uint64_t expectedNonce
) 
1252         We update signerinfo with timestamp and tsa certificate chain. 
1253         encDigest is the original signed blob, which we must hash and compare. 
1254         inData comes from the unAuthAttr section of the CMS message 
1256         These are set in signerinfo as side effects: 
1261     SecCmsDecoderRef        decoderContext 
= NULL
; 
1262     SecCmsMessageRef        cmsMessage 
= NULL
; 
1263     SecCmsContentInfoRef    contentInfo
; 
1264     SecCmsSignedDataRef     signedData
; 
1265     SECOidTag               contentTypeTag
; 
1266     int                     contentLevelCount
; 
1268     OSStatus                result 
= errSecUnknownFormat
; 
1269     CSSM_DATA               
**signingCerts 
= NULL
; 
1271     dtprintf("decodeTimeStampToken top: PORT_GetError() %d -----\n", PORT_GetError()); 
1274     /* decode the message */ 
1275     require_noerr(result 
= SecCmsDecoderCreate (NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &decoderContext
), xit
); 
1276     result 
= SecCmsDecoderUpdate(decoderContext
, inData
->Data
, inData
->Length
); 
1279         result 
= errSecTimestampInvalid
; 
1280         SecCmsDecoderDestroy(decoderContext
); 
1284     require_noerr(result 
= SecCmsDecoderFinish(decoderContext
, &cmsMessage
), xit
); 
1286     // process the results 
1287     contentLevelCount 
= SecCmsMessageContentLevelCount(cmsMessage
); 
1290         printDataAsHex("encDigest",encDigest
, 0); 
1292     for (ix 
= 0; ix 
< contentLevelCount
; ++ix
) 
1294         dtprintf("\n----- Content Level %d -----\n", ix
); 
1295         // get content information 
1296         contentInfo 
= SecCmsMessageContentLevel (cmsMessage
, ix
); 
1297         contentTypeTag 
= SecCmsContentInfoGetContentTypeTag (contentInfo
); 
1299         // After 2nd round, contentInfo.content.data is the TSTInfo 
1301         debugShowContentTypeOID(contentInfo
); 
1303         switch (contentTypeTag
) 
1305         case SEC_OID_PKCS7_SIGNED_DATA
: 
1307             require((signedData 
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(contentInfo
)) != NULL
, xit
); 
1309             debugShowSignerInfo(signedData
); 
1311             SECAlgorithmID 
**digestAlgorithms 
= SecCmsSignedDataGetDigestAlgs(signedData
); 
1312             unsigned digestAlgCount 
= SecCmsArrayCount((void **)digestAlgorithms
); 
1313             dtprintf("digestAlgCount: %d\n", digestAlgCount
); 
1314             if (signedData
->digests
) 
1318                 for (jx
=0;jx 
< digestAlgCount
;jx
++) 
1320                     sprintf(buffer
, " digest[%u]", jx
); 
1321                     printDataAsHex(buffer
,signedData
->digests
[jx
], 0); 
1326                 dtprintf("No digests\n"); 
1327                 CSSM_DATA_PTR innerContent 
= SecCmsContentInfoGetInnerContent(contentInfo
); 
1330                     dtprintf("inner content length: %ld\n", innerContent
->Length
); 
1331                     SecAsn1TSAMessageImprint fakeMessageImprint 
= {{{0}},}; 
1332                     OSStatus status 
= createTSAMessageImprint(signedData
, innerContent
, &fakeMessageImprint
); 
1334                         {    dtprintf("createTSAMessageImprint status: %d\n", (int)status
); } 
1335                     printDataAsHex("inner content hash",&fakeMessageImprint
.hashedMessage
, 0); 
1336                     CSSM_DATA_PTR digestdata 
= &fakeMessageImprint
.hashedMessage
; 
1337                     CSSM_DATA_PTR digests
[2] = {digestdata
, NULL
}; 
1338                     SecCmsSignedDataSetDigests(signedData
, digestAlgorithms
, (CSSM_DATA_PTR 
*)&digests
); 
1341                     dtprintf("no inner content\n"); 
1345                 Import the certificates. We leave this as a warning, since 
1346                 there are configurations where the certificates are not returned. 
1348             signingCerts 
= SecCmsSignedDataGetCertificateList(signedData
); 
1349             if (signingCerts 
== NULL
) 
1350             {    dtprintf("SecCmsSignedDataGetCertificateList returned NULL\n"); } 
1353                 if (!signerinfo
->timestampCertList
) 
1354                     signerinfo
->timestampCertList 
= CFArrayCreateMutable(kCFAllocatorDefault
, 10, &kCFTypeArrayCallBacks
); 
1355                 saveTSACertificates(signingCerts
, signerinfo
->timestampCertList
); 
1356                 require_noerr(result 
= setTSALeafValidityDates(signerinfo
), xit
); 
1357                 debugSaveCertificates(signingCerts
); 
1360             int numberOfSigners 
= SecCmsSignedDataSignerInfoCount (signedData
); 
1362             result 
= verifySigners(signedData
, numberOfSigners
, timeStampPolicy
); 
1364                 dtprintf("verifySigners failed: %ld\n", (long)result
);   // warning 
1367             if (result
)     // remap to SecCmsVSTimestampNotTrusted ? 
1372         case SEC_OID_PKCS9_SIGNING_CERTIFICATE
: 
1374             dtprintf("SEC_OID_PKCS9_SIGNING_CERTIFICATE seen\n"); 
1378         case SEC_OID_PKCS9_ID_CT_TSTInfo
: 
1380             SecAsn1TSATSTInfo tstInfo 
= {{0},}; 
1381             result 
= verifyTSTInfo(contentInfo
->rawContent
, signingCerts
, &tstInfo
, &signerinfo
->timestampTime
, expectedNonce
); 
1382             if (signerinfo
->timestampTime
) 
1384                 const char *tstamp 
= cfabsoluteTimeToString(signerinfo
->timestampTime
); 
1387                     dtprintf("Timestamp Authority timestamp: %s\n", tstamp
); 
1388                     free((void *)tstamp
); 
1395             dtprintf("otherContent : %p\n", (char *)SecCmsContentInfoGetContent (contentInfo
)); 
1399             dtprintf("ContentTypeTag : %x\n", contentTypeTag
); 
1405                 SecCmsMessageDestroy(cmsMessage
);