2 * Copyright (c) 2012-2016 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/SecBasePriv.h>
45 #include <Security/SecPolicy.h>
46 #include <Security/SecTrustPriv.h>
47 #include <Security/SecImportExport.h>
48 #include <Security/SecCertificatePriv.h>
49 #include <utilities/SecCFRelease.h>
50 #include <utilities/SecDispatchRelease.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_secinfo(scope, format...) \
95 syslog(LOG_NOTICE, format); \
96 secinfo(scope, format); \
100 #define tsaDebug(args...) tsa_secinfo("tsa", ## args)
101 #define tsa_secinfo(scope, format...) \
102 secinfo(scope, format)
106 #define TSTINFO_DEBUG 1 //jch
110 #define dtprintf(args...) tsaDebug(args)
112 #define dtprintf(args...)
115 #define kHTTPResponseCodeContinue 100
116 #define kHTTPResponseCodeOK 200
117 #define kHTTPResponseCodeNoContent 204
118 #define kHTTPResponseCodeBadRequest 400
119 #define kHTTPResponseCodeUnauthorized 401
120 #define kHTTPResponseCodeForbidden 403
121 #define kHTTPResponseCodeNotFound 404
122 #define kHTTPResponseCodeConflict 409
123 #define kHTTPResponseCodeExpectationFailed 417
124 #define kHTTPResponseCodeServFail 500
125 #define kHTTPResponseCodeServiceUnavailable 503
126 #define kHTTPResponseCodeInsufficientStorage 507
128 #pragma mark ----- Debug/Utilities -----
130 static OSStatus
remapHTTPErrorCodes(OSStatus status
)
134 case kHTTPResponseCodeOK
:
135 case kHTTPResponseCodeContinue
:
137 case kHTTPResponseCodeBadRequest
:
138 return errSecTimestampBadRequest
;
139 case kHTTPResponseCodeNoContent
:
140 case kHTTPResponseCodeUnauthorized
:
141 case kHTTPResponseCodeForbidden
:
142 case kHTTPResponseCodeNotFound
:
143 case kHTTPResponseCodeConflict
:
144 case kHTTPResponseCodeExpectationFailed
:
145 case kHTTPResponseCodeServFail
:
146 case kHTTPResponseCodeInsufficientStorage
:
147 case kHTTPResponseCodeServiceUnavailable
:
148 return errSecTimestampServiceNotAvailable
;
156 static void printDataAsHex(const char *title
, const CSSM_DATA
*d
, unsigned maxToPrint
) // 0 means print it all
161 uint32 len
= (uint32
)d
->Length
;
166 const int wrapwid
= 24; // large enough so SHA-1 hashes fit on one line...
168 if ((maxToPrint
!= 0) && (len
> maxToPrint
))
174 bufferSize
= wrapwid
+3*len
;
175 buffer
= (char *)malloc(bufferSize
);
177 offset
= sprintf(buffer
, "%s [len = %u]\n", title
, len
);
178 dtprintf("%s", buffer
);
181 for (i
=0; (i
< len
) && (offset
+3 < bufferSize
); i
++, offset
+= sz
)
183 sz
= sprintf(buffer
+ offset
, " %02x", (unsigned int)cp
[i
] & 0xff);
184 if ((i
% wrapwid
) == (wrapwid
-1))
186 dtprintf("%s", buffer
);
192 sz
=sprintf(buffer
+ offset
, more
?" ...\n":"\n");
196 // fprintf(stderr, "%s", buffer);
197 dtprintf("%s", buffer
);
204 int tsaWriteFileX(const char *fileName
, const unsigned char *bytes
, size_t numBytes
)
209 fd
= open(fileName
, O_RDWR
| O_CREAT
| O_TRUNC
, 0600);
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
, SecCertificateRef signerCert
, 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,};
888 require(tstInfo
&& signerCert
&& (tstInfo
->genTime
.Length
< 16), xit
);;
890 memcpy(timeStr
, tstInfo
->genTime
.Data
, tstInfo
->genTime
.Length
);
891 timeStr
[tstInfo
->genTime
.Length
] = 0;
892 require_noerr(convertGeneralizedTimeToCFAbsoluteTime(timeStr
, &genTime
), xit
);
893 if (SecCertificateIsValidX(signerCert
, genTime
)) // iOS?
896 result
= errSecTimestampInvalid
;
898 *timestampTime
= genTime
;
903 static OSStatus
verifyTSTInfo(const CSSM_DATA_PTR content
, SecCertificateRef signerCert
, SecAsn1TSATSTInfo
*tstInfo
, CFAbsoluteTime
*timestampTime
, uint64_t expectedNonce
)
905 OSStatus status
= paramErr
;
906 SecAsn1CoderRef coder
= NULL
;
911 require_noerr(SecAsn1CoderCreate(&coder
), xit
);
912 require_noerr(SecAsn1Decode(coder
, content
->Data
, content
->Length
,
913 kSecAsn1TSATSTInfoTemplate
, tstInfo
), xit
);
914 displayTSTInfo(tstInfo
);
917 if (tstInfo
->nonce
.Data
&& expectedNonce
!=0)
919 uint64_t nonce
= tsaDER_ToInt(&tstInfo
->nonce
);
920 // if (expectedNonce!=nonce)
921 dtprintf("verifyTSTInfo nonce: actual: %lld, expected: %lld\n", nonce
, expectedNonce
);
922 require_action(expectedNonce
==nonce
, xit
, status
= errSecTimestampRejection
);
925 status
= SecTSAValidateTimestamp(tstInfo
, signerCert
, timestampTime
);
926 dtprintf("SecTSAValidateTimestamp result: %ld\n", (long)status
);
930 SecAsn1CoderRelease(coder
);
934 static void debugShowExtendedTrustResult(int index
, CFDictionaryRef extendedResult
)
939 CFStringRef xresStr
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
,
940 CFSTR("Extended trust result for signer #%d : %@"), index
, extendedResult
);
951 extern const char *cssmErrorString(CSSM_RETURN error
);
953 static void statusBitTest(CSSM_TP_APPLE_CERT_STATUS certStatus
, uint32 bit
, const char *str
)
955 if (certStatus
& bit
)
956 dtprintf("%s ", str
);
960 static void debugShowCertEvidenceInfo(uint16_t certCount
, const CSSM_TP_APPLE_EVIDENCE_INFO
*info
)
963 CSSM_TP_APPLE_CERT_STATUS cs
;
964 // const CSSM_TP_APPLE_EVIDENCE_INFO *pinfo = info;
966 for (ix
=0; info
&& (ix
<certCount
); ix
++, ++info
)
968 cs
= info
->StatusBits
;
969 dtprintf(" cert %u:\n", ix
);
970 dtprintf(" StatusBits : 0x%x", (unsigned)cs
);
974 statusBitTest(cs
, CSSM_CERT_STATUS_EXPIRED
, "EXPIRED");
975 statusBitTest(cs
, CSSM_CERT_STATUS_NOT_VALID_YET
,
977 statusBitTest(cs
, CSSM_CERT_STATUS_IS_IN_INPUT_CERTS
,
978 "IS_IN_INPUT_CERTS");
979 statusBitTest(cs
, CSSM_CERT_STATUS_IS_IN_ANCHORS
,
981 statusBitTest(cs
, CSSM_CERT_STATUS_IS_ROOT
, "IS_ROOT");
982 statusBitTest(cs
, CSSM_CERT_STATUS_IS_FROM_NET
, "IS_FROM_NET");
988 dtprintf(" NumStatusCodes : %u ", info
->NumStatusCodes
);
989 CSSM_RETURN
*pstatuscode
= info
->StatusCodes
;
991 for (jx
=0; pstatuscode
&& (jx
<info
->NumStatusCodes
); jx
++, ++pstatuscode
)
992 dtprintf("%s ", cssmErrorString(*pstatuscode
));
995 dtprintf(" Index: %u\n", info
->Index
);
1002 static const char *trustResultTypeString(SecTrustResultType trustResultType
)
1004 switch (trustResultType
)
1006 case kSecTrustResultProceed
: return "TrustResultProceed";
1007 case kSecTrustResultUnspecified
: return "TrustResultUnspecified";
1008 case kSecTrustResultDeny
: return "TrustResultDeny"; // user reject
1009 case kSecTrustResultInvalid
: return "TrustResultInvalid";
1010 case kSecTrustResultRecoverableTrustFailure
: return "TrustResultRecoverableTrustFailure";
1011 case kSecTrustResultFatalTrustFailure
: return "TrustResultUnspecified";
1012 case kSecTrustResultOtherError
: return "TrustResultOtherError";
1013 default: return "TrustResultUnknown";
1019 static OSStatus
verifySigners(SecCmsSignedDataRef signedData
, int numberOfSigners
, CFTypeRef timeStampPolicy
)
1021 // See <rdar://problem/11077588> Bubble up SecTrustEvaluate of timestamp response to high level callers
1022 // Also <rdar://problem/11077708> Properly handle revocation information of timestamping certificate
1024 SecTrustRef trustRef
= NULL
;
1025 CFTypeRef policy
= CFRetainSafe(timeStampPolicy
);
1026 int result
=errSecInternalError
;
1030 require(policy
= SecPolicyCreateWithOID(kSecPolicyAppleTimeStamping
), xit
);
1034 for (jx
= 0; jx
< numberOfSigners
; ++jx
)
1036 SecTrustResultType trustResultType
;
1037 CFDictionaryRef extendedResult
= NULL
;
1038 CFArrayRef certChain
= NULL
;
1039 uint16_t certCount
= 0;
1041 CSSM_TP_APPLE_EVIDENCE_INFO
*statusChain
= NULL
;
1043 // SecCmsSignedDataVerifySignerInfo returns trustRef, which we can call SecTrustEvaluate on
1044 // usually (always?) if result is noErr, the SecTrust*Result calls will return errSecTrustNotAvailable
1045 result
= SecCmsSignedDataVerifySignerInfo (signedData
, jx
, NULL
, policy
, &trustRef
);
1046 dtprintf("[%s] SecCmsSignedDataVerifySignerInfo: result: %d, signer: %d\n",
1047 __FUNCTION__
, result
, jx
);
1048 require_noerr(result
, xit
);
1050 result
= SecTrustEvaluate (trustRef
, &trustResultType
);
1051 dtprintf("[%s] SecTrustEvaluate: result: %d, trustResult: %s (%d)\n",
1052 __FUNCTION__
, result
, trustResultTypeString(trustResultType
), trustResultType
);
1055 switch (trustResultType
)
1057 case kSecTrustResultProceed
:
1058 case kSecTrustResultUnspecified
:
1060 case kSecTrustResultDeny
: // user reject
1061 result
= errSecTimestampNotTrusted
; // SecCmsVSTimestampNotTrusted ?
1063 case kSecTrustResultInvalid
:
1064 assert(false); // should never happen
1065 result
= errSecTimestampNotTrusted
; // SecCmsVSTimestampNotTrusted ?
1067 case kSecTrustResultRecoverableTrustFailure
:
1068 case kSecTrustResultFatalTrustFailure
:
1069 case kSecTrustResultOtherError
:
1073 There are two "errors" that need to be resolved externally:
1074 CSSMERR_TP_CERT_EXPIRED can be OK if the timestamp was made
1075 before the TSA chain expired; CSSMERR_TP_CERT_NOT_VALID_YET
1076 can happen in the case where the user's clock was set to 0.
1077 We don't want to prevent them using apps automatically, so
1078 return noErr and let codesign or whover decide.
1080 OSStatus resultCode
;
1081 require_action(SecTrustGetCssmResultCode(trustRef
, &resultCode
)==noErr
, xit
, result
= errSecTimestampNotTrusted
);
1082 result
= (resultCode
== CSSMERR_TP_CERT_EXPIRED
|| resultCode
== CSSMERR_TP_CERT_NOT_VALID_YET
)?noErr
:errSecTimestampNotTrusted
;
1087 rx
= SecTrustGetResult(trustRef
, &trustResultType
, &certChain
, &statusChain
);
1088 dtprintf("[%s] SecTrustGetResult: result: %d, type: %d\n", __FUNCTION__
,rx
, trustResultType
);
1089 certCount
= certChain
?CFArrayGetCount(certChain
):0;
1090 debugShowCertEvidenceInfo(certCount
, statusChain
);
1091 CFReleaseNull(certChain
);
1093 rx
= SecTrustCopyExtendedResult(trustRef
, &extendedResult
);
1094 dtprintf("[%s] SecTrustCopyExtendedResult: result: %d\n", __FUNCTION__
, rx
);
1097 debugShowExtendedTrustResult(jx
, extendedResult
);
1098 CFRelease(extendedResult
);
1102 CFReleaseNull(trustRef
);
1107 CFReleaseNull(trustRef
);
1113 static OSStatus
impExpImportCertUnCommon(
1114 const CSSM_DATA
*cdata
,
1115 SecKeychainRef importKeychain
, // optional
1116 CFMutableArrayRef outArray
) // optional, append here
1118 // The only difference between this and impExpImportCertCommon is that we append to outArray
1119 // before attempting to add to the keychain
1120 OSStatus status
= noErr
;
1121 SecCertificateRef certRef
= NULL
;
1123 require_action(cdata
, xit
, status
= errSecUnsupportedFormat
);
1125 /* Pass kCFAllocatorNull as bytesDeallocator to assure the bytes aren't freed */
1126 CFDataRef data
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, (const UInt8
*)cdata
->Data
, (CFIndex
)cdata
->Length
, kCFAllocatorNull
);
1127 require_action(data
, xit
, status
= errSecUnsupportedFormat
);
1129 certRef
= SecCertificateCreateWithData(kCFAllocatorDefault
, data
);
1130 CFRelease(data
); /* certRef has its own copy of the data now */
1132 dtprintf("impExpHandleCert error\n");
1133 return errSecUnsupportedFormat
;
1137 CFArrayAppendValue(outArray
, certRef
);
1141 status
= SecCertificateAddToKeychain(certRef
, importKeychain
);
1142 if (status
!=noErr
&& status
!=errSecDuplicateItem
)
1143 { dtprintf("SecCertificateAddToKeychain error: %ld\n", (long)status
); }
1152 static void saveTSACertificates(CSSM_DATA
**signingCerts
, CFMutableArrayRef outArray
)
1154 SecKeychainRef defaultKeychain
= NULL
;
1155 // Don't save certificates in keychain to avoid securityd issues
1156 // if (SecKeychainCopyDefault(&defaultKeychain))
1157 // defaultKeychain = NULL;
1159 unsigned certCount
= SecCmsArrayCount((void **)signingCerts
);
1161 for (dex
=0; dex
<certCount
; dex
++)
1163 OSStatus rx
= impExpImportCertUnCommon(signingCerts
[dex
], defaultKeychain
, outArray
);
1164 if (rx
!=noErr
&& rx
!=errSecDuplicateItem
)
1165 dtprintf("impExpImportCertCommon failed: %ld\n", (long)rx
);
1167 if (defaultKeychain
)
1168 CFRelease(defaultKeychain
);
1171 static const char *cfabsoluteTimeToString(CFAbsoluteTime abstime
)
1173 CFGregorianDate greg
= CFAbsoluteTimeGetGregorianDate(abstime
, NULL
);
1175 if (19 != snprintf(str
, 20, "%4.4d-%2.2d-%2.2d_%2.2d:%2.2d:%2.2d",
1176 (int)greg
.year
, greg
.month
, greg
.day
, greg
.hour
, greg
.minute
, (int)greg
.second
))
1178 char *data
= (char *)malloc(20);
1179 strncpy(data
, str
, 20);
1183 static OSStatus
setTSALeafValidityDates(SecCmsSignerInfoRef signerinfo
)
1185 SecCertificateRef tsaLeaf
= SecCmsSignerInfoGetSigningCertificate(signerinfo
, NULL
);
1188 return SecCmsVSSigningCertNotFound
;
1190 signerinfo
->tsaLeafNotBefore
= SecCertificateNotValidBefore(tsaLeaf
); /* Start date for Timestamp Authority leaf */
1191 signerinfo
->tsaLeafNotAfter
= SecCertificateNotValidAfter(tsaLeaf
); /* Expiration date for Timestamp Authority leaf */
1193 const char *nbefore
= cfabsoluteTimeToString(signerinfo
->tsaLeafNotBefore
);
1194 const char *nafter
= cfabsoluteTimeToString(signerinfo
->tsaLeafNotAfter
);
1195 if (nbefore
&& nafter
)
1197 dtprintf("Timestamp Authority leaf valid from %s to %s\n", nbefore
, nafter
);
1198 free((void *)nbefore
);free((void *)nafter
);
1201 return errSecSuccess
;
1205 From RFC 3161: Time-Stamp Protocol (TSP),August 2001, APPENDIX B:
1207 B) The validity of the digital signature may then be verified in the
1210 1) The time-stamp token itself MUST be verified and it MUST be
1211 verified that it applies to the signature of the signer.
1213 2) The date/time indicated by the TSA in the TimeStampToken
1216 3) The certificate used by the signer MUST be identified and
1219 4) The date/time indicated by the TSA MUST be within the
1220 validity period of the signer's certificate.
1222 5) The revocation information about that certificate, at the
1223 date/time of the Time-Stamping operation, MUST be retrieved.
1225 6) Should the certificate be revoked, then the date/time of
1226 revocation shall be later than the date/time indicated by
1229 If all these conditions are successful, then the digital signature
1230 shall be declared as valid.
1234 OSStatus
decodeTimeStampToken(SecCmsSignerInfoRef signerinfo
, CSSM_DATA_PTR inData
, CSSM_DATA_PTR encDigest
, uint64_t expectedNonce
)
1236 return decodeTimeStampTokenWithPolicy(signerinfo
, NULL
, inData
, encDigest
, expectedNonce
);
1239 OSStatus
decodeTimeStampTokenWithPolicy(SecCmsSignerInfoRef signerinfo
, CFTypeRef timeStampPolicy
, CSSM_DATA_PTR inData
, CSSM_DATA_PTR encDigest
, uint64_t expectedNonce
)
1242 We update signerinfo with timestamp and tsa certificate chain.
1243 encDigest is the original signed blob, which we must hash and compare.
1244 inData comes from the unAuthAttr section of the CMS message
1246 These are set in signerinfo as side effects:
1251 SecCmsDecoderRef decoderContext
= NULL
;
1252 SecCmsMessageRef cmsMessage
= NULL
;
1253 SecCmsContentInfoRef contentInfo
;
1254 SecCmsSignedDataRef signedData
;
1255 SECOidTag contentTypeTag
;
1256 int contentLevelCount
;
1258 OSStatus result
= errSecUnknownFormat
;
1259 CSSM_DATA
**signingCerts
= NULL
;
1261 dtprintf("decodeTimeStampToken top: PORT_GetError() %d -----\n", PORT_GetError());
1264 /* decode the message */
1265 require_noerr(result
= SecCmsDecoderCreate (NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &decoderContext
), xit
);
1266 result
= SecCmsDecoderUpdate(decoderContext
, inData
->Data
, inData
->Length
);
1269 result
= errSecTimestampInvalid
;
1270 SecCmsDecoderDestroy(decoderContext
);
1274 require_noerr(result
= SecCmsDecoderFinish(decoderContext
, &cmsMessage
), xit
);
1276 // process the results
1277 contentLevelCount
= SecCmsMessageContentLevelCount(cmsMessage
);
1280 printDataAsHex("encDigest",encDigest
, 0);
1282 for (ix
= 0; ix
< contentLevelCount
; ++ix
)
1284 dtprintf("\n----- Content Level %d -----\n", ix
);
1285 // get content information
1286 contentInfo
= SecCmsMessageContentLevel (cmsMessage
, ix
);
1287 contentTypeTag
= SecCmsContentInfoGetContentTypeTag (contentInfo
);
1289 // After 2nd round, contentInfo.content.data is the TSTInfo
1291 debugShowContentTypeOID(contentInfo
);
1293 switch (contentTypeTag
)
1295 case SEC_OID_PKCS7_SIGNED_DATA
:
1297 require((signedData
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(contentInfo
)) != NULL
, xit
);
1299 debugShowSignerInfo(signedData
);
1301 SECAlgorithmID
**digestAlgorithms
= SecCmsSignedDataGetDigestAlgs(signedData
);
1302 unsigned digestAlgCount
= SecCmsArrayCount((void **)digestAlgorithms
);
1303 dtprintf("digestAlgCount: %d\n", digestAlgCount
);
1304 if (signedData
->digests
)
1308 for (jx
=0;jx
< digestAlgCount
;jx
++)
1310 sprintf(buffer
, " digest[%u]", jx
);
1311 printDataAsHex(buffer
,signedData
->digests
[jx
], 0);
1316 dtprintf("No digests\n");
1317 CSSM_DATA_PTR innerContent
= SecCmsContentInfoGetInnerContent(contentInfo
);
1320 dtprintf("inner content length: %ld\n", innerContent
->Length
);
1321 SecAsn1TSAMessageImprint fakeMessageImprint
= {{{0}},};
1322 OSStatus status
= createTSAMessageImprint(signedData
, innerContent
, &fakeMessageImprint
);
1323 require_noerr_action(status
, xit
, dtprintf("createTSAMessageImprint status: %d\n", (int)status
); result
= status
);
1324 printDataAsHex("inner content hash",&fakeMessageImprint
.hashedMessage
, 0);
1325 CSSM_DATA_PTR digestdata
= &fakeMessageImprint
.hashedMessage
;
1326 CSSM_DATA_PTR digests
[2] = {digestdata
, NULL
};
1327 status
= SecCmsSignedDataSetDigests(signedData
, digestAlgorithms
, (CSSM_DATA_PTR
*)&digests
);
1328 require_noerr_action(status
, xit
, dtprintf("createTSAMessageImprint status: %d\n", (int)status
); result
= status
);
1331 dtprintf("no inner content\n");
1335 Import the certificates. We leave this as a warning, since
1336 there are configurations where the certificates are not returned.
1338 signingCerts
= SecCmsSignedDataGetCertificateList(signedData
);
1339 if (signingCerts
== NULL
)
1340 { dtprintf("SecCmsSignedDataGetCertificateList returned NULL\n"); }
1343 if (!signerinfo
->timestampCertList
)
1344 signerinfo
->timestampCertList
= CFArrayCreateMutable(kCFAllocatorDefault
, 10, &kCFTypeArrayCallBacks
);
1345 saveTSACertificates(signingCerts
, signerinfo
->timestampCertList
);
1346 require_noerr(result
= setTSALeafValidityDates(signerinfo
), xit
);
1347 debugSaveCertificates(signingCerts
);
1350 int numberOfSigners
= SecCmsSignedDataSignerInfoCount (signedData
);
1352 result
= verifySigners(signedData
, numberOfSigners
, timeStampPolicy
);
1354 dtprintf("verifySigners failed: %ld\n", (long)result
); // warning
1357 if (result
) // remap to SecCmsVSTimestampNotTrusted ?
1362 case SEC_OID_PKCS9_SIGNING_CERTIFICATE
:
1364 dtprintf("SEC_OID_PKCS9_SIGNING_CERTIFICATE seen\n");
1368 case SEC_OID_PKCS9_ID_CT_TSTInfo
:
1370 SecAsn1TSATSTInfo tstInfo
= {{0},};
1371 SecCertificateRef signerCert
= SecCmsSignerInfoGetSigningCertificate(signerinfo
, NULL
);
1372 result
= verifyTSTInfo(contentInfo
->rawContent
, signerCert
, &tstInfo
, &signerinfo
->timestampTime
, expectedNonce
);
1373 if (signerinfo
->timestampTime
)
1375 const char *tstamp
= cfabsoluteTimeToString(signerinfo
->timestampTime
);
1378 dtprintf("Timestamp Authority timestamp: %s\n", tstamp
);
1379 free((void *)tstamp
);
1386 dtprintf("otherContent : %p\n", (char *)SecCmsContentInfoGetContent (contentInfo
));
1390 dtprintf("ContentTypeTag : %x\n", contentTypeTag
);
1396 SecCmsMessageDestroy(cmsMessage
);