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
); 
 202 int tsaWriteFileX(const char *fileName
, const unsigned char *bytes
, size_t numBytes
) 
 207     fd 
= open(fileName
, O_RDWR 
| O_CREAT 
| O_TRUNC
, 0600); 
 211     rtn 
= (int)write(fd
, bytes
, numBytes
); 
 212     if(rtn 
!= (int)numBytes
) 
 215             fprintf(stderr
, "writeFile: short write\n"); 
 226 char *cfStringToChar(CFStringRef inStr
) 
 230     const char *str 
= NULL
; 
 233         return strdup("");     // return a null string 
 236         if ((str 
= CFStringGetCStringPtr(inStr
, kCFStringEncodingUTF8
))) { 
 237         result 
= strdup(str
); 
 239         // need to extract into buffer 
 240         CFIndex length 
= CFStringGetLength(inStr
);  // in 16-bit character units 
 241         CFIndex bytesToAllocate 
= CFStringGetMaximumSizeForEncoding(length
, kCFStringEncodingUTF8
) + 1; 
 242         result 
= malloc(bytesToAllocate
); 
 243         if (!CFStringGetCString(inStr
, result
, bytesToAllocate
, kCFStringEncodingUTF8
)) 
 250 /* Oids longer than this are considered invalid. */ 
 251 #define MAX_OID_SIZE                            32 
 254 /* FIXME: There are other versions of this in SecCertifcate.c and SecCertificateP.c */ 
 255 static CFStringRef 
SecDERItemCopyOIDDecimalRepresentation(CFAllocatorRef allocator
, const CSSM_OID 
*oid
) 
 257         if (oid
->Length 
== 0) 
 258         return CFSTR("<NULL>"); 
 260         if (oid
->Length 
> MAX_OID_SIZE
) 
 261         return CFSTR("Oid too long"); 
 263     CFMutableStringRef result 
= CFStringCreateMutable(allocator
, 0); 
 265         // The first two levels are encoded into one byte, since the root levelq 
 266         // has only 3 nodes (40*x + y).  However if x = joint-iso-itu-t(2) then 
 267         // y may be > 39, so we have to add special-case handling for this. 
 268         uint32_t x 
= oid
->Data
[0] / 40; 
 269         uint32_t y 
= oid
->Data
[0] % 40; 
 272                 // Handle special case for large y if x = 2 
 276     CFStringAppendFormat(result
, NULL
, CFSTR("%u.%u"), x
, y
); 
 279         for (x 
= 1; x 
< oid
->Length
; ++x
) 
 281                 value 
= (value 
<< 7) | (oid
->Data
[x
] & 0x7F); 
 282         /* @@@ value may not span more than 4 bytes. */ 
 283         /* A max number of 20 values is allowed. */ 
 284                 if (!(oid
->Data
[x
] & 0x80)) 
 286             CFStringAppendFormat(result
, NULL
, CFSTR(".%lu"), (unsigned long)value
); 
 294 static void debugSaveCertificates(CSSM_DATA 
**outCerts
) 
 299         CSSM_DATA_PTR 
*certp
; 
 301         const char *certNameBase 
= "/tmp/tsa-resp-cert-"; 
 302         char fname
[PATH_MAX
]; 
 303         unsigned certCount 
= SecCmsArrayCount((void **)outCerts
); 
 304         dtprintf("Found %d certs\n",certCount
); 
 306         for (certp
=outCerts
;*certp
;certp
++, ++jx
) 
 309             strncpy(fname
, certNameBase
, strlen(certNameBase
)+1); 
 310             sprintf(numstr
,"%u", jx
); 
 311             strcat(fname
,numstr
); 
 312             tsaWriteFileX(fname
, (*certp
)->Data
, (*certp
)->Length
); 
 314                 break;  //something wrong 
 320 static void debugShowSignerInfo(SecCmsSignedDataRef signedData
) 
 323     int numberOfSigners 
= SecCmsSignedDataSignerInfoCount (signedData
); 
 324     dtprintf("numberOfSigners : %d\n", numberOfSigners
); 
 326     for (ix
=0;ix 
< numberOfSigners
;ix
++) 
 328         SecCmsSignerInfoRef sigi 
= SecCmsSignedDataGetSignerInfo(signedData
,ix
); 
 331             CFStringRef commonName 
= SecCmsSignerInfoGetSignerCommonName(sigi
); 
 332             const char *signerhdr 
= "      signer    : "; 
 335                 char *cn 
= cfStringToChar(commonName
); 
 336                 dtprintf("%s%s\n", signerhdr
, cn
); 
 341                 dtprintf("%s<NULL>\n", signerhdr
); 
 347 static void debugShowContentTypeOID(SecCmsContentInfoRef contentInfo
) 
 351     CSSM_OID 
*typeOID 
= SecCmsContentInfoGetContentTypeOID(contentInfo
); 
 354         CFStringRef oidCFStr 
= SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault
, typeOID
); 
 355         char *oidstr 
