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> 
  51 #include <utilities/SecDispatchRelease.h> 
  53 #include "tsaSupport.h" 
  54 #include "tsaSupportPriv.h" 
  55 #include "tsaTemplates.h" 
  62 const CFStringRef kTSAContextKeyURL 
= CFSTR("ServerURL"); 
  63 const CFStringRef kTSAContextKeyNoCerts 
= CFSTR("NoCerts"); 
  64 const CFStringRef kTSADebugContextKeyBadReq 
= CFSTR("DebugBadReq"); 
  65 const CFStringRef kTSADebugContextKeyBadNonce 
= CFSTR("DebugBadNonce"); 
  67 extern const SecAsn1Template kSecAsn1TSATSTInfoTemplate
[]; 
  69 extern OSStatus 
impExpImportCertCommon( 
  70         const CSSM_DATA         
*cdata
, 
  71         SecKeychainRef          importKeychain
, // optional 
  72         CFMutableArrayRef       outArray
);              // optional, append here 
  74 #pragma mark ----- Debug Logs ----- 
  77 #define TSA_USE_SYSLOG 1 
  84     #define tsaDebug(fmt, ...) \ 
  87             struct timeval time_now;   \ 
  88             gettimeofday(&time_now, NULL);  \ 
  89             struct tm* time_info = localtime(&time_now.tv_sec);    \ 
  90             strftime(buf, sizeof(buf), "[%Y-%m-%d %H:%M:%S]", time_info);   \ 
  91                     fprintf(stderr, "%s " fmt, buf, ## __VA_ARGS__); \ 
  92                     syslog(LOG_ERR, " " fmt, ## __VA_ARGS__); \ 
  94     #define tsa_secinfo(scope, format...) \ 
  96         syslog(LOG_NOTICE, format); \ 
  97         secinfo(scope, format); \ 
 101     #define tsaDebug(args...)                   tsa_secinfo("tsa", ## args) 
 102 #define tsa_secinfo(scope, format...) \ 
 103         secinfo(scope, format) 
 107 #define TSTINFO_DEBUG   1   //jch 
 111 #define dtprintf(args...)    tsaDebug(args) 
 113 #define dtprintf(args...) 
 116 #define kHTTPResponseCodeContinue               100 
 117 #define kHTTPResponseCodeOK                     200 
 118 #define kHTTPResponseCodeNoContent              204 
 119 #define kHTTPResponseCodeBadRequest             400 
 120 #define kHTTPResponseCodeUnauthorized           401 
 121 #define kHTTPResponseCodeForbidden              403 
 122 #define kHTTPResponseCodeNotFound               404 
 123 #define kHTTPResponseCodeConflict               409 
 124 #define kHTTPResponseCodeExpectationFailed      417 
 125 #define kHTTPResponseCodeServFail               500 
 126 #define kHTTPResponseCodeServiceUnavailable     503 
 127 #define kHTTPResponseCodeInsufficientStorage    507 
 129 #pragma mark ----- Debug/Utilities ----- 
 131 static OSStatus 
remapHTTPErrorCodes(OSStatus status
) 
 135     case kHTTPResponseCodeOK
: 
 136     case kHTTPResponseCodeContinue
: 
 138     case kHTTPResponseCodeBadRequest
: 
 139         return errSecTimestampBadRequest
; 
 140     case kHTTPResponseCodeNoContent
: 
 141     case kHTTPResponseCodeUnauthorized
: 
 142     case kHTTPResponseCodeForbidden
: 
 143     case kHTTPResponseCodeNotFound
: 
 144     case kHTTPResponseCodeConflict
: 
 145     case kHTTPResponseCodeExpectationFailed
: 
 146     case kHTTPResponseCodeServFail
: 
 147     case kHTTPResponseCodeInsufficientStorage
: 
 148     case kHTTPResponseCodeServiceUnavailable
: 
 149         return errSecTimestampServiceNotAvailable
; 
 157 static void printDataAsHex(const char *title
, const CSSM_DATA 
*d
, unsigned maxToPrint
) // 0 means print it all 
 162     uint32 len 
= (uint32
)d
->Length
; 
 167     const int wrapwid 
= 24;     // large enough so SHA-1 hashes fit on one line... 
 169     if ((maxToPrint 
!= 0) && (len 
> maxToPrint
)) 
 175     bufferSize 
= wrapwid
+3*len
; 
 176     buffer 
= (char *)malloc(bufferSize
); 
 178     offset 
= sprintf(buffer
, "%s [len = %u]\n", title
, len
); 
 179     dtprintf("%s", buffer
); 
 182     for (i
=0; (i 
< len
) && (offset
+3 < bufferSize
); i
++, offset 
+= sz
) 
 184         sz 
= sprintf(buffer 
+ offset
, " %02x", (unsigned int)cp
[i
] & 0xff); 
 185         if ((i 
% wrapwid
) == (wrapwid
-1)) 
 187             dtprintf("%s", buffer
); 
 193     sz
=sprintf(buffer 
+ offset
, more
?" ...\n":"\n"); 
 197 //    fprintf(stderr, "%s", buffer); 
 198     dtprintf("%s", buffer
); 
 205 int tsaWriteFileX(const char *fileName
, const unsigned char *bytes
, size_t numBytes
) 
 210     fd 
= open(fileName
, O_RDWR 
| O_CREAT 
| O_TRUNC
, 0600); 
 214     rtn 
= (int)write(fd
, bytes
, numBytes
); 
 215     if(rtn 
!= (int)numBytes
) 
 218             fprintf(stderr
, "writeFile: short write\n"); 
 229 char *cfStringToChar(CFStringRef inStr
) 
 233     const char *str 
= NULL
; 
 236         return strdup("");     // return a null string 
 239         if ((str 
= CFStringGetCStringPtr(inStr
, kCFStringEncodingUTF8
))) { 
 240         result 
= strdup(str
); 
 242         // need to extract into buffer 
 243         CFIndex length 
= CFStringGetLength(inStr
);  // in 16-bit character units 
 244         CFIndex bytesToAllocate 
= CFStringGetMaximumSizeForEncoding(length
, kCFStringEncodingUTF8
) + 1; 
 245         result 
= malloc(bytesToAllocate
); 
 246         if (!CFStringGetCString(inStr
, result
, bytesToAllocate
, kCFStringEncodingUTF8
)) 
 253 /* Oids longer than this are considered invalid. */ 
 254 #define MAX_OID_SIZE                            32 
 257 /* FIXME: There are other versions of this in SecCertifcate.c and SecCertificateP.c */ 
 258 static CFStringRef 
SecDERItemCopyOIDDecimalRepresentation(CFAllocatorRef allocator
, const CSSM_OID 
*oid
) 
 260         if (oid
->Length 
== 0) 
 261         return CFSTR("<NULL>"); 
 263         if (oid
->Length 
> MAX_OID_SIZE
) 
 264         return CFSTR("Oid too long"); 
 266     CFMutableStringRef result 
= CFStringCreateMutable(allocator
, 0); 
 268         // The first two levels are encoded into one byte, since the root levelq 
 269         // has only 3 nodes (40*x + y).  However if x = joint-iso-itu-t(2) then 
 270         // y may be > 39, so we have to add special-case handling for this. 
 271         uint32_t x 
= oid
->Data
[0] / 40; 
 272         uint32_t y 
= oid
->Data
[0] % 40; 
 275                 // Handle special case for large y if x = 2 
 279     CFStringAppendFormat(result
, NULL
, CFSTR("%u.%u"), x
, y
); 
 282         for (x 
= 1; x 
< oid
->Length
; ++x
) 
 284                 value 
= (value 
<< 7) | (oid
->Data
[x
] & 0x7F); 
 285         /* @@@ value may not span more than 4 bytes. */ 
 286         /* A max number of 20 values is allowed. */ 
 287                 if (!(oid
->Data
[x
] & 0x80)) 
 289             CFStringAppendFormat(result
, NULL
, CFSTR(".%lu"), (unsigned long)value
); 
 297 static void debugSaveCertificates(CSSM_DATA 
**outCerts
) 
 302         CSSM_DATA_PTR 
*certp
; 
 304         const char *certNameBase 
= "/tmp/tsa-resp-cert-"; 
 305         char fname
[PATH_MAX
]; 
 306         unsigned certCount 
= SecCmsArrayCount((void **)outCerts
); 
 307         dtprintf("Found %d certs\n",certCount
); 
 309         for (certp
=outCerts
;*certp
;certp
++, ++jx
) 
 312             strncpy(fname
, certNameBase
, strlen(certNameBase
)+1); 
 313             sprintf(numstr
,"%u", jx
); 
 314             strcat(fname
,numstr
); 
 315             tsaWriteFileX(fname
, (*certp
)->Data
, (*certp
)->Length
); 
 317                 break;  //something wrong 
 323 static void debugShowSignerInfo(SecCmsSignedDataRef signedData
) 
 326     int numberOfSigners 
= SecCmsSignedDataSignerInfoCount (signedData
); 
 327     dtprintf("numberOfSigners : %d\n", numberOfSigners
); 
 329     for (ix
=0;ix 
< numberOfSigners
;ix
++) 
 331         SecCmsSignerInfoRef sigi 
= SecCmsSignedDataGetSignerInfo(signedData
,ix
); 
 334             CFStringRef commonName 
= SecCmsSignerInfoGetSignerCommonName(sigi
); 
 335             const char *signerhdr 
= "      signer    : "; 
 338                 char *cn 
= cfStringToChar(commonName
); 
 339                 dtprintf("%s%s\n", signerhdr
, cn
); 
 342                 CFReleaseNull(commonName
); 
 345                 dtprintf("%s<NULL>\n", signerhdr
); 
 351 static void debugShowContentTypeOID(SecCmsContentInfoRef contentInfo
) 
 355     CSSM_OID 
*typeOID 
= SecCmsContentInfoGetContentTypeOID(contentInfo
); 
 358         CFStringRef oidCFStr 
= SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault
, typeOID
); 
 359         char *oidstr 
= cfStringToChar(oidCFStr
); 
 360         printDataAsHex("oid:", typeOID
, (unsigned int)typeOID
->Length
); 
 361         dtprintf("\toid: %s\n", oidstr
); 
 370 uint64_t tsaDER_ToInt(const CSSM_DATA 
*DER_Data
) 
 375         while(i 
< DER_Data
->Length
) { 
 376                 rtn 
|= DER_Data
->Data
[i
]; 
 377                 if(++i 
== DER_Data
->Length
) { 
 385 void displayTSTInfo(SecAsn1TSATSTInfo 
*tstInfo
) 
 388     dtprintf("--- TSTInfo ---\n"); 
 392     if (tstInfo
->version
.Data
) 
 394         uint64_t vers 
= tsaDER_ToInt(&tstInfo
->version
); 
 395         dtprintf("Version:\t\t%u\n", (int)vers
); 
 398     if (tstInfo
->serialNumber
.Data
) 
 400         uint64_t sn 
= tsaDER_ToInt(&tstInfo
->serialNumber
); 
 401         dtprintf("SerialNumber:\t%llu\n", sn
); 
 404     if (tstInfo
->ordering
.Data
) 
 406         uint64_t ord 
= tsaDER_ToInt(&tstInfo
->ordering
); 
 407         dtprintf("Ordering:\t\t%s\n", ord
?"yes":"no"); 
 410     if (tstInfo
->nonce
.Data
) 
 412         uint64_t nonce 
= tsaDER_ToInt(&tstInfo
->nonce
); 
 413         dtprintf("Nonce:\t\t%llu\n", nonce
); 
 416         dtprintf("Nonce:\t\tnot specified\n"); 
 418     if (tstInfo
->genTime
.Data
) 
 420         char buf
[tstInfo
->genTime
.Length
+1]; 
 421         memcpy(buf
, (const char *)tstInfo
->genTime
.Data
, tstInfo
->genTime
.Length
); 
 422         buf
[tstInfo
->genTime
.Length
]=0; 
 423         dtprintf("GenTime:\t\t%s\n", buf
); 
 426     dtprintf("-- MessageImprint --\n"); 
 427     if (true)   // SecAsn1TSAMessageImprint 
 429         printDataAsHex(" Algorithm:",&tstInfo
->messageImprint
.hashAlgorithm
.algorithm
, 0); 
 430         printDataAsHex(" Message  :", &tstInfo
->messageImprint
.hashedMessage
, 0);//tstInfo->messageImprint.hashedMessage.Length); 
 435 #pragma mark ----- TimeStamp Response using XPC ----- 
 437 #include <xpc/private.h> 
 439 static OSStatus 
checkForNonDERResponse(const unsigned char *resp
, size_t respLen
) 
 442         Good start is something like 30 82 0c 03 30 15 02 01  00 30 10 0c 0e 4f 70 65 
 444         URL:    http://timestamp-int.corp.apple.com/signserver/process?TimeStampSigner 
 445         Resp:   Http/1.1 Service Unavailable 
 447         URL:    http://timestamp-int.corp.apple.com/ts01 
 450         URL:    http://cutandtaste.com/404 (or other forced 404 site) 
 454     OSStatus status 
= noErr
; 
 455     const char ader
[2] = { 0x30, 0x82 }; 
 456     char *respStr 
= NULL
; 
 458     size_t badResponseCount
; 
 460     const char *badResponses
[] = 
 463         "Http/1.1 Service Unavailable", 
 467     require_action(resp 
&& respLen
, xit
, status 
= errSecTimestampServiceNotAvailable
); 
 469     // This is usual case 
 470     if ((respLen 
> 1) && (memcmp(resp
, ader
, 2)==0))    // might be good; pass on to DER decoder 
 473     badResponseCount 
= sizeof(badResponses
)/sizeof(char *); 
 475     for (ix 
= 0; ix 
< badResponseCount
; ++ix
) 
 476         if (strlen(badResponses
[ix
]) > maxlen
) 
 477             maxlen 
= strlen(badResponses
[ix
]); 
 479     // Prevent a large response from allocating a ton of memory 
 480     if (respLen 
> maxlen
) 
 483     respStr 
= (char *)malloc(respLen
+1); 
 484     strlcpy(respStr
, (const char *)resp
, respLen
); 
 486     for (ix 
= 0; ix 
< badResponseCount
; ++ix
) 
 487         if (strcmp(respStr
, badResponses
[ix
])==0) 
 488             return errSecTimestampServiceNotAvailable
; 
 492         free((void *)respStr
); 
 497 static OSStatus 
sendTSARequestWithXPC(const unsigned char *tsaReq
, size_t tsaReqLength
, const unsigned char *tsaURL
, unsigned char **tsaResp
, size_t *tsaRespLength
) 
 499     __block OSStatus result 
= noErr
; 
 500     int timeoutInSeconds 
= 15; 
 501     extern xpc_object_t 
xpc_create_with_format(const char * format
, ...); 
 503         dispatch_queue_t xpc_queue 
= dispatch_queue_create("com.apple.security.XPCTimeStampingService", DISPATCH_QUEUE_SERIAL
); 
 504     __block dispatch_semaphore_t waitSemaphore 
= dispatch_semaphore_create(0); 
 505     dispatch_time_t finishTime 
= dispatch_time(DISPATCH_TIME_NOW
, timeoutInSeconds 
* NSEC_PER_SEC
); 
 507     xpc_connection_t con 
= xpc_connection_create("com.apple.security.XPCTimeStampingService", xpc_queue
); 
 509     xpc_connection_set_event_handler(con
, ^(xpc_object_t event
) { 
 510         xpc_type_t xtype 
= xpc_get_type(event
); 
 511         if (XPC_TYPE_ERROR 
== xtype
) 
 512         {    tsaDebug("default: connection error: %s\n", xpc_dictionary_get_string(event
, XPC_ERROR_KEY_DESCRIPTION
)); } 
 514          {   tsaDebug("default: unexpected connection event %p\n", event
); } 
 517     xpc_connection_resume(con
); 
 519     xpc_object_t tsaReqData 
= xpc_data_create(tsaReq
, tsaReqLength
); 
 520     const char *urlstr 
= (tsaURL
?(const char *)tsaURL
:""); 
 521     xpc_object_t url_as_xpc_string 
= xpc_string_create(urlstr
); 
 523     xpc_object_t message 
= xpc_create_with_format("{operation: TimeStampRequest, ServerURL: %value, TimeStampRequest: %value}", url_as_xpc_string
, tsaReqData
); 
 525     xpc_connection_send_message_with_reply(con
, message
, xpc_queue
, ^(xpc_object_t reply
) 
 527         tsaDebug("xpc_connection_send_message_with_reply handler called back\n"); 
 528         dispatch_retain_safe(waitSemaphore
); 
 530         xpc_type_t xtype 
= xpc_get_type(reply
); 
 531         if (XPC_TYPE_ERROR 
== xtype
) 
 532             {   tsaDebug("message error: %s\n", xpc_dictionary_get_string(reply
, XPC_ERROR_KEY_DESCRIPTION
)); } 
 533         else if (XPC_TYPE_CONNECTION 
== xtype
) 
 534             { tsaDebug("received connection\n"); } 
 535         else if (XPC_TYPE_DICTIONARY 
== xtype
) 
 539          // This is useful for debugging. 
 540         char *debug = xpc_copy_description(reply); 
 541         tsaDebug("DEBUG %s\n", debug); 
 546         xpc_object_t xpcTimeStampReply 
= xpc_dictionary_get_value(reply
, "TimeStampReply"); 
 547         size_t xpcTSRLength 
= xpc_data_get_length(xpcTimeStampReply
); 
 548         tsaDebug("xpcTSRLength: %ld bytes of response\n", xpcTSRLength
); 
 550         xpc_object_t xpcTimeStampError 
= xpc_dictionary_get_value(reply
, "TimeStampError"); 
 551         xpc_object_t xpcTimeStampStatus 
= xpc_dictionary_get_value(reply
, "TimeStampStatus"); 
 553         if (xpcTimeStampError 
|| xpcTimeStampStatus
) 
 556             if (xpcTimeStampError
) 
 558                 size_t len 
= xpc_string_get_length(xpcTimeStampError
); 
 559                 char *buf 
= (char *)malloc(len
); 
 560                 strlcpy(buf
, xpc_string_get_string_ptr(xpcTimeStampError
), len
+1); 
 561                 tsaDebug("xpcTimeStampError: %s\n", buf
); 
 566             if (xpcTimeStampStatus
) 
 568                 result 
= (OSStatus
)xpc_int64_get_value(xpcTimeStampStatus
); 
 569                 tsaDebug("xpcTimeStampStatus: %d\n", (int)result
); 
 573         result 
= remapHTTPErrorCodes(result
); 
 575         if ((result 
== noErr
) && tsaResp 
&& tsaRespLength
) 
 577             *tsaRespLength 
= xpcTSRLength
; 
 578             *tsaResp 
= (unsigned char *)malloc(xpcTSRLength
); 
 580             size_t bytesCopied 
= xpc_data_get_bytes(xpcTimeStampReply
, *tsaResp
, 0, xpcTSRLength
); 
 581             if (bytesCopied 
!= xpcTSRLength
) 
 582             {    tsaDebug("length mismatch: copied: %ld, xpc: %ld\n", bytesCopied
, xpcTSRLength
); } 
 584             if ((result 
= checkForNonDERResponse(*tsaResp
,bytesCopied
))) 
 586                 tsaDebug("received non-DER response from timestamp server\n"); 
 591                 tsaDebug("copied: %ld bytes of response\n", bytesCopied
); 
 594         tsaDebug("releasing connection\n"); 
 598         { tsaDebug("unexpected message reply type %p\n", xtype
); } 
 599         if (waitSemaphore
) { dispatch_semaphore_signal(waitSemaphore
); } 
 600         dispatch_release_null(waitSemaphore
); 
 602     { tsaDebug("waiting up to %d seconds for response from XPC\n", timeoutInSeconds
); } 
 603     if (waitSemaphore
) { dispatch_semaphore_wait(waitSemaphore
, finishTime
); } 
 605     dispatch_release_null(waitSemaphore
); 
 606     xpc_release(tsaReqData
); 
 607     xpc_release(message
); 
 609     { tsaDebug("sendTSARequestWithXPC exit\n"); } 
 614 #pragma mark ----- TimeStamp request ----- 
 616 #include "tsaTemplates.h" 
 617 #include <security_asn1/SecAsn1Coder.h> 
 618 #include <Security/oidsalg.h> 
 619 #include <AssertMacros.h> 
 620 #include <libkern/OSByteOrder.h> 
 622 extern const SecAsn1Template kSecAsn1TSATimeStampReqTemplate
; 
 623 extern const SecAsn1Template kSecAsn1TSATimeStampRespTemplateDER
; 
 625 CFMutableDictionaryRef 
SecCmsTSAGetDefaultContext(CFErrorRef 
*error
) 
 627     // Caller responsible for retain/release 
 628     // <rdar://problem/11077440> Update SecCmsTSAGetDefaultContext with actual URL for Apple Timestamp server 
 629     //      URL will be in TimeStampingPrefs.plist 
 631     CFBundleRef secFWbundle 
= NULL
; 
 632     CFURLRef resourceURL 
= NULL
; 
 633     CFDataRef resourceData 
= NULL
; 
 634     CFPropertyListRef prefs 
= NULL
; 
 635     CFMutableDictionaryRef contextDict 
= NULL
; 
 636     SInt32 errorCode 
= 0; 
 637     CFOptionFlags options 
= 0; 
 638     CFPropertyListFormat format 
= 0; 
 639     OSStatus status 
= noErr
; 
 641     require_action(secFWbundle 
= CFBundleGetBundleWithIdentifier(CFSTR("com.apple.security")), xit
, status 
= errSecInternalError
); 
 642     CFRetain(secFWbundle
); 
 644     require_action(resourceURL 
= CFBundleCopyResourceURL(secFWbundle
, CFSTR("TimeStampingPrefs"), CFSTR("plist"), NULL
), 
 645         xit
, status 
= errSecInvalidPrefsDomain
); 
 647     require(CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault
, resourceURL
, &resourceData
, 
 648         NULL
, NULL
, &errorCode
), xit
); 
 649     require_action(resourceData
, xit
, status 
= errSecDataNotAvailable
); 
 651     prefs 
= CFPropertyListCreateWithData(kCFAllocatorDefault
, resourceData
, options
, &format
, error
); 
 652     require_action(prefs 
&& (CFGetTypeID(prefs
)==CFDictionaryGetTypeID()), xit
, status 
= errSecInvalidPrefsDomain
); 
 654     contextDict 
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, prefs
); 
 662         *error 
= CFErrorCreate(kCFAllocatorDefault
, kCFErrorDomainOSStatus
, status
, NULL
); 
 664         CFRelease(secFWbundle
); 
 666         CFRelease(resourceURL
); 
 668         CFRelease(resourceData
); 
 675 static CFDataRef 
_SecTSARequestCopyDEREncoding(SecAsn1TSAMessageImprint 
*messageImprint
, bool noCerts
, uint64_t nonce
) 
 677     // Returns DER encoded TimeStampReq 
 678     // Modeled on _SecOCSPRequestCopyDEREncoding 
 679     // The Timestamp Authority supports 64 bit nonces (or more possibly) 
 681     SecAsn1CoderRef             coder 
= NULL
; 
 683     SecAsn1Item                 vers 
= {1, &version
}; 
 684     uint8_t                     creq 
= noCerts
?0:1; 
 685     SecAsn1Item                 certReq 
= {1, &creq
};   //jch - to request or not? 
 686     SecAsn1TSATimeStampReq      tsreq 
= {}; 
 687     CFDataRef                   der 
= NULL
; 
 688     uint64_t                    nonceVal 
= OSSwapHostToBigConstInt64(nonce
); 
 689     SecAsn1Item                 nonceItem 
= {sizeof(uint64_t), (unsigned char *)&nonceVal
}; 
 691     uint8_t OID_FakePolicy_Data
[] = { 0x2A, 0x03, 0x04, 0x05, 0x06}; 
 692     const CSSM_OID fakePolicyOID 
= {sizeof(OID_FakePolicy_Data
),OID_FakePolicy_Data
}; 
 694     tsreq
.version 
= vers
; 
 696     tsreq
.messageImprint 
= *messageImprint
; 
 697     tsreq
.certReq 
= certReq
; 
 699     // skip reqPolicy, extensions for now - FAKES - jch 
 700     tsreq
.reqPolicy 
= fakePolicyOID
;    //policyID; 
 702     tsreq
.nonce 
= nonceItem
; 
 704     // Encode the request 
 705     require_noerr(SecAsn1CoderCreate(&coder
), errOut
); 
 708     require_noerr(SecAsn1EncodeItem(coder
, &tsreq
, 
 709         &kSecAsn1TSATimeStampReqTemplate
, &encoded
), errOut
); 
 710     der 
= CFDataCreate(kCFAllocatorDefault
, encoded
.Data
, 
 715         SecAsn1CoderRelease(coder
); 
 720 OSStatus 
SecTSAResponseCopyDEREncoding(SecAsn1CoderRef coder
, const CSSM_DATA 
*tsaResponse
, SecAsn1TimeStampRespDER 
*respDER
) 
 722     // Partially decode the response 
 723     OSStatus status 
= paramErr
; 
 725     require(tsaResponse 
&& respDER
, errOut
); 
 726     require_noerr(SecAsn1DecodeData(coder
, tsaResponse
, 
 727         &kSecAsn1TSATimeStampRespTemplateDER
, respDER
), errOut
); 
 735 #pragma mark ----- TS Callback ----- 
 737 OSStatus 
SecCmsTSADefaultCallback(CFTypeRef context
, void *messageImprintV
, uint64_t nonce
, CSSM_DATA 
*signedDERBlob
) 
 739     OSStatus result 
= paramErr
; 
 740     const unsigned char *tsaReq 
= NULL
; 
 741     size_t tsaReqLength 
= 0; 
 742     CFDataRef cfreq 
= NULL
; 
 743     unsigned char *tsaURL 
= NULL
; 
 744     bool noCerts 
= false; 
 746     if (!context 
|| CFGetTypeID(context
)!=CFDictionaryGetTypeID()) 
 749     SecAsn1TSAMessageImprint 
*messageImprint 
= (SecAsn1TSAMessageImprint 
*)messageImprintV
; 
 750     if (!messageImprint 
|| !signedDERBlob
) 
 753     CFBooleanRef cfnocerts 
= (CFBooleanRef
)CFDictionaryGetValue((CFDictionaryRef
)context
, kTSAContextKeyNoCerts
); 
 756         tsaDebug("[TSA] Request noCerts\n"); 
 757         noCerts 
= CFBooleanGetValue(cfnocerts
); 
 760     // We must spoof the nonce here, before sending the request. 
 761     // If we tried to alter the reply, then the signature would break instead. 
 762     CFBooleanRef cfBadNonce 
= (CFBooleanRef
)CFDictionaryGetValue((CFDictionaryRef
)context
, kTSADebugContextKeyBadNonce
); 
 763     if (cfBadNonce 
&& CFBooleanGetValue(cfBadNonce
)) 
 765         tsaDebug("[TSA] Forcing bad TS Request by changing nonce\n"); 
 769     printDataAsHex("[TSA] hashToTimeStamp:", &messageImprint
->hashedMessage
,128); 
 770     cfreq 
= _SecTSARequestCopyDEREncoding(messageImprint
, noCerts
, nonce
); 
 773         tsaReq 
= CFDataGetBytePtr(cfreq
); 
 774         tsaReqLength 
= CFDataGetLength(cfreq
); 
 778         tsaWriteFileX("/tmp/tsareq.req", tsaReq
, tsaReqLength
); 
 782     CFTypeRef url 
= CFDictionaryGetValue((CFDictionaryRef
)context
, kTSAContextKeyURL
); 
 785         tsaDebug("[TSA] missing URL for TSA (key: %s)\n", "kTSAContextKeyURL"); 
 789     CFStringRef urlStr 
= NULL
; 
 790     if (CFURLGetTypeID() == CFGetTypeID(url
)) { 
 791         urlStr 
= CFURLGetString(url
); 
 793         require_quiet(CFStringGetTypeID() == CFGetTypeID(url
), xit
); 
 796     require_quiet(urlStr
, xit
); 
 799         If debugging, look at special values in the context to mess things up 
 802     CFBooleanRef cfBadReq 
= (CFBooleanRef
)CFDictionaryGetValue((CFDictionaryRef
)context
, kTSADebugContextKeyBadReq
); 
 803     if (cfBadReq 
&& CFBooleanGetValue(cfBadReq
)) 
 805         tsaDebug("[TSA] Forcing bad TS Request by truncating length from %ld to %ld\n", tsaReqLength
, (tsaReqLength
-4)); 
 809     // need to extract into buffer 
 810     CFIndex length 
= CFStringGetLength(urlStr
);        // in 16-bit character units 
 811     tsaURL 
= malloc(6 * length 
+ 1);                // pessimistic 
 812     if (!CFStringGetCString(urlStr
, (char *)tsaURL
, 6 * length 
+ 1, kCFStringEncodingUTF8
)) 
 815     tsaDebug("[TSA] URL for timestamp server: %s\n", tsaURL
); 
 817     unsigned char *tsaResp 
= NULL
; 
 818     size_t tsaRespLength 
= 0; 
 819     tsaDebug("calling sendTSARequestWithXPC with %ld bytes of request\n", tsaReqLength
); 
 821     require_noerr(result 
= sendTSARequestWithXPC(tsaReq
, tsaReqLength
, tsaURL
, &tsaResp
, &tsaRespLength
), xit
); 
 823     tsaDebug("sendTSARequestWithXPC copied: %ld bytes of response\n", tsaRespLength
); 
 825     signedDERBlob
->Data 
= tsaResp
; 
 826     signedDERBlob
->Length 
= tsaRespLength
; 
 832         free((void *)tsaURL
); 
 839 #pragma mark ----- TimeStamp Verification ----- 
 841 static OSStatus 
convertGeneralizedTimeToCFAbsoluteTime(const char *timeStr
, CFAbsoluteTime 
*ptime
) 
 844         See http://userguide.icu-project.org/formatparse/datetime for date/time format. 
 845         The "Z" signal a GMT time, but CFDateFormatterGetAbsoluteTimeFromString returns 
 846         values based on local time. 
 849     OSStatus result 
= noErr
; 
 850     CFDateFormatterRef formatter 
= NULL
; 
 851     CFStringRef time_string 
= NULL
; 
 852     CFTimeZoneRef gmt 
= NULL
; 
 853     CFLocaleRef locale 
= NULL
; 
 854     CFRange 
*rangep 
= NULL
; 
 856     require(timeStr 
&& timeStr
[0] && ptime
, xit
); 
 857     require(formatter 
= CFDateFormatterCreate(kCFAllocatorDefault
, locale
, kCFDateFormatterNoStyle
, kCFDateFormatterNoStyle
), xit
); 
 858 //    CFRetain(formatter); 
 859     CFDateFormatterSetFormat(formatter
, CFSTR("yyyyMMddHHmmss'Z'"));    // GeneralizedTime 
 860     gmt 
= CFTimeZoneCreateWithTimeIntervalFromGMT(NULL
, 0); 
 861         CFDateFormatterSetProperty(formatter
, kCFDateFormatterTimeZone
, gmt
); 
 863     time_string 
= CFStringCreateWithCString(kCFAllocatorDefault
, timeStr
, kCFStringEncodingUTF8
); 
 864     if (!time_string 
|| !CFDateFormatterGetAbsoluteTimeFromString(formatter
, time_string
, rangep
, ptime
)) 
 866         dtprintf("%s is not a valid date\n", timeStr
); 
 872         CFRelease(formatter
); 
 874         CFRelease(time_string
); 
 881 static OSStatus 
SecTSAValidateTimestamp(const SecAsn1TSATSTInfo 
*tstInfo
, CSSM_DATA 
**signingCerts
, CFAbsoluteTime 
*timestampTime
) 
 883     // See <rdar://problem/11077708> Properly handle revocation information of timestamping certificate 
 884     OSStatus result 
= paramErr
; 
 885     CFAbsoluteTime genTime 
= 0; 
 886     char timeStr
[32] = {0,}; 
 887     SecCertificateRef signingCertificate 
= NULL
; 
 889     require(tstInfo 
&& signingCerts 
&& (tstInfo
->genTime
.Length 
< 16), xit
); 
 891     // Find the leaf signingCert 
 892     require_noerr(result 
= SecCertificateCreateFromData(*signingCerts
, 
 893         CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_DER
, &signingCertificate
), xit
); 
 895     memcpy(timeStr
, tstInfo
->genTime
.Data
, tstInfo
->genTime
.Length
); 
 896     timeStr
[tstInfo
->genTime
.Length
] = 0; 
 897     require_noerr(convertGeneralizedTimeToCFAbsoluteTime(timeStr
, &genTime
), xit
); 
 898     if (SecCertificateIsValidX(signingCertificate
, genTime
)) // iOS? 
 901         result 
= errSecTimestampInvalid
; 
 903         *timestampTime 
= genTime
; 
 905     if (signingCertificate
) 
 906         CFReleaseNull(signingCertificate
); 
 910 static OSStatus 
verifyTSTInfo(const CSSM_DATA_PTR content
, CSSM_DATA 
**signingCerts
, SecAsn1TSATSTInfo 
*tstInfo
, CFAbsoluteTime 
*timestampTime
, uint64_t expectedNonce
) 
 912     OSStatus status 
= paramErr
; 
 913     SecAsn1CoderRef coder 
= NULL
; 
 918     require_noerr(SecAsn1CoderCreate(&coder
), xit
); 
 919     require_noerr(SecAsn1Decode(coder
, content
->Data
, content
->Length
, 
 920                 kSecAsn1TSATSTInfoTemplate
, tstInfo
), xit
); 
 921     displayTSTInfo(tstInfo
); 
 924     if (tstInfo
->nonce
.Data 
&& expectedNonce
!=0) 
 926         uint64_t nonce 
= tsaDER_ToInt(&tstInfo
->nonce
); 
 927      //   if (expectedNonce!=nonce) 
 928             dtprintf("verifyTSTInfo nonce: actual: %lld, expected: %lld\n", nonce
, expectedNonce
); 
 929         require_action(expectedNonce
==nonce
, xit
, status 
= errSecTimestampRejection
); 
 932     status 
= SecTSAValidateTimestamp(tstInfo
, signingCerts
, timestampTime
); 
 933     dtprintf("SecTSAValidateTimestamp result: %ld\n", (long)status
); 
 937         SecAsn1CoderRelease(coder
); 
 941 static void debugShowExtendedTrustResult(int index
, CFDictionaryRef extendedResult
) 
 946         CFStringRef xresStr 
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, 
 947         CFSTR("Extended trust result for signer #%d : %@"), index
, extendedResult
); 
 958 extern const char *cssmErrorString(CSSM_RETURN error
); 
 960 static void statusBitTest(CSSM_TP_APPLE_CERT_STATUS certStatus
, uint32 bit
, const char *str
) 
 962         if (certStatus 
& bit
) 
 963                 dtprintf("%s  ", str
); 
 967 static void debugShowCertEvidenceInfo(uint16_t certCount
, const CSSM_TP_APPLE_EVIDENCE_INFO 
*info
) 
 970         CSSM_TP_APPLE_CERT_STATUS cs
; 
 971 //      const CSSM_TP_APPLE_EVIDENCE_INFO *pinfo = info; 
 973         for (ix
=0; info 
&& (ix
<certCount
); ix
++, ++info
) 
 975                 cs 
= info
->StatusBits
; 
 976                 dtprintf("   cert %u:\n", ix
); 
 977                 dtprintf("      StatusBits     : 0x%x", (unsigned)cs
); 
 981                         statusBitTest(cs
, CSSM_CERT_STATUS_EXPIRED
, "EXPIRED"); 
 982                         statusBitTest(cs
, CSSM_CERT_STATUS_NOT_VALID_YET
, 
 984                         statusBitTest(cs
, CSSM_CERT_STATUS_IS_IN_INPUT_CERTS
, 
 985                                 "IS_IN_INPUT_CERTS"); 
 986                         statusBitTest(cs
, CSSM_CERT_STATUS_IS_IN_ANCHORS
, 
 988                         statusBitTest(cs
, CSSM_CERT_STATUS_IS_ROOT
, "IS_ROOT"); 
 989                         statusBitTest(cs
, CSSM_CERT_STATUS_IS_FROM_NET
, "IS_FROM_NET"); 
 995                 dtprintf("      NumStatusCodes : %u ", info
->NumStatusCodes
); 
 996         CSSM_RETURN 
*pstatuscode 
= info
->StatusCodes
; 
 998         for (jx
=0; pstatuscode 
&& (jx
<info
->NumStatusCodes
); jx
++, ++pstatuscode
) 
 999             dtprintf("%s  ", cssmErrorString(*pstatuscode
)); 
1002                 dtprintf("      Index: %u\n", info
->Index
); 
1009 static const char *trustResultTypeString(SecTrustResultType trustResultType
) 
1011     switch (trustResultType
) 
1013     case kSecTrustResultProceed
:                    return "TrustResultProceed"; 
1014     case kSecTrustResultUnspecified
:                return "TrustResultUnspecified"; 
1015     case kSecTrustResultDeny
:                       return "TrustResultDeny";   // user reject 
1016     case kSecTrustResultInvalid
:                    return "TrustResultInvalid"; 
1017     case kSecTrustResultConfirm
:                    return "TrustResultConfirm"; 
1018     case kSecTrustResultRecoverableTrustFailure
:    return "TrustResultRecoverableTrustFailure"; 
1019     case kSecTrustResultFatalTrustFailure
:          return "TrustResultUnspecified"; 
1020     case kSecTrustResultOtherError
:                 return "TrustResultOtherError"; 
1021     default:                                        return "TrustResultUnknown"; 
1027 static OSStatus 
verifySigners(SecCmsSignedDataRef signedData
, int numberOfSigners
, CFTypeRef timeStampPolicy
) 
1029     // See <rdar://problem/11077588> Bubble up SecTrustEvaluate of timestamp response to high level callers 
1030     // Also <rdar://problem/11077708> Properly handle revocation information of timestamping certificate 
1032     SecTrustRef trustRef 
= NULL
; 
1033     CFTypeRef policy 
= CFRetainSafe(timeStampPolicy
); 
1034     int result
=errSecInternalError
; 
1038         require(policy 
= SecPolicyCreateWithOID(kSecPolicyAppleTimeStamping
), xit
); 
1042     for (jx 
= 0; jx 
< numberOfSigners
; ++jx
) 
1044         SecTrustResultType trustResultType
; 
1045         CFDictionaryRef extendedResult 
= NULL
; 
1046         CFArrayRef certChain 
= NULL
; 
1047         uint16_t certCount 
= 0; 
1049         CSSM_TP_APPLE_EVIDENCE_INFO 
*statusChain 
= NULL
; 
1051         // SecCmsSignedDataVerifySignerInfo returns trustRef, which we can call SecTrustEvaluate on 
1052         // usually (always?) if result is noErr, the SecTrust*Result calls will return errSecTrustNotAvailable 
1053         result 
= SecCmsSignedDataVerifySignerInfo (signedData
, jx
, NULL
, policy
, &trustRef
); 
1054         dtprintf("[%s] SecCmsSignedDataVerifySignerInfo: result: %d, signer: %d\n", 
1055             __FUNCTION__
, result
, jx
); 
1056          require_noerr(result
, xit
); 
1058         result 
= SecTrustEvaluate (trustRef
, &trustResultType
); 
1059         dtprintf("[%s] SecTrustEvaluate: result: %d, trustResult: %s (%d)\n", 
1060             __FUNCTION__
, result
, trustResultTypeString(trustResultType
), trustResultType
); 
1063         switch (trustResultType
) 
1065                 case kSecTrustResultProceed
: 
1066                 case kSecTrustResultUnspecified
: 
1068                 case kSecTrustResultDeny
:                   // user reject 
1069                         result 
= errSecTimestampNotTrusted
;     // SecCmsVSTimestampNotTrusted ? 
1071                 case kSecTrustResultInvalid
: 
1072                         assert(false);                          // should never happen 
1073                         result 
= errSecTimestampNotTrusted
;     // SecCmsVSTimestampNotTrusted ? 
1075         case kSecTrustResultConfirm
: 
1076         case kSecTrustResultRecoverableTrustFailure
: 
1077         case kSecTrustResultFatalTrustFailure
: 
1078         case kSecTrustResultOtherError
: 
1082                     There are two "errors" that need to be resolved externally: 
1083                     CSSMERR_TP_CERT_EXPIRED can be OK if the timestamp was made 
1084                     before the TSA chain expired; CSSMERR_TP_CERT_NOT_VALID_YET 
1085                     can happen in the case where the user's clock was set to 0. 
1086                     We don't want to prevent them using apps automatically, so 
1087                     return noErr and let codesign or whover decide. 
1089                                 OSStatus resultCode
; 
1090                                 require_action(SecTrustGetCssmResultCode(trustRef
, &resultCode
)==noErr
, xit
, result 
= errSecTimestampNotTrusted
); 
1091                                 result 
= (resultCode 
== CSSMERR_TP_CERT_EXPIRED 
|| resultCode 
== CSSMERR_TP_CERT_NOT_VALID_YET
)?noErr
:errSecTimestampNotTrusted
; 
1096         rx 
= SecTrustGetResult(trustRef
, &trustResultType
, &certChain
, &statusChain
); 
1097         dtprintf("[%s] SecTrustGetResult: result: %d, type: %d\n", __FUNCTION__
,rx
, trustResultType
); 
1098         certCount 
= certChain
?CFArrayGetCount(certChain
):0; 
1099         debugShowCertEvidenceInfo(certCount
, statusChain
); 
1100         CFReleaseNull(certChain
); 
1102         rx 
= SecTrustCopyExtendedResult(trustRef
, &extendedResult
); 
1103         dtprintf("[%s] SecTrustCopyExtendedResult: result: %d\n", __FUNCTION__
, rx
); 
1106             debugShowExtendedTrustResult(jx
, extendedResult
); 
1107             CFRelease(extendedResult
); 
1111             CFReleaseNull(trustRef
); 
1116         CFReleaseNull(trustRef
); 
1122 static OSStatus 
impExpImportCertUnCommon( 
1123         const CSSM_DATA         
*cdata
, 
1124         SecKeychainRef          importKeychain
, // optional 
1125         CFMutableArrayRef       outArray
)               // optional, append here 
1127     // The only difference between this and impExpImportCertCommon is that we append to outArray 
1128     // before attempting to add to the keychain 
1129         OSStatus status 
= noErr
; 
1130         SecCertificateRef certRef 
= NULL
; 
1132     require_action(cdata
, xit
, status 
= errSecUnsupportedFormat
); 
1134         /* Pass kCFAllocatorNull as bytesDeallocator to assure the bytes aren't freed */ 
1135         CFDataRef data 
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, (const UInt8 
*)cdata
->Data
, (CFIndex
)cdata
->Length
, kCFAllocatorNull
); 
1136     require_action(data
, xit
, status 
= errSecUnsupportedFormat
); 
1138         certRef 
= SecCertificateCreateWithData(kCFAllocatorDefault
, data
); 
1139         CFRelease(data
); /* certRef has its own copy of the data now */ 
1141                 dtprintf("impExpHandleCert error\n"); 
1142                 return errSecUnsupportedFormat
; 
1146                 CFArrayAppendValue(outArray
, certRef
); 
1150                 status 
= SecCertificateAddToKeychain(certRef
, importKeychain
); 
1151                 if (status
!=noErr 
&& status
!=errSecDuplicateItem
) 
1152             { dtprintf("SecCertificateAddToKeychain error: %ld\n", (long)status
); } 
1161 static void saveTSACertificates(CSSM_DATA 
**signingCerts
, CFMutableArrayRef     outArray
) 
1163     SecKeychainRef defaultKeychain 
= NULL
; 
1164     // Don't save certificates in keychain to avoid securityd issues 
1165 //  if (SecKeychainCopyDefault(&defaultKeychain)) 
1166 //     defaultKeychain = NULL; 
1168     unsigned certCount 
= SecCmsArrayCount((void **)signingCerts
); 
1170     for (dex
=0; dex
<certCount
; dex
++) 
1172         OSStatus rx 
= impExpImportCertUnCommon(signingCerts
[dex
], defaultKeychain
, outArray
); 
1173         if (rx
!=noErr 
&& rx
!=errSecDuplicateItem
) 
1174             dtprintf("impExpImportCertCommon failed: %ld\n", (long)rx
); 
1176     if (defaultKeychain
) 
1177         CFRelease(defaultKeychain
); 
1180 static const char *cfabsoluteTimeToString(CFAbsoluteTime abstime
) 
1182     CFGregorianDate greg 
= CFAbsoluteTimeGetGregorianDate(abstime
, NULL
); 
1184     if (19 != snprintf(str
, 20, "%4.4d-%2.2d-%2.2d_%2.2d:%2.2d:%2.2d", 
1185         (int)greg
.year
, greg
.month
, greg
.day
, greg
.hour
, greg
.minute
, (int)greg
.second
)) 
1187     char *data 
= (char *)malloc(20); 
1188     strncpy(data
, str
, 20); 
1192 static OSStatus 
setTSALeafValidityDates(SecCmsSignerInfoRef signerinfo
) 
1194     OSStatus status 
= noErr
; 
1196     if (!signerinfo
->timestampCertList 
|| (CFArrayGetCount(signerinfo
->timestampCertList
) == 0)) 
1197         return SecCmsVSSigningCertNotFound
; 
1199     SecCertificateRef tsaLeaf 
= (SecCertificateRef
)CFArrayGetValueAtIndex(signerinfo
->timestampCertList
, 0); 
1200     require_action(tsaLeaf
, xit
, status 
= errSecCertificateCannotOperate
); 
1202     signerinfo
->tsaLeafNotBefore 
= SecCertificateNotValidBefore(tsaLeaf
); /* Start date for Timestamp Authority leaf */ 
1203     signerinfo
->tsaLeafNotAfter 
= SecCertificateNotValidAfter(tsaLeaf
);   /* Expiration date for Timestamp Authority leaf */ 
1205     const char *nbefore 
= cfabsoluteTimeToString(signerinfo
->tsaLeafNotBefore
); 
1206     const char *nafter 
= cfabsoluteTimeToString(signerinfo
->tsaLeafNotAfter
); 
1207     if (nbefore 
&& nafter
) 
1209         dtprintf("Timestamp Authority leaf valid from %s to %s\n", nbefore
, nafter
); 
1210         free((void *)nbefore
);free((void *)nafter
); 
1215                         status = errSecCertificateNotValidYet; 
1217                         status = errSecCertificateExpired; 
1225     From RFC 3161: Time-Stamp Protocol (TSP),August 2001, APPENDIX B: 
1227     B) The validity of the digital signature may then be verified in the 
1230         1)  The time-stamp token itself MUST be verified and it MUST be 
1231             verified that it applies to the signature of the signer. 
1233         2)  The date/time indicated by the TSA in the TimeStampToken 
1236         3)  The certificate used by the signer MUST be identified and 
1239         4)  The date/time indicated by the TSA MUST be within the 
1240             validity period of the signer's certificate. 
1242         5)  The revocation information about that certificate, at the 
1243             date/time of the Time-Stamping operation, MUST be retrieved. 
1245         6)  Should the certificate be revoked, then the date/time of 
1246             revocation shall be later than the date/time indicated by 
1249     If all these conditions are successful, then the digital signature 
1250     shall be declared as valid. 
1254 OSStatus 
decodeTimeStampToken(SecCmsSignerInfoRef signerinfo
, CSSM_DATA_PTR inData
, CSSM_DATA_PTR encDigest
, uint64_t expectedNonce
) 
1256     return decodeTimeStampTokenWithPolicy(signerinfo
, NULL
, inData
, encDigest
, expectedNonce
); 
1259 OSStatus 
decodeTimeStampTokenWithPolicy(SecCmsSignerInfoRef signerinfo
, CFTypeRef timeStampPolicy
, CSSM_DATA_PTR inData
, CSSM_DATA_PTR encDigest
, uint64_t expectedNonce
) 
1262         We update signerinfo with timestamp and tsa certificate chain. 
1263         encDigest is the original signed blob, which we must hash and compare. 
1264         inData comes from the unAuthAttr section of the CMS message 
1266         These are set in signerinfo as side effects: 
1271     SecCmsDecoderRef        decoderContext 
= NULL
; 
1272     SecCmsMessageRef        cmsMessage 
= NULL
; 
1273     SecCmsContentInfoRef    contentInfo
; 
1274     SecCmsSignedDataRef     signedData
; 
1275     SECOidTag               contentTypeTag
; 
1276     int                     contentLevelCount
; 
1278     OSStatus                result 
= errSecUnknownFormat
; 
1279     CSSM_DATA               
**signingCerts 
= NULL
; 
1281     dtprintf("decodeTimeStampToken top: PORT_GetError() %d -----\n", PORT_GetError()); 
1284     /* decode the message */ 
1285     require_noerr(result 
= SecCmsDecoderCreate (NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &decoderContext
), xit
); 
1286     result 
= SecCmsDecoderUpdate(decoderContext
, inData
->Data
, inData
->Length
); 
1289         result 
= errSecTimestampInvalid
; 
1290         SecCmsDecoderDestroy(decoderContext
); 
1294     require_noerr(result 
= SecCmsDecoderFinish(decoderContext
, &cmsMessage
), xit
); 
1296     // process the results 
1297     contentLevelCount 
= SecCmsMessageContentLevelCount(cmsMessage
); 
1300         printDataAsHex("encDigest",encDigest
, 0); 
1302     for (ix 
= 0; ix 
< contentLevelCount
; ++ix
) 
1304         dtprintf("\n----- Content Level %d -----\n", ix
); 
1305         // get content information 
1306         contentInfo 
= SecCmsMessageContentLevel (cmsMessage
, ix
); 
1307         contentTypeTag 
= SecCmsContentInfoGetContentTypeTag (contentInfo
); 
1309         // After 2nd round, contentInfo.content.data is the TSTInfo 
1311         debugShowContentTypeOID(contentInfo
); 
1313         switch (contentTypeTag
) 
1315         case SEC_OID_PKCS7_SIGNED_DATA
: 
1317             require((signedData 
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(contentInfo
)) != NULL
, xit
); 
1319             debugShowSignerInfo(signedData
); 
1321             SECAlgorithmID 
**digestAlgorithms 
= SecCmsSignedDataGetDigestAlgs(signedData
); 
1322             unsigned digestAlgCount 
= SecCmsArrayCount((void **)digestAlgorithms
); 
1323             dtprintf("digestAlgCount: %d\n", digestAlgCount
); 
1324             if (signedData
->digests
) 
1328                 for (jx
=0;jx 
< digestAlgCount
;jx
++) 
1330                     sprintf(buffer
, " digest[%u]", jx
); 
1331                     printDataAsHex(buffer
,signedData
->digests
[jx
], 0); 
1336                 dtprintf("No digests\n"); 
1337                 CSSM_DATA_PTR innerContent 
= SecCmsContentInfoGetInnerContent(contentInfo
); 
1340                     dtprintf("inner content length: %ld\n", innerContent
->Length
); 
1341                     SecAsn1TSAMessageImprint fakeMessageImprint 
= {{{0}},}; 
1342                     OSStatus status 
= createTSAMessageImprint(signedData
, innerContent
, &fakeMessageImprint
); 
1344                         {    dtprintf("createTSAMessageImprint status: %d\n", (int)status
); } 
1345                     printDataAsHex("inner content hash",&fakeMessageImprint
.hashedMessage
, 0); 
1346                     CSSM_DATA_PTR digestdata 
= &fakeMessageImprint
.hashedMessage
; 
1347                     CSSM_DATA_PTR digests
[2] = {digestdata
, NULL
}; 
1348                     SecCmsSignedDataSetDigests(signedData
, digestAlgorithms
, (CSSM_DATA_PTR 
*)&digests
); 
1351                     dtprintf("no inner content\n"); 
1355                 Import the certificates. We leave this as a warning, since 
1356                 there are configurations where the certificates are not returned. 
1358             signingCerts 
= SecCmsSignedDataGetCertificateList(signedData
); 
1359             if (signingCerts 
== NULL
) 
1360             {    dtprintf("SecCmsSignedDataGetCertificateList returned NULL\n"); } 
1363                 if (!signerinfo
->timestampCertList
) 
1364                     signerinfo
->timestampCertList 
= CFArrayCreateMutable(kCFAllocatorDefault
, 10, &kCFTypeArrayCallBacks
); 
1365                 saveTSACertificates(signingCerts
, signerinfo
->timestampCertList
); 
1366                 require_noerr(result 
= setTSALeafValidityDates(signerinfo
), xit
); 
1367                 debugSaveCertificates(signingCerts
); 
1370             int numberOfSigners 
= SecCmsSignedDataSignerInfoCount (signedData
); 
1372             result 
= verifySigners(signedData
, numberOfSigners
, timeStampPolicy
); 
1374                 dtprintf("verifySigners failed: %ld\n", (long)result
);   // warning 
1377             if (result
)     // remap to SecCmsVSTimestampNotTrusted ? 
1382         case SEC_OID_PKCS9_SIGNING_CERTIFICATE
: 
1384             dtprintf("SEC_OID_PKCS9_SIGNING_CERTIFICATE seen\n"); 
1388         case SEC_OID_PKCS9_ID_CT_TSTInfo
: 
1390             SecAsn1TSATSTInfo tstInfo 
= {{0},}; 
1391             result 
= verifyTSTInfo(contentInfo
->rawContent
, signingCerts
, &tstInfo
, &signerinfo
->timestampTime
, expectedNonce
); 
1392             if (signerinfo
->timestampTime
) 
1394                 const char *tstamp 
= cfabsoluteTimeToString(signerinfo
->timestampTime
); 
1397                     dtprintf("Timestamp Authority timestamp: %s\n", tstamp
); 
1398                     free((void *)tstamp
); 
1405             dtprintf("otherContent : %p\n", (char *)SecCmsContentInfoGetContent (contentInfo
)); 
1409             dtprintf("ContentTypeTag : %x\n", contentTypeTag
); 
1415                 SecCmsMessageDestroy(cmsMessage
);