= cfStringToChar(oidCFStr
); 
 356         printDataAsHex("oid:", typeOID
, (unsigned int)typeOID
->Length
); 
 357         dtprintf("\toid: %s\n", oidstr
); 
 366 uint64_t tsaDER_ToInt(const CSSM_DATA 
*DER_Data
) 
 371         while(i 
< DER_Data
->Length
) { 
 372                 rtn 
|= DER_Data
->Data
[i
]; 
 373                 if(++i 
== DER_Data
->Length
) { 
 381 void displayTSTInfo(SecAsn1TSATSTInfo 
*tstInfo
) 
 384     dtprintf("--- TSTInfo ---\n"); 
 388     if (tstInfo
->version
.Data
) 
 390         uint64_t vers 
= tsaDER_ToInt(&tstInfo
->version
); 
 391         dtprintf("Version:\t\t%u\n", (int)vers
); 
 394     if (tstInfo
->serialNumber
.Data
) 
 396         uint64_t sn 
= tsaDER_ToInt(&tstInfo
->serialNumber
); 
 397         dtprintf("SerialNumber:\t%llu\n", sn
); 
 400     if (tstInfo
->ordering
.Data
) 
 402         uint64_t ord 
= tsaDER_ToInt(&tstInfo
->ordering
); 
 403         dtprintf("Ordering:\t\t%s\n", ord
?"yes":"no"); 
 406     if (tstInfo
->nonce
.Data
) 
 408         uint64_t nonce 
= tsaDER_ToInt(&tstInfo
->nonce
); 
 409         dtprintf("Nonce:\t\t%llu\n", nonce
); 
 412         dtprintf("Nonce:\t\tnot specified\n"); 
 414     if (tstInfo
->genTime
.Data
) 
 416         char buf
[tstInfo
->genTime
.Length
+1]; 
 417         memcpy(buf
, (const char *)tstInfo
->genTime
.Data
, tstInfo
->genTime
.Length
); 
 418         buf
[tstInfo
->genTime
.Length
]=0; 
 419         dtprintf("GenTime:\t\t%s\n", buf
); 
 422     dtprintf("-- MessageImprint --\n"); 
 423     if (true)   // SecAsn1TSAMessageImprint 
 425         printDataAsHex(" Algorithm:",&tstInfo
->messageImprint
.hashAlgorithm
.algorithm
, 0); 
 426         printDataAsHex(" Message  :", &tstInfo
->messageImprint
.hashedMessage
, 0);//tstInfo->messageImprint.hashedMessage.Length); 
 431 #pragma mark ----- TimeStamp Response using XPC ----- 
 433 #include <xpc/private.h> 
 435 static OSStatus 
checkForNonDERResponse(const unsigned char *resp
, size_t respLen
) 
 438         Good start is something like 30 82 0c 03 30 15 02 01  00 30 10 0c 0e 4f 70 65 
 440         URL:    http://timestamp-int.corp.apple.com/signserver/process?TimeStampSigner 
 441         Resp:   Http/1.1 Service Unavailable 
 443         URL:    http://timestamp-int.corp.apple.com/ts01 
 446         URL:    http://cutandtaste.com/404 (or other forced 404 site) 
 450     OSStatus status 
= noErr
; 
 451     const char ader
[2] = { 0x30, 0x82 }; 
 452     char *respStr 
= NULL
; 
 454     size_t badResponseCount
; 
 456     const char *badResponses
[] = 
 459         "Http/1.1 Service Unavailable", 
 463     require_action(resp 
&& respLen
, xit
, status 
= errSecTimestampServiceNotAvailable
); 
 465     // This is usual case 
 466     if ((respLen 
> 1) && (memcmp(resp
, ader
, 2)==0))    // might be good; pass on to DER decoder 
 469     badResponseCount 
= sizeof(badResponses
)/sizeof(char *); 
 471     for (ix 
= 0; ix 
< badResponseCount
; ++ix
) 
 472         if (strlen(badResponses
[ix
]) > maxlen
) 
 473             maxlen 
= strlen(badResponses
[ix
]); 
 475     // Prevent a large response from allocating a ton of memory 
 476     if (respLen 
> maxlen
) 
 479     respStr 
= (char *)malloc(respLen
+1); 
 480     strlcpy(respStr
, (const char *)resp
, respLen
); 
 482     for (ix 
= 0; ix 
< badResponseCount
; ++ix
) 
 483         if (strcmp(respStr
, badResponses
[ix
])==0) 
 484             return errSecTimestampServiceNotAvailable
; 
 488         free((void *)respStr
); 
 493 static OSStatus 
sendTSARequestWithXPC(const unsigned char *tsaReq
, size_t tsaReqLength
, const unsigned char *tsaURL
, unsigned char **tsaResp
, size_t *tsaRespLength
) 
 495     __block OSStatus result 
= noErr
; 
 496     int timeoutInSeconds 
= 15; 
 497     extern xpc_object_t 
xpc_create_with_format(const char * format
, ...); 
 499         dispatch_queue_t xpc_queue 
= dispatch_queue_create("com.apple.security.XPCTimeStampingService", DISPATCH_QUEUE_SERIAL
); 
 500     __block dispatch_semaphore_t waitSemaphore 
= dispatch_semaphore_create(0); 
 501     dispatch_time_t finishTime 
= dispatch_time(DISPATCH_TIME_NOW
, timeoutInSeconds 
* NSEC_PER_SEC
); 
 503     xpc_connection_t con 
= xpc_connection_create("com.apple.security.XPCTimeStampingService", xpc_queue
); 
 505     xpc_connection_set_event_handler(con
, ^(xpc_object_t event
) { 
 506         xpc_type_t xtype 
= xpc_get_type(event
); 
 507         if (XPC_TYPE_ERROR 
== xtype
) 
 508         {    tsaDebug("default: connection error: %s\n", xpc_dictionary_get_string(event
, XPC_ERROR_KEY_DESCRIPTION
)); } 
 510          {   tsaDebug("default: unexpected connection event %p\n", event
); } 
 513     xpc_connection_resume(con
); 
 515     xpc_object_t tsaReqData 
= xpc_data_create(tsaReq
, tsaReqLength
); 
 516     const char *urlstr 
= (tsaURL
?(const char *)tsaURL
:""); 
 517     xpc_object_t url_as_xpc_string 
= xpc_string_create(urlstr
); 
 519     xpc_object_t message 
= xpc_create_with_format("{operation: TimeStampRequest, ServerURL: %value, TimeStampRequest: %value}", url_as_xpc_string
, tsaReqData
); 
 521     xpc_connection_send_message_with_reply(con
, message
, xpc_queue
, ^(xpc_object_t reply
) 
 523         tsaDebug("xpc_connection_send_message_with_reply handler called back\n"); 
 524         dispatch_retain(waitSemaphore
); 
 526     xpc_type_t xtype 
= xpc_get_type(reply
); 
 527         if (XPC_TYPE_ERROR 
== xtype
) 
 528             {   tsaDebug("message error: %s\n", xpc_dictionary_get_string(reply
, XPC_ERROR_KEY_DESCRIPTION
)); } 
 529         else if (XPC_TYPE_CONNECTION 
== xtype
) 
 530             { tsaDebug("received connection\n"); } 
 531         else if (XPC_TYPE_DICTIONARY 
== xtype
) 
 535          // This is useful for debugging. 
 536         char *debug = xpc_copy_description(reply); 
 537         tsaDebug("DEBUG %s\n", debug); 
 542         xpc_object_t xpcTimeStampReply 
= xpc_dictionary_get_value(reply
, "TimeStampReply"); 
 543         size_t xpcTSRLength 
= xpc_data_get_length(xpcTimeStampReply
); 
 544         tsaDebug("xpcTSRLength: %ld bytes of response\n", xpcTSRLength
); 
 546         xpc_object_t xpcTimeStampError 
= xpc_dictionary_get_value(reply
, "TimeStampError"); 
 547         xpc_object_t xpcTimeStampStatus 
= xpc_dictionary_get_value(reply
, "TimeStampStatus"); 
 549         if (xpcTimeStampError 
|| xpcTimeStampStatus
) 
 552             if (xpcTimeStampError
) 
 554                 size_t len 
= xpc_string_get_length(xpcTimeStampError
); 
 555                 char *buf 
= (char *)malloc(len
); 
 556                 strlcpy(buf
, xpc_string_get_string_ptr(xpcTimeStampError
), len
+1); 
 557                 tsaDebug("xpcTimeStampError: %s\n", buf
); 
 562             if (xpcTimeStampStatus
) 
 564                 result 
= (OSStatus
)xpc_int64_get_value(xpcTimeStampStatus
); 
 565                 tsaDebug("xpcTimeStampStatus: %d\n", (int)result
); 
 569         result 
= remapHTTPErrorCodes(result
); 
 571         if ((result 
== noErr
) && tsaResp 
&& tsaRespLength
) 
 573             *tsaRespLength 
= xpcTSRLength
; 
 574             *tsaResp 
= (unsigned char *)malloc(xpcTSRLength
); 
 576             size_t bytesCopied 
= xpc_data_get_bytes(xpcTimeStampReply
, *tsaResp
, 0, xpcTSRLength
); 
 577             if (bytesCopied 
!= xpcTSRLength
) 
 578             {    tsaDebug("length mismatch: copied: %ld, xpc: %ld\n", bytesCopied
, xpcTSRLength
); } 
 580             if ((result 
= checkForNonDERResponse(*tsaResp
,bytesCopied
))) 
 582                 tsaDebug("received non-DER response from timestamp server\n"); 
 587                 tsaDebug("copied: %ld bytes of response\n", bytesCopied
); 
 590         tsaDebug("releasing connection\n"); 
 594         { tsaDebug("unexpected message reply type %p\n", xtype
); } 
 596         dispatch_semaphore_signal(waitSemaphore
); 
 597         dispatch_release(waitSemaphore
); 
 600     { tsaDebug("waiting up to %d seconds for response from XPC\n", timeoutInSeconds
); } 
 601         dispatch_semaphore_wait(waitSemaphore
, finishTime
); 
 603         dispatch_release(waitSemaphore
); 
 604     xpc_release(tsaReqData
); 
 605     xpc_release(message
); 
 607     { tsaDebug("sendTSARequestWithXPC exit\n"); } 
 612 #pragma mark ----- TimeStamp request ----- 
 614 #include "tsaTemplates.h" 
 615 #include <security_asn1/SecAsn1Coder.h> 
 616 #include <Security/oidsalg.h> 
 617 #include <AssertMacros.h> 
 618 #include <libkern/OSByteOrder.h> 
 620 extern const SecAsn1Template kSecAsn1TSATimeStampReqTemplate
; 
 621 extern const SecAsn1Template kSecAsn1TSATimeStampRespTemplateDER
; 
 623 CFMutableDictionaryRef 
SecCmsTSAGetDefaultContext(CFErrorRef 
*error
) 
 625     // Caller responsible for retain/release 
 626     // <rdar://problem/11077440> Update SecCmsTSAGetDefaultContext with actual URL for Apple Timestamp server 
 627     //      URL will be in TimeStampingPrefs.plist 
 629     CFBundleRef secFWbundle 
= NULL
; 
 630     CFURLRef resourceURL 
= NULL
; 
 631     CFDataRef resourceData 
= NULL
; 
 632     CFPropertyListRef prefs 
= NULL
; 
 633     CFMutableDictionaryRef contextDict 
= NULL
; 
 634     SInt32 errorCode 
= 0; 
 635     CFOptionFlags options 
= 0; 
 636     CFPropertyListFormat format 
= 0; 
 637     OSStatus status 
= noErr
; 
 639     require_action(secFWbundle 
= CFBundleGetBundleWithIdentifier(CFSTR("com.apple.security")), xit
, status 
= errSecInternalError
); 
 640     require_action(resourceURL 
= CFBundleCopyResourceURL(secFWbundle
, CFSTR("TimeStampingPrefs"), CFSTR("plist"), NULL
), 
 641         xit
, status 
= errSecInvalidPrefsDomain
); 
 643     require(CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault
, resourceURL
, &resourceData
, 
 644         NULL
, NULL
, &errorCode
), xit
); 
 645     require_action(resourceData
, xit
, status 
= errSecDataNotAvailable
); 
 647     prefs 
= CFPropertyListCreateWithData(kCFAllocatorDefault
, resourceData
, options
, &format
, error
); 
 648     require_action(prefs 
&& (CFGetTypeID(prefs
)==CFDictionaryGetTypeID()), xit
, status 
= errSecInvalidPrefsDomain
); 
 650     contextDict 
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, prefs
); 
 658         *error 
= CFErrorCreate(kCFAllocatorDefault
, kCFErrorDomainOSStatus
, status
, NULL
); 
 660         CFRelease(secFWbundle
); 
 662         CFRelease(resourceURL
); 
 664         CFRelease(resourceData
); 
 671 static CFDataRef 
_SecTSARequestCopyDEREncoding(SecAsn1TSAMessageImprint 
*messageImprint
, bool noCerts
, uint64_t nonce
) 
 673     // Returns DER encoded TimeStampReq 
 674     // Modeled on _SecOCSPRequestCopyDEREncoding 
 675     // The Timestamp Authority supports 64 bit nonces (or more possibly) 
 677     SecAsn1CoderRef             coder 
= NULL
; 
 679     SecAsn1Item                 vers 
= {1, &version
}; 
 680     uint8_t                     creq 
= noCerts
?0:1; 
 681     SecAsn1Item                 certReq 
= {1, &creq
};   //jch - to request or not? 
 682     SecAsn1TSATimeStampReq      tsreq 
= {}; 
 683     CFDataRef                   der 
= NULL
; 
 684     uint64_t                    nonceVal 
= OSSwapHostToBigConstInt64(nonce
); 
 685     SecAsn1Item                 nonceItem 
= {sizeof(uint64_t), (unsigned char *)&nonceVal
}; 
 687     uint8_t OID_FakePolicy_Data
[] = { 0x2A, 0x03, 0x04, 0x05, 0x06}; 
 688     const CSSM_OID fakePolicyOID 
= {sizeof(OID_FakePolicy_Data
),OID_FakePolicy_Data
}; 
 690     tsreq
.version 
= vers
; 
 692     tsreq
.messageImprint 
= *messageImprint
; 
 693     tsreq
.certReq 
= certReq
; 
 695     // skip reqPolicy, extensions for now - FAKES - jch 
 696     tsreq
.reqPolicy 
= fakePolicyOID
;    //policyID; 
 698     tsreq
.nonce 
= nonceItem
; 
 700     // Encode the request 
 701     require_noerr(SecAsn1CoderCreate(&coder
), errOut
); 
 704     require_noerr(SecAsn1EncodeItem(coder
, &tsreq
, 
 705         &kSecAsn1TSATimeStampReqTemplate
, &encoded
), errOut
); 
 706     der 
= CFDataCreate(kCFAllocatorDefault
, encoded
.Data
, 
 711         SecAsn1CoderRelease(coder
); 
 716 OSStatus 
SecTSAResponseCopyDEREncoding(SecAsn1CoderRef coder
, const CSSM_DATA 
*tsaResponse
, SecAsn1TimeStampRespDER 
*respDER
) 
 718     // Partially decode the response 
 719     OSStatus status 
= paramErr
; 
 721     require(tsaResponse 
&& respDER
, errOut
); 
 722     require_noerr(SecAsn1DecodeData(coder
, tsaResponse
, 
 723         &kSecAsn1TSATimeStampRespTemplateDER
, respDER
), errOut
); 
 731 #pragma mark ----- TS Callback ----- 
 733 OSStatus 
SecCmsTSADefaultCallback(CFTypeRef context
, void *messageImprintV
, uint64_t nonce
, CSSM_DATA 
*signedDERBlob
) 
 735     OSStatus result 
= paramErr
; 
 736     const unsigned char *tsaReq 
= NULL
; 
 737     size_t tsaReqLength 
= 0; 
 738     CFDataRef cfreq 
= NULL
; 
 739     unsigned char *tsaURL 
= NULL
; 
 740     bool noCerts 
= false; 
 742     if (!context 
|| CFGetTypeID(context
)!=CFDictionaryGetTypeID()) 
 745     SecAsn1TSAMessageImprint 
*messageImprint 
= (SecAsn1TSAMessageImprint 
*)messageImprintV
; 
 746     if (!messageImprint 
|| !signedDERBlob
) 
 749     CFBooleanRef cfnocerts 
= (CFBooleanRef
)CFDictionaryGetValue((CFDictionaryRef
)context
, kTSAContextKeyNoCerts
); 
 752         tsaDebug("[TSA] Request noCerts\n"); 
 753         noCerts 
= CFBooleanGetValue(cfnocerts
); 
 756     // We must spoof the nonce here, before sending the request. 
 757     // If we tried to alter the reply, then the signature would break instead. 
 758     CFBooleanRef cfBadNonce 
= (CFBooleanRef
)CFDictionaryGetValue((CFDictionaryRef
)context
, kTSADebugContextKeyBadNonce
); 
 759     if (cfBadNonce 
&& CFBooleanGetValue(cfBadNonce
)) 
 761         tsaDebug("[TSA] Forcing bad TS Request by changing nonce\n"); 
 765     printDataAsHex("[TSA] hashToTimeStamp:", &messageImprint
->hashedMessage
,128); 
 766     cfreq 
= _SecTSARequestCopyDEREncoding(messageImprint
, noCerts
, nonce
); 
 769         tsaReq 
= CFDataGetBytePtr(cfreq
); 
 770         tsaReqLength 
= CFDataGetLength(cfreq
); 
 774         tsaWriteFileX("/tmp/tsareq.req", tsaReq
, tsaReqLength
); 
 778     CFStringRef url 
= (CFStringRef
)CFDictionaryGetValue((CFDictionaryRef
)context
, kTSAContextKeyURL
); 
 781         tsaDebug("[TSA] missing URL for TSA (key: %s)\n", "kTSAContextKeyURL"); 
 786         If debugging, look at special values in the context to mess things up 
 789     CFBooleanRef cfBadReq 
= (CFBooleanRef
)CFDictionaryGetValue((CFDictionaryRef
)context
, kTSADebugContextKeyBadReq
); 
 790     if (cfBadReq 
&& CFBooleanGetValue(cfBadReq
)) 
 792         tsaDebug("[TSA] Forcing bad TS Request by truncating length from %ld to %ld\n", tsaReqLength
, (tsaReqLength
-4)); 
 796     // need to extract into buffer 
 797     CFIndex length 
= CFStringGetLength(url
);        // in 16-bit character units 
 798     tsaURL 
= malloc(6 * length 
+ 1);                // pessimistic 
 799     if (!CFStringGetCString(url
, (char *)tsaURL
, 6 * length 
+ 1, kCFStringEncodingUTF8
)) 
 802     tsaDebug("[TSA] URL for timestamp server: %s\n", tsaURL
); 
 804     unsigned char *tsaResp 
= NULL
; 
 805     size_t tsaRespLength 
= 0; 
 806     tsaDebug("calling sendTSARequestWithXPC with %ld bytes of request\n", tsaReqLength
); 
 808     require_noerr(result 
= sendTSARequestWithXPC(tsaReq
, tsaReqLength
, tsaURL
, &tsaResp
, &tsaRespLength
), xit
); 
 810     tsaDebug("sendTSARequestWithXPC copied: %ld bytes of response\n", tsaRespLength
); 
 812     signedDERBlob
->Data 
= tsaResp
; 
 813     signedDERBlob
->Length 
= tsaRespLength
; 
 819         free((void *)tsaURL
); 
 826 #pragma mark ----- TimeStamp Verification ----- 
 828 static OSStatus 
convertGeneralizedTimeToCFAbsoluteTime(const char *timeStr
, CFAbsoluteTime 
*ptime
) 
 831         See http://userguide.icu-project.org/formatparse/datetime for date/time format. 
 832         The "Z" signal a GMT time, but CFDateFormatterGetAbsoluteTimeFromString returns 
 833         values based on local time. 
 836     OSStatus result 
= noErr
; 
 837     CFDateFormatterRef formatter 
= NULL
; 
 838     CFStringRef time_string 
= NULL
; 
 839     CFTimeZoneRef gmt 
= NULL
; 
 840     CFLocaleRef locale 
= NULL
; 
 841     CFRange 
*rangep 
= NULL
; 
 843     require(timeStr 
&& timeStr
[0] && ptime
, xit
); 
 844     require(formatter 
= CFDateFormatterCreate(kCFAllocatorDefault
, locale
, kCFDateFormatterNoStyle
, kCFDateFormatterNoStyle
), xit
); 
 845 //    CFRetain(formatter); 
 846     CFDateFormatterSetFormat(formatter
, CFSTR("yyyyMMddHHmmss'Z'"));    // GeneralizedTime 
 847     gmt 
= CFTimeZoneCreateWithTimeIntervalFromGMT(NULL
, 0); 
 848         CFDateFormatterSetProperty(formatter
, kCFDateFormatterTimeZone
, gmt
); 
 850     time_string 
= CFStringCreateWithCString(kCFAllocatorDefault
, timeStr
, kCFStringEncodingUTF8
); 
 851     if (!time_string 
|| !CFDateFormatterGetAbsoluteTimeFromString(formatter
, time_string
, rangep
, ptime
)) 
 853         dtprintf("%s is not a valid date\n", timeStr
); 
 859         CFRelease(formatter
); 
 861         CFRelease(time_string
); 
 868 static OSStatus 
SecTSAValidateTimestamp(const SecAsn1TSATSTInfo 
*tstInfo
, CSSM_DATA 
**signingCerts
, CFAbsoluteTime 
*timestampTime
) 
 870     // See <rdar://problem/11077708> Properly handle revocation information of timestamping certificate 
 871     OSStatus result 
= paramErr
; 
 872     CFAbsoluteTime genTime 
= 0; 
 873     char timeStr
[32] = {0,}; 
 874     SecCertificateRef signingCertificate 
= NULL
; 
 876     require(tstInfo 
&& signingCerts 
&& (tstInfo
->genTime
.Length 
< 16), xit
); 
 878     // Find the leaf signingCert 
 879     require_noerr(result 
= SecCertificateCreateFromData(*signingCerts
, 
 880         CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_DER
, &signingCertificate
), xit
); 
 882     memcpy(timeStr
, tstInfo
->genTime
.Data
, tstInfo
->genTime
.Length
); 
 883     timeStr
[tstInfo
->genTime
.Length
] = 0; 
 884     require_noerr(convertGeneralizedTimeToCFAbsoluteTime(timeStr
, &genTime
), xit
); 
 885     if (SecCertificateIsValidX(signingCertificate
, genTime
)) // iOS? 
 888         result 
= errSecTimestampInvalid
; 
 890         *timestampTime 
= genTime
; 
 895 static OSStatus 
verifyTSTInfo(const CSSM_DATA_PTR content
, CSSM_DATA 
**signingCerts
, SecAsn1TSATSTInfo 
*tstInfo
, CFAbsoluteTime 
*timestampTime
, uint64_t expectedNonce
) 
 897     OSStatus status 
= paramErr
; 
 898     SecAsn1CoderRef coder 
= NULL
; 
 903     require_noerr(SecAsn1CoderCreate(&coder
), xit
); 
 904     require_noerr(SecAsn1Decode(coder
, content
->Data
, content
->Length
, 
 905                 kSecAsn1TSATSTInfoTemplate
, tstInfo
), xit
); 
 906     displayTSTInfo(tstInfo
); 
 909     if (tstInfo
->nonce
.Data 
&& expectedNonce
!=0) 
 911         uint64_t nonce 
= tsaDER_ToInt(&tstInfo
->nonce
); 
 912      //   if (expectedNonce!=nonce) 
 913             dtprintf("verifyTSTInfo nonce: actual: %lld, expected: %lld\n", nonce
, expectedNonce
); 
 914         require_action(expectedNonce
==nonce
, xit
, status 
= errSecTimestampRejection
); 
 917     status 
= SecTSAValidateTimestamp(tstInfo
, signingCerts
, timestampTime
); 
 918     dtprintf("SecTSAValidateTimestamp result: %ld\n", (long)status
); 
 922         SecAsn1CoderRelease(coder
); 
 926 static void debugShowExtendedTrustResult(int index
, CFDictionaryRef extendedResult
) 
 931         CFStringRef xresStr 
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, 
 932         CFSTR("Extended trust result for signer #%d : %@"), index
, extendedResult
); 
 943 extern const char *cssmErrorString(CSSM_RETURN error
); 
 945 static void statusBitTest(CSSM_TP_APPLE_CERT_STATUS certStatus
, uint32 bit
, const char *str
) 
 947         if (certStatus 
& bit
) 
 948                 dtprintf("%s  ", str
); 
 952 static void debugShowCertEvidenceInfo(uint16_t certCount
, const CSSM_TP_APPLE_EVIDENCE_INFO 
*info
) 
 955         CSSM_TP_APPLE_CERT_STATUS cs
; 
 956 //      const CSSM_TP_APPLE_EVIDENCE_INFO *pinfo = info; 
 958         for (ix
=0; info 
&& (ix
<certCount
); ix
++, ++info
) 
 960                 cs 
= info
->StatusBits
; 
 961                 dtprintf("   cert %u:\n", ix
); 
 962                 dtprintf("      StatusBits     : 0x%x", (unsigned)cs
); 
 966                         statusBitTest(cs
, CSSM_CERT_STATUS_EXPIRED
, "EXPIRED"); 
 967                         statusBitTest(cs
, CSSM_CERT_STATUS_NOT_VALID_YET
, 
 969                         statusBitTest(cs
, CSSM_CERT_STATUS_IS_IN_INPUT_CERTS
, 
 970                                 "IS_IN_INPUT_CERTS"); 
 971                         statusBitTest(cs
, CSSM_CERT_STATUS_IS_IN_ANCHORS
, 
 973                         statusBitTest(cs
, CSSM_CERT_STATUS_IS_ROOT
, "IS_ROOT"); 
 974                         statusBitTest(cs
, CSSM_CERT_STATUS_IS_FROM_NET
, "IS_FROM_NET"); 
 980                 dtprintf("      NumStatusCodes : %u ", info
->NumStatusCodes
); 
 981         CSSM_RETURN 
*pstatuscode 
= info
->StatusCodes
; 
 983         for (jx
=0; pstatuscode 
&& (jx
<info
->NumStatusCodes
); jx
++, ++pstatuscode
) 
 984             dtprintf("%s  ", cssmErrorString(*pstatuscode
)); 
 987                 dtprintf("      Index: %u\n", info
->Index
); 
 994 static const char *trustResultTypeString(SecTrustResultType trustResultType
) 
 996     switch (trustResultType
) 
 998     case kSecTrustResultProceed
:                    return "TrustResultProceed"; 
 999     case kSecTrustResultUnspecified
:                return "TrustResultUnspecified"; 
1000     case kSecTrustResultDeny
:                       return "TrustResultDeny";   // user reject 
1001     case kSecTrustResultInvalid
:                    return "TrustResultInvalid"; 
1002     case kSecTrustResultConfirm
:                    return "TrustResultConfirm"; 
1003     case kSecTrustResultRecoverableTrustFailure
:    return "TrustResultRecoverableTrustFailure"; 
1004     case kSecTrustResultFatalTrustFailure
:          return "TrustResultUnspecified"; 
1005     case kSecTrustResultOtherError
:                 return "TrustResultOtherError"; 
1006     default:                                        return "TrustResultUnknown"; 
1012 static OSStatus 
verifySigners(SecCmsSignedDataRef signedData
, int numberOfSigners
, CFTypeRef timeStampPolicy
) 
1014     // See <rdar://problem/11077588> Bubble up SecTrustEvaluate of timestamp response to high level callers 
1015     // Also <rdar://problem/11077708> Properly handle revocation information of timestamping certificate 
1017     CFTypeRef policy 
= CFRetainSafe(timeStampPolicy
); 
1018     int result
=errSecInternalError
; 
1022         require(policy 
= SecPolicyCreateWithOID(kSecPolicyAppleTimeStamping
), xit
); 
1026     for (jx 
= 0; jx 
< numberOfSigners
; ++jx
) 
1028         SecTrustResultType trustResultType
; 
1029         SecTrustRef trustRef 
= NULL
; 
1030         CFDictionaryRef extendedResult 
= NULL
; 
1031         CFArrayRef certChain 
= NULL
; 
1032         uint16_t certCount 
= 0; 
1034         CSSM_TP_APPLE_EVIDENCE_INFO 
*statusChain 
= NULL
; 
1036         // SecCmsSignedDataVerifySignerInfo returns trustRef, which we can call SecTrustEvaluate on 
1037         // usually (always?) if result is noErr, the SecTrust*Result calls will return errSecTrustNotAvailable 
1038         result 
= SecCmsSignedDataVerifySignerInfo (signedData
, jx
, NULL
, policy
, &trustRef
); 
1039         dtprintf("[%s] SecCmsSignedDataVerifySignerInfo: result: %d, signer: %d\n", 
1040             __FUNCTION__
, result
, jx
); 
1041          require_noerr(result
, xit
); 
1043         result 
= SecTrustEvaluate (trustRef
, &trustResultType
); 
1044         dtprintf("[%s] SecTrustEvaluate: result: %d, trustResult: %s (%d)\n", 
1045             __FUNCTION__
, result
, trustResultTypeString(trustResultType
), trustResultType
); 
1048         switch (trustResultType
) 
1050                 case kSecTrustResultProceed
: 
1051                 case kSecTrustResultUnspecified
: 
1053                 case kSecTrustResultDeny
:                   // user reject 
1054                         result 
= errSecTimestampNotTrusted
;     // SecCmsVSTimestampNotTrusted ? 
1056                 case kSecTrustResultInvalid
: 
1057                         assert(false);                          // should never happen 
1058                         result 
= errSecTimestampNotTrusted
;     // SecCmsVSTimestampNotTrusted ? 
1060         case kSecTrustResultConfirm
: 
1061         case kSecTrustResultRecoverableTrustFailure
: 
1062         case kSecTrustResultFatalTrustFailure
: 
1063         case kSecTrustResultOtherError
: 
1067                     There are two "errors" that need to be resolved externally: 
1068                     CSSMERR_TP_CERT_EXPIRED can be OK if the timestamp was made 
1069                     before the TSA chain expired; CSSMERR_TP_CERT_NOT_VALID_YET 
1070                     can happen in the case where the user's clock was set to 0. 
1071                     We don't want to prevent them using apps automatically, so 
1072                     return noErr and let codesign or whover decide. 
1074                                 OSStatus resultCode
; 
1075                                 require_action(SecTrustGetCssmResultCode(trustRef
, &resultCode
)==noErr
, xit
, result 
= errSecTimestampNotTrusted
); 
1076                                 result 
= (resultCode 
== CSSMERR_TP_CERT_EXPIRED 
|| resultCode 
== CSSMERR_TP_CERT_NOT_VALID_YET
)?noErr
:errSecTimestampNotTrusted
; 
1081         rx 
= SecTrustGetResult(trustRef
, &trustResultType
, &certChain
, &statusChain
); 
1082         dtprintf("[%s] SecTrustGetResult: result: %d, type: %d\n", __FUNCTION__
,rx
, trustResultType
); 
1083         certCount 
= certChain
?CFArrayGetCount(certChain
):0; 
1084         debugShowCertEvidenceInfo(certCount
, statusChain
); 
1086         rx 
= SecTrustCopyExtendedResult(trustRef
, &extendedResult
); 
1087         dtprintf("[%s] SecTrustCopyExtendedResult: result: %d\n", __FUNCTION__
, rx
); 
1090             debugShowExtendedTrustResult(jx
, extendedResult
); 
1091             CFRelease(extendedResult
); 
1095             CFRelease (trustRef
); 
1104 static OSStatus 
impExpImportCertUnCommon( 
1105         const CSSM_DATA         
*cdata
, 
1106         SecKeychainRef          importKeychain
, // optional 
1107         CFMutableArrayRef       outArray
)               // optional, append here 
1109     // The only difference between this and impExpImportCertCommon is that we append to outArray 
1110     // before attempting to add to the keychain 
1111         OSStatus status 
= noErr
; 
1112         SecCertificateRef certRef 
= NULL
; 
1114     require_action(cdata
, xit
, status 
= errSecUnsupportedFormat
); 
1116         /* Pass kCFAllocatorNull as bytesDeallocator to assure the bytes aren't freed */ 
1117         CFDataRef data 
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, (const UInt8 
*)cdata
->Data
, (CFIndex
)cdata
->Length
, kCFAllocatorNull
); 
1118     require_action(data
, xit
, status 
= errSecUnsupportedFormat
); 
1120         certRef 
= SecCertificateCreateWithData(kCFAllocatorDefault
, data
); 
1121         CFRelease(data
); /* certRef has its own copy of the data now */ 
1123                 dtprintf("impExpHandleCert error\n"); 
1124                 return errSecUnsupportedFormat
; 
1128                 CFArrayAppendValue(outArray
, certRef
); 
1132                 status 
= SecCertificateAddToKeychain(certRef
, importKeychain
); 
1133                 if (status
!=noErr 
&& status
!=errSecDuplicateItem
) 
1134             { dtprintf("SecCertificateAddToKeychain error: %ld\n", (long)status
); } 
1143 static void saveTSACertificates(CSSM_DATA 
**signingCerts
, CFMutableArrayRef     outArray
) 
1145     SecKeychainRef defaultKeychain 
= NULL
; 
1146     // Don't save certificates in keychain to avoid securityd issues 
1147 //  if (SecKeychainCopyDefault(&defaultKeychain)) 
1148 //     defaultKeychain = NULL; 
1150     unsigned certCount 
= SecCmsArrayCount((void **)signingCerts
); 
1152     for (dex
=0; dex
<certCount
; dex
++) 
1154         OSStatus rx 
= impExpImportCertUnCommon(signingCerts
[dex
], defaultKeychain
, outArray
); 
1155         if (rx
!=noErr 
&& rx
!=errSecDuplicateItem
) 
1156             dtprintf("impExpImportCertCommon failed: %ld\n", (long)rx
); 
1158     if (defaultKeychain
) 
1159         CFRelease(defaultKeychain
); 
1162 static const char *cfabsoluteTimeToString(CFAbsoluteTime abstime
) 
1164     CFGregorianDate greg 
= CFAbsoluteTimeGetGregorianDate(abstime
, NULL
); 
1166     if (19 != snprintf(str
, 20, "%4.4d-%2.2d-%2.2d_%2.2d:%2.2d:%2.2d", 
1167         (int)greg
.year
, greg
.month
, greg
.day
, greg
.hour
, greg
.minute
, (int)greg
.second
)) 
1169     char *data 
= (char *)malloc(20); 
1170     strncpy(data
, str
, 20); 
1174 static OSStatus 
setTSALeafValidityDates(SecCmsSignerInfoRef signerinfo
) 
1176     OSStatus status 
= noErr
; 
1178     if (!signerinfo
->timestampCertList 
|| (CFArrayGetCount(signerinfo
->timestampCertList
) == 0)) 
1179         return SecCmsVSSigningCertNotFound
; 
1181     SecCertificateRef tsaLeaf 
= (SecCertificateRef
)CFArrayGetValueAtIndex(signerinfo
->timestampCertList
, 0); 
1182     require_action(tsaLeaf
, xit
, status 
= errSecCertificateCannotOperate
); 
1184     signerinfo
->tsaLeafNotBefore 
= SecCertificateNotValidBefore(tsaLeaf
); /* Start date for Timestamp Authority leaf */ 
1185     signerinfo
->tsaLeafNotAfter 
= SecCertificateNotValidAfter(tsaLeaf
);   /* Expiration date for Timestamp Authority leaf */ 
1187     const char *nbefore 
= cfabsoluteTimeToString(signerinfo
->tsaLeafNotBefore
); 
1188     const char *nafter 
= cfabsoluteTimeToString(signerinfo
->tsaLeafNotAfter
); 
1189     if (nbefore 
&& nafter
) 
1191         dtprintf("Timestamp Authority leaf valid from %s to %s\n", nbefore
, nafter
); 
1192         free((void *)nbefore
);free((void *)nafter
); 
1197                         status = errSecCertificateNotValidYet; 
1199                         status = errSecCertificateExpired; 
1207     From RFC 3161: Time-Stamp Protocol (TSP),August 2001, APPENDIX B: 
1209     B) The validity of the digital signature may then be verified in the 
1212         1)  The time-stamp token itself MUST be verified and it MUST be 
1213             verified that it applies to the signature of the signer. 
1215         2)  The date/time indicated by the TSA in the TimeStampToken 
1218         3)  The certificate used by the signer MUST be identified and 
1221         4)  The date/time indicated by the TSA MUST be within the 
1222             validity period of the signer's certificate. 
1224         5)  The revocation information about that certificate, at the 
1225             date/time of the Time-Stamping operation, MUST be retrieved. 
1227         6)  Should the certificate be revoked, then the date/time of 
1228             revocation shall be later than the date/time indicated by 
1231     If all these conditions are successful, then the digital signature 
1232     shall be declared as valid. 
1236 OSStatus 
decodeTimeStampToken(SecCmsSignerInfoRef signerinfo
, CSSM_DATA_PTR inData
, CSSM_DATA_PTR encDigest
, uint64_t expectedNonce
) 
1238     return decodeTimeStampTokenWithPolicy(signerinfo
, NULL
, inData
, encDigest
, expectedNonce
); 
1241 OSStatus 
decodeTimeStampTokenWithPolicy(SecCmsSignerInfoRef signerinfo
, CFTypeRef timeStampPolicy
, CSSM_DATA_PTR inData
, CSSM_DATA_PTR encDigest
, uint64_t expectedNonce
) 
1244         We update signerinfo with timestamp and tsa certificate chain. 
1245         encDigest is the original signed blob, which we must hash and compare. 
1246         inData comes from the unAuthAttr section of the CMS message 
1248         These are set in signerinfo as side effects: 
1253     SecCmsDecoderRef        decoderContext 
= NULL
; 
1254     SecCmsMessageRef        cmsMessage 
= NULL
; 
1255     SecCmsContentInfoRef    contentInfo
; 
1256     SecCmsSignedDataRef     signedData
; 
1257     SECOidTag               contentTypeTag
; 
1258     int                     contentLevelCount
; 
1260     OSStatus                result 
= errSecUnknownFormat
; 
1261     CSSM_DATA               
**signingCerts 
= NULL
; 
1263     dtprintf("decodeTimeStampToken top: PORT_GetError() %d -----\n", PORT_GetError()); 
1266     /* decode the message */ 
1267     require_noerr(result 
= SecCmsDecoderCreate (NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &decoderContext
), xit
); 
1268     result 
= SecCmsDecoderUpdate(decoderContext
, inData
->Data
, inData
->Length
); 
1271         result 
= errSecTimestampInvalid
; 
1272         SecCmsDecoderDestroy(decoderContext
); 
1276     require_noerr(result 
= SecCmsDecoderFinish(decoderContext
, &cmsMessage
), xit
); 
1278     // process the results 
1279     contentLevelCount 
= SecCmsMessageContentLevelCount(cmsMessage
); 
1282         printDataAsHex("encDigest",encDigest
, 0); 
1284     for (ix 
= 0; ix 
< contentLevelCount
; ++ix
) 
1286         dtprintf("\n----- Content Level %d -----\n", ix
); 
1287         // get content information 
1288         contentInfo 
= SecCmsMessageContentLevel (cmsMessage
, ix
); 
1289         contentTypeTag 
= SecCmsContentInfoGetContentTypeTag (contentInfo
); 
1291         // After 2nd round, contentInfo.content.data is the TSTInfo 
1293         debugShowContentTypeOID(contentInfo
); 
1295         switch (contentTypeTag
) 
1297         case SEC_OID_PKCS7_SIGNED_DATA
: 
1299             require((signedData 
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(contentInfo
)) != NULL
, xit
); 
1301             debugShowSignerInfo(signedData
); 
1303             SECAlgorithmID 
**digestAlgorithms 
= SecCmsSignedDataGetDigestAlgs(signedData
); 
1304             unsigned digestAlgCount 
= SecCmsArrayCount((void **)digestAlgorithms
); 
1305             dtprintf("digestAlgCount: %d\n", digestAlgCount
); 
1306             if (signedData
->digests
) 
1310                 for (jx
=0;jx 
< digestAlgCount
;jx
++) 
1312                     sprintf(buffer
, " digest[%u]", jx
); 
1313                     printDataAsHex(buffer
,signedData
->digests
[jx
], 0); 
1318                 dtprintf("No digests\n"); 
1319                 CSSM_DATA_PTR innerContent 
= SecCmsContentInfoGetInnerContent(contentInfo
); 
1322                     dtprintf("inner content length: %ld\n", innerContent
->Length
); 
1323                     SecAsn1TSAMessageImprint fakeMessageImprint 
= {{{0}},}; 
1324                     OSStatus status 
= createTSAMessageImprint(signedData
, innerContent
, &fakeMessageImprint
); 
1326                         {    dtprintf("createTSAMessageImprint status: %d\n", (int)status
); } 
1327                     printDataAsHex("inner content hash",&fakeMessageImprint
.hashedMessage
, 0); 
1328                     CSSM_DATA_PTR digestdata 
= &fakeMessageImprint
.hashedMessage
; 
1329                     CSSM_DATA_PTR digests
[2] = {digestdata
, NULL
}; 
1330                     SecCmsSignedDataSetDigests(signedData
, digestAlgorithms
, (CSSM_DATA_PTR 
*)&digests
); 
1333                     dtprintf("no inner content\n"); 
1337                 Import the certificates. We leave this as a warning, since 
1338                 there are configurations where the certificates are not returned. 
1340             signingCerts 
= SecCmsSignedDataGetCertificateList(signedData
); 
1341             if (signingCerts 
== NULL
) 
1342             {    dtprintf("SecCmsSignedDataGetCertificateList returned NULL\n"); } 
1345                 if (!signerinfo
->timestampCertList
) 
1346                     signerinfo
->timestampCertList 
= CFArrayCreateMutable(kCFAllocatorDefault
, 10, &kCFTypeArrayCallBacks
); 
1347                 saveTSACertificates(signingCerts
, signerinfo
->timestampCertList
); 
1348                 require_noerr(result 
= setTSALeafValidityDates(signerinfo
), xit
); 
1349                 debugSaveCertificates(signingCerts
); 
1352             int numberOfSigners 
= SecCmsSignedDataSignerInfoCount (signedData
); 
1354             result 
= verifySigners(signedData
, numberOfSigners
, timeStampPolicy
); 
1356                 dtprintf("verifySigners failed: %ld\n", (long)result
);   // warning 
1359             if (result
)     // remap to SecCmsVSTimestampNotTrusted ? 
1364         case SEC_OID_PKCS9_SIGNING_CERTIFICATE
: 
1366             dtprintf("SEC_OID_PKCS9_SIGNING_CERTIFICATE seen\n"); 
1370         case SEC_OID_PKCS9_ID_CT_TSTInfo
: 
1372             SecAsn1TSATSTInfo tstInfo 
= {{0},}; 
1373             result 
= verifyTSTInfo(contentInfo
->rawContent
, signingCerts
, &tstInfo
, &signerinfo
->timestampTime
, expectedNonce
); 
1374             if (signerinfo
->timestampTime
) 
1376                 const char *tstamp 
= cfabsoluteTimeToString(signerinfo
->timestampTime
); 
1379                     dtprintf("Timestamp Authority timestamp: %s\n", tstamp
); 
1380                     free((void *)tstamp
); 
1387             dtprintf("otherContent : %p\n", (char *)SecCmsContentInfoGetContent (contentInfo
)); 
1391             dtprintf("ContentTypeTag : %x\n", contentTypeTag
); 
1397                 SecCmsMessageDestroy(cmsMessage
);