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
)) {
173 bufferSize
= wrapwid
+3*len
;
174 buffer
= (char *)malloc(bufferSize
);
176 offset
= sprintf(buffer
, "%s [len = %u]\n", title
, len
);
177 dtprintf("%s", buffer
);
180 for (i
=0; (i
< len
) && (offset
+3 < bufferSize
); i
++, offset
+= sz
) {
181 sz
= sprintf(buffer
+ offset
, " %02x", (unsigned int)cp
[i
] & 0xff);
182 if ((i
% wrapwid
) == (wrapwid
-1)) {
183 dtprintf("%s\n", buffer
);
189 sz
=sprintf(buffer
+ offset
, more
?" ...\n":"\n");
193 dtprintf("%s", buffer
);
200 int tsaWriteFileX(const char *fileName
, const unsigned char *bytes
, size_t numBytes
)
205 fd
= open(fileName
, O_RDWR
| O_CREAT
| O_TRUNC
, 0600);
210 rtn
= (int)write(fd
, bytes
, numBytes
);
211 if(rtn
!= (int)numBytes
)
214 fprintf(stderr
, "writeFile: short write\n");
225 char *cfStringToChar(CFStringRef inStr
)
229 const char *str
= NULL
;
232 return strdup(""); // return a null string
235 if ((str
= CFStringGetCStringPtr(inStr
, kCFStringEncodingUTF8
))) {
236 result
= strdup(str
);
238 // need to extract into buffer
239 CFIndex length
= CFStringGetLength(inStr
); // in 16-bit character units
240 CFIndex bytesToAllocate
= CFStringGetMaximumSizeForEncoding(length
, kCFStringEncodingUTF8
) + 1;
241 result
= malloc(bytesToAllocate
);
242 if (!CFStringGetCString(inStr
, result
, bytesToAllocate
, kCFStringEncodingUTF8
))
249 /* Oids longer than this are considered invalid. */
250 #define MAX_OID_SIZE 32
253 /* FIXME: There are other versions of this in SecCertifcate.c and SecCertificateP.c */
254 static CFStringRef
SecDERItemCopyOIDDecimalRepresentation(CFAllocatorRef allocator
, const CSSM_OID
*oid
)
256 if (oid
->Length
== 0)
257 return CFSTR("<NULL>");
259 if (oid
->Length
> MAX_OID_SIZE
)
260 return CFSTR("Oid too long");
262 CFMutableStringRef result
= CFStringCreateMutable(allocator
, 0);
264 // The first two levels are encoded into one byte, since the root levelq
265 // has only 3 nodes (40*x + y). However if x = joint-iso-itu-t(2) then
266 // y may be > 39, so we have to add special-case handling for this.
267 uint32_t x
= oid
->Data
[0] / 40;
268 uint32_t y
= oid
->Data
[0] % 40;
271 // Handle special case for large y if x = 2
275 CFStringAppendFormat(result
, NULL
, CFSTR("%u.%u"), x
, y
);
278 for (x
= 1; x
< oid
->Length
; ++x
)
280 value
= (value
<< 7) | (oid
->Data
[x
] & 0x7F);
281 /* @@@ value may not span more than 4 bytes. */
282 /* A max number of 20 values is allowed. */
283 if (!(oid
->Data
[x
] & 0x80))
285 CFStringAppendFormat(result
, NULL
, CFSTR(".%lu"), (unsigned long)value
);
293 static void debugSaveCertificates(CSSM_DATA
**outCerts
)
298 CSSM_DATA_PTR
*certp
;
300 const char *certNameBase
= "/tmp/tsa-resp-cert-";
301 char fname
[PATH_MAX
];
302 unsigned certCount
= SecCmsArrayCount((void **)outCerts
);
303 dtprintf("Found %d certs\n",certCount
);
305 for (certp
=outCerts
;*certp
;certp
++, ++jx
)
308 strncpy(fname
, certNameBase
, strlen(certNameBase
)+1);
309 sprintf(numstr
,"%u", jx
);
310 strcat(fname
,numstr
);
311 tsaWriteFileX(fname
, (*certp
)->Data
, (*certp
)->Length
);
313 break; //something wrong
319 static void debugShowSignerInfo(SecCmsSignedDataRef signedData
)
322 int numberOfSigners
= SecCmsSignedDataSignerInfoCount (signedData
);
323 dtprintf("numberOfSigners : %d\n", numberOfSigners
);
325 for (ix
=0;ix
< numberOfSigners
;ix
++)
327 SecCmsSignerInfoRef sigi
= SecCmsSignedDataGetSignerInfo(signedData
,ix
);
330 CFStringRef commonName
= SecCmsSignerInfoGetSignerCommonName(sigi
);
331 const char *signerhdr
= " signer : ";
334 char *cn
= cfStringToChar(commonName
);
335 dtprintf("%s%s\n", signerhdr
, cn
);
338 CFReleaseNull(commonName
);
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_safe(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
); }
595 if (waitSemaphore
) { dispatch_semaphore_signal(waitSemaphore
); }
596 dispatch_release_null(waitSemaphore
);
598 { tsaDebug("waiting up to %d seconds for response from XPC\n", timeoutInSeconds
); }
599 if (waitSemaphore
) { dispatch_semaphore_wait(waitSemaphore
, finishTime
); }
601 dispatch_release_null(waitSemaphore
);
602 xpc_release(tsaReqData
);
603 xpc_release(message
);
605 { tsaDebug("sendTSARequestWithXPC exit\n"); }
610 #pragma mark ----- TimeStamp request -----
612 #include "tsaTemplates.h"
613 #include <security_asn1/SecAsn1Coder.h>
614 #include <Security/oidsalg.h>
615 #include <AssertMacros.h>
616 #include <libkern/OSByteOrder.h>
618 extern const SecAsn1Template kSecAsn1TSATimeStampReqTemplate
;
619 extern const SecAsn1Template kSecAsn1TSATimeStampRespTemplateDER
;
621 CFMutableDictionaryRef
SecCmsTSAGetDefaultContext(CFErrorRef
*error
)
623 // Caller responsible for retain/release
624 // <rdar://problem/11077440> Update SecCmsTSAGetDefaultContext with actual URL for Apple Timestamp server
625 // URL will be in TimeStampingPrefs.plist
627 CFBundleRef secFWbundle
= NULL
;
628 CFURLRef resourceURL
= NULL
;
629 CFDataRef resourceData
= NULL
;
630 CFPropertyListRef prefs
= NULL
;
631 CFMutableDictionaryRef contextDict
= NULL
;
632 SInt32 errorCode
= 0;
633 CFOptionFlags options
= 0;
634 CFPropertyListFormat format
= 0;
635 OSStatus status
= noErr
;
637 require_action(secFWbundle
= CFBundleGetBundleWithIdentifier(CFSTR("com.apple.security")), xit
, status
= errSecInternalError
);
638 CFRetain(secFWbundle
);
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 CFTypeRef url
= CFDictionaryGetValue((CFDictionaryRef
)context
, kTSAContextKeyURL
);
781 tsaDebug("[TSA] missing URL for TSA (key: %s)\n", "kTSAContextKeyURL");
785 CFStringRef urlStr
= NULL
;
786 if (CFURLGetTypeID() == CFGetTypeID(url
)) {
787 urlStr
= CFURLGetString(url
);
789 require_quiet(CFStringGetTypeID() == CFGetTypeID(url
), xit
);
792 require_quiet(urlStr
, xit
);
795 If debugging, look at special values in the context to mess things up
798 CFBooleanRef cfBadReq
= (CFBooleanRef
)CFDictionaryGetValue((CFDictionaryRef
)context
, kTSADebugContextKeyBadReq
);
799 if (cfBadReq
&& CFBooleanGetValue(cfBadReq
))
801 tsaDebug("[TSA] Forcing bad TS Request by truncating length from %ld to %ld\n", tsaReqLength
, (tsaReqLength
-4));
805 // need to extract into buffer
806 CFIndex length
= CFStringGetLength(urlStr
); // in 16-bit character units
807 tsaURL
= malloc(6 * length
+ 1); // pessimistic
808 if (!CFStringGetCString(urlStr
, (char *)tsaURL
, 6 * length
+ 1, kCFStringEncodingUTF8
))
811 tsaDebug("[TSA] URL for timestamp server: %s\n", tsaURL
);
813 unsigned char *tsaResp
= NULL
;
814 size_t tsaRespLength
= 0;
815 tsaDebug("calling sendTSARequestWithXPC with %ld bytes of request\n", tsaReqLength
);
817 require_noerr(result
= sendTSARequestWithXPC(tsaReq
, tsaReqLength
, tsaURL
, &tsaResp
, &tsaRespLength
), xit
);
819 tsaDebug("sendTSARequestWithXPC copied: %ld bytes of response\n", tsaRespLength
);
821 signedDERBlob
->Data
= tsaResp
;
822 signedDERBlob
->Length
= tsaRespLength
;
828 free((void *)tsaURL
);
835 #pragma mark ----- TimeStamp Verification -----
837 static OSStatus
convertGeneralizedTimeToCFAbsoluteTime(const char *timeStr
, CFAbsoluteTime
*ptime
)
840 See http://userguide.icu-project.org/formatparse/datetime for date/time format.
841 The "Z" signal a GMT time, but CFDateFormatterGetAbsoluteTimeFromString returns
842 values based on local time.
845 OSStatus result
= noErr
;
846 CFDateFormatterRef formatter
= NULL
;
847 CFStringRef time_string
= NULL
;
848 CFTimeZoneRef gmt
= NULL
;
849 CFLocaleRef locale
= NULL
;
850 CFRange
*rangep
= NULL
;
852 require(timeStr
&& timeStr
[0] && ptime
, xit
);
853 require(formatter
= CFDateFormatterCreate(kCFAllocatorDefault
, locale
, kCFDateFormatterNoStyle
, kCFDateFormatterNoStyle
), xit
);
854 // CFRetain(formatter);
855 CFDateFormatterSetFormat(formatter
, CFSTR("yyyyMMddHHmmss'Z'")); // GeneralizedTime
856 gmt
= CFTimeZoneCreateWithTimeIntervalFromGMT(NULL
, 0);
857 CFDateFormatterSetProperty(formatter
, kCFDateFormatterTimeZone
, gmt
);
859 time_string
= CFStringCreateWithCString(kCFAllocatorDefault
, timeStr
, kCFStringEncodingUTF8
);
860 if (!time_string
|| !CFDateFormatterGetAbsoluteTimeFromString(formatter
, time_string
, rangep
, ptime
))
862 dtprintf("%s is not a valid date\n", timeStr
);
868 CFRelease(formatter
);
870 CFRelease(time_string
);
877 static OSStatus
SecTSAValidateTimestamp(const SecAsn1TSATSTInfo
*tstInfo
, SecCertificateRef signerCert
, CFAbsoluteTime
*timestampTime
)
879 // See <rdar://problem/11077708> Properly handle revocation information of timestamping certificate
880 OSStatus result
= paramErr
;
881 CFAbsoluteTime genTime
= 0;
882 char timeStr
[32] = {0,};
884 require(tstInfo
&& signerCert
&& (tstInfo
->genTime
.Length
< 16), xit
);;
886 memcpy(timeStr
, tstInfo
->genTime
.Data
, tstInfo
->genTime
.Length
);
887 timeStr
[tstInfo
->genTime
.Length
] = 0;
888 require_noerr(convertGeneralizedTimeToCFAbsoluteTime(timeStr
, &genTime
), xit
);
889 if (SecCertificateIsValidX(signerCert
, genTime
)) // iOS?
892 result
= errSecTimestampInvalid
;
894 *timestampTime
= genTime
;
899 static OSStatus
verifyTSTInfo(const CSSM_DATA_PTR content
, SecCertificateRef signerCert
, SecAsn1TSATSTInfo
*tstInfo
, CFAbsoluteTime
*timestampTime
, uint64_t expectedNonce
)
901 OSStatus status
= paramErr
;
902 SecAsn1CoderRef coder
= NULL
;
907 require_noerr(SecAsn1CoderCreate(&coder
), xit
);
908 require_noerr(SecAsn1Decode(coder
, content
->Data
, content
->Length
,
909 kSecAsn1TSATSTInfoTemplate
, tstInfo
), xit
);
910 displayTSTInfo(tstInfo
);
913 if (tstInfo
->nonce
.Data
&& expectedNonce
!=0)
915 uint64_t nonce
= tsaDER_ToInt(&tstInfo
->nonce
);
916 // if (expectedNonce!=nonce)
917 dtprintf("verifyTSTInfo nonce: actual: %lld, expected: %lld\n", nonce
, expectedNonce
);
918 require_action(expectedNonce
==nonce
, xit
, status
= errSecTimestampRejection
);
921 status
= SecTSAValidateTimestamp(tstInfo
, signerCert
, timestampTime
);
922 dtprintf("SecTSAValidateTimestamp result: %ld\n", (long)status
);
926 SecAsn1CoderRelease(coder
);
930 static void debugShowExtendedTrustResult(int index
, CFDictionaryRef extendedResult
)
935 CFStringRef xresStr
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
,
936 CFSTR("Extended trust result for signer #%d : %@"), index
, extendedResult
);
947 extern const char *cssmErrorString(CSSM_RETURN error
);
949 static void statusBitTest(CSSM_TP_APPLE_CERT_STATUS certStatus
, uint32 bit
, const char *str
)
951 if (certStatus
& bit
)
952 dtprintf("%s ", str
);
956 static void debugShowCertEvidenceInfo(uint16_t certCount
, const CSSM_TP_APPLE_EVIDENCE_INFO
*info
)
959 CSSM_TP_APPLE_CERT_STATUS cs
;
960 // const CSSM_TP_APPLE_EVIDENCE_INFO *pinfo = info;
962 for (ix
=0; info
&& (ix
<certCount
); ix
++, ++info
)
964 cs
= info
->StatusBits
;
965 dtprintf(" cert %u:\n", ix
);
966 dtprintf(" StatusBits : 0x%x", (unsigned)cs
);
970 statusBitTest(cs
, CSSM_CERT_STATUS_EXPIRED
, "EXPIRED");
971 statusBitTest(cs
, CSSM_CERT_STATUS_NOT_VALID_YET
,
973 statusBitTest(cs
, CSSM_CERT_STATUS_IS_IN_INPUT_CERTS
,
974 "IS_IN_INPUT_CERTS");
975 statusBitTest(cs
, CSSM_CERT_STATUS_IS_IN_ANCHORS
,
977 statusBitTest(cs
, CSSM_CERT_STATUS_IS_ROOT
, "IS_ROOT");
978 statusBitTest(cs
, CSSM_CERT_STATUS_IS_FROM_NET
, "IS_FROM_NET");
984 dtprintf(" NumStatusCodes : %u ", info
->NumStatusCodes
);
985 CSSM_RETURN
*pstatuscode
= info
->StatusCodes
;
987 for (jx
=0; pstatuscode
&& (jx
<info
->NumStatusCodes
); jx
++, ++pstatuscode
)
988 dtprintf("%s ", cssmErrorString(*pstatuscode
));
991 dtprintf(" Index: %u\n", info
->Index
);
998 static const char *trustResultTypeString(SecTrustResultType trustResultType
)
1000 switch (trustResultType
)
1002 case kSecTrustResultProceed
: return "TrustResultProceed";
1003 case kSecTrustResultUnspecified
: return "TrustResultUnspecified";
1004 case kSecTrustResultDeny
: return "TrustResultDeny"; // user reject
1005 case kSecTrustResultInvalid
: return "TrustResultInvalid";
1006 case kSecTrustResultRecoverableTrustFailure
: return "TrustResultRecoverableTrustFailure";
1007 case kSecTrustResultFatalTrustFailure
: return "TrustResultUnspecified";
1008 case kSecTrustResultOtherError
: return "TrustResultOtherError";
1009 default: return "TrustResultUnknown";
1015 static OSStatus
verifySigners(SecCmsSignedDataRef signedData
, int numberOfSigners
, CFTypeRef timeStampPolicy
)
1017 // See <rdar://problem/11077588> Bubble up SecTrustEvaluate of timestamp response to high level callers
1018 // Also <rdar://problem/11077708> Properly handle revocation information of timestamping certificate
1020 SecTrustRef trustRef
= NULL
;
1021 CFTypeRef policy
= CFRetainSafe(timeStampPolicy
);
1022 int result
=errSecInternalError
;
1026 require(policy
= SecPolicyCreateWithOID(kSecPolicyAppleTimeStamping
), xit
);
1030 for (jx
= 0; jx
< numberOfSigners
; ++jx
)
1032 SecTrustResultType trustResultType
;
1033 CFDictionaryRef extendedResult
= NULL
;
1034 CFArrayRef certChain
= NULL
;
1035 uint16_t certCount
= 0;
1037 CSSM_TP_APPLE_EVIDENCE_INFO
*statusChain
= NULL
;
1039 // SecCmsSignedDataVerifySignerInfo returns trustRef, which we can call SecTrustEvaluate on
1040 // usually (always?) if result is noErr, the SecTrust*Result calls will return errSecTrustNotAvailable
1041 result
= SecCmsSignedDataVerifySignerInfo (signedData
, jx
, NULL
, policy
, &trustRef
);
1042 dtprintf("[%s] SecCmsSignedDataVerifySignerInfo: result: %d, signer: %d\n",
1043 __FUNCTION__
, result
, jx
);
1044 require_noerr(result
, xit
);
1046 result
= SecTrustEvaluate (trustRef
, &trustResultType
);
1047 dtprintf("[%s] SecTrustEvaluate: result: %d, trustResult: %s (%d)\n",
1048 __FUNCTION__
, result
, trustResultTypeString(trustResultType
), trustResultType
);
1051 switch (trustResultType
)
1053 case kSecTrustResultProceed
:
1054 case kSecTrustResultUnspecified
:
1056 case kSecTrustResultDeny
: // user reject
1057 result
= errSecTimestampNotTrusted
; // SecCmsVSTimestampNotTrusted ?
1059 case kSecTrustResultInvalid
:
1060 assert(false); // should never happen
1061 result
= errSecTimestampNotTrusted
; // SecCmsVSTimestampNotTrusted ?
1063 case kSecTrustResultRecoverableTrustFailure
:
1064 case kSecTrustResultFatalTrustFailure
:
1065 case kSecTrustResultOtherError
:
1069 There are two "errors" that need to be resolved externally:
1070 CSSMERR_TP_CERT_EXPIRED can be OK if the timestamp was made
1071 before the TSA chain expired; CSSMERR_TP_CERT_NOT_VALID_YET
1072 can happen in the case where the user's clock was set to 0.
1073 We don't want to prevent them using apps automatically, so
1074 return noErr and let codesign or whover decide.
1076 OSStatus resultCode
;
1077 require_action(SecTrustGetCssmResultCode(trustRef
, &resultCode
)==noErr
, xit
, result
= errSecTimestampNotTrusted
);
1078 result
= (resultCode
== CSSMERR_TP_CERT_EXPIRED
|| resultCode
== CSSMERR_TP_CERT_NOT_VALID_YET
)?noErr
:errSecTimestampNotTrusted
;
1083 rx
= SecTrustGetResult(trustRef
, &trustResultType
, &certChain
, &statusChain
);
1084 dtprintf("[%s] SecTrustGetResult: result: %d, type: %d\n", __FUNCTION__
,rx
, trustResultType
);
1085 certCount
= certChain
?CFArrayGetCount(certChain
):0;
1086 debugShowCertEvidenceInfo(certCount
, statusChain
);
1087 CFReleaseNull(certChain
);
1089 rx
= SecTrustCopyExtendedResult(trustRef
, &extendedResult
);
1090 dtprintf("[%s] SecTrustCopyExtendedResult: result: %d\n", __FUNCTION__
, rx
);
1093 debugShowExtendedTrustResult(jx
, extendedResult
);
1094 CFRelease(extendedResult
);
1098 CFReleaseNull(trustRef
);
1103 CFReleaseNull(trustRef
);
1109 static OSStatus
impExpImportCertUnCommon(
1110 const CSSM_DATA
*cdata
,
1111 SecKeychainRef importKeychain
, // optional
1112 CFMutableArrayRef outArray
) // optional, append here
1114 // The only difference between this and impExpImportCertCommon is that we append to outArray
1115 // before attempting to add to the keychain
1116 OSStatus status
= noErr
;
1117 SecCertificateRef certRef
= NULL
;
1119 require_action(cdata
, xit
, status
= errSecUnsupportedFormat
);
1121 /* Pass kCFAllocatorNull as bytesDeallocator to assure the bytes aren't freed */
1122 CFDataRef data
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, (const UInt8
*)cdata
->Data
, (CFIndex
)cdata
->Length
, kCFAllocatorNull
);
1123 require_action(data
, xit
, status
= errSecUnsupportedFormat
);
1125 certRef
= SecCertificateCreateWithData(kCFAllocatorDefault
, data
);
1126 CFRelease(data
); /* certRef has its own copy of the data now */
1128 dtprintf("impExpHandleCert error\n");
1129 return errSecUnsupportedFormat
;
1133 CFArrayAppendValue(outArray
, certRef
);
1137 status
= SecCertificateAddToKeychain(certRef
, importKeychain
);
1138 if (status
!=noErr
&& status
!=errSecDuplicateItem
)
1139 { dtprintf("SecCertificateAddToKeychain error: %ld\n", (long)status
); }
1148 static void saveTSACertificates(CSSM_DATA
**signingCerts
, CFMutableArrayRef outArray
)
1150 SecKeychainRef defaultKeychain
= NULL
;
1151 // Don't save certificates in keychain to avoid securityd issues
1152 // if (SecKeychainCopyDefault(&defaultKeychain))
1153 // defaultKeychain = NULL;
1155 unsigned certCount
= SecCmsArrayCount((void **)signingCerts
);
1157 for (dex
=0; dex
<certCount
; dex
++)
1159 OSStatus rx
= impExpImportCertUnCommon(signingCerts
[dex
], defaultKeychain
, outArray
);
1160 if (rx
!=noErr
&& rx
!=errSecDuplicateItem
)
1161 dtprintf("impExpImportCertCommon failed: %ld\n", (long)rx
);
1163 if (defaultKeychain
)
1164 CFRelease(defaultKeychain
);
1167 static const char *cfabsoluteTimeToString(CFAbsoluteTime abstime
)
1169 CFGregorianDate greg
= CFAbsoluteTimeGetGregorianDate(abstime
, NULL
);
1171 if (19 != snprintf(str
, 20, "%4.4d-%2.2d-%2.2d_%2.2d:%2.2d:%2.2d",
1172 (int)greg
.year
, greg
.month
, greg
.day
, greg
.hour
, greg
.minute
, (int)greg
.second
))
1174 char *data
= (char *)malloc(20);
1175 strncpy(data
, str
, 20);
1179 static OSStatus
setTSALeafValidityDates(SecCmsSignerInfoRef signerinfo
)
1181 SecCertificateRef tsaLeaf
= SecCmsSignerInfoGetSigningCertificate(signerinfo
, NULL
);
1184 return SecCmsVSSigningCertNotFound
;
1186 signerinfo
->tsaLeafNotBefore
= SecCertificateNotValidBefore(tsaLeaf
); /* Start date for Timestamp Authority leaf */
1187 signerinfo
->tsaLeafNotAfter
= SecCertificateNotValidAfter(tsaLeaf
); /* Expiration date for Timestamp Authority leaf */
1189 const char *nbefore
= cfabsoluteTimeToString(signerinfo
->tsaLeafNotBefore
);
1190 const char *nafter
= cfabsoluteTimeToString(signerinfo
->tsaLeafNotAfter
);
1191 if (nbefore
&& nafter
)
1193 dtprintf("Timestamp Authority leaf valid from %s to %s\n", nbefore
, nafter
);
1194 free((void *)nbefore
);free((void *)nafter
);
1197 return errSecSuccess
;
1201 From RFC 3161: Time-Stamp Protocol (TSP),August 2001, APPENDIX B:
1203 B) The validity of the digital signature may then be verified in the
1206 1) The time-stamp token itself MUST be verified and it MUST be
1207 verified that it applies to the signature of the signer.
1209 2) The date/time indicated by the TSA in the TimeStampToken
1212 3) The certificate used by the signer MUST be identified and
1215 4) The date/time indicated by the TSA MUST be within the
1216 validity period of the signer's certificate.
1218 5) The revocation information about that certificate, at the
1219 date/time of the Time-Stamping operation, MUST be retrieved.
1221 6) Should the certificate be revoked, then the date/time of
1222 revocation shall be later than the date/time indicated by
1225 If all these conditions are successful, then the digital signature
1226 shall be declared as valid.
1230 OSStatus
decodeTimeStampToken(SecCmsSignerInfoRef signerinfo
, CSSM_DATA_PTR inData
, CSSM_DATA_PTR encDigest
, uint64_t expectedNonce
)
1232 return decodeTimeStampTokenWithPolicy(signerinfo
, NULL
, inData
, encDigest
, expectedNonce
);
1235 OSStatus
decodeTimeStampTokenWithPolicy(SecCmsSignerInfoRef signerinfo
, CFTypeRef timeStampPolicy
, CSSM_DATA_PTR inData
, CSSM_DATA_PTR encDigest
, uint64_t expectedNonce
)
1238 We update signerinfo with timestamp and tsa certificate chain.
1239 encDigest is the original signed blob, which we must hash and compare.
1240 inData comes from the unAuthAttr section of the CMS message
1242 These are set in signerinfo as side effects:
1248 SecCmsDecoderRef decoderContext
= NULL
;
1249 SecCmsMessageRef cmsMessage
= NULL
;
1250 SecCmsContentInfoRef contentInfo
;
1251 SecCmsSignedDataRef signedData
;
1252 SECOidTag contentTypeTag
;
1253 int contentLevelCount
;
1255 OSStatus result
= errSecUnknownFormat
;
1256 CSSM_DATA
**signingCerts
= NULL
;
1258 dtprintf("decodeTimeStampToken top: PORT_GetError() %d -----\n", PORT_GetError());
1261 /* decode the message */
1262 require_noerr(result
= SecCmsDecoderCreate (NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &decoderContext
), xit
);
1263 result
= SecCmsDecoderUpdate(decoderContext
, inData
->Data
, inData
->Length
);
1266 result
= errSecTimestampInvalid
;
1267 SecCmsDecoderDestroy(decoderContext
);
1271 require_noerr(result
= SecCmsDecoderFinish(decoderContext
, &cmsMessage
), xit
);
1273 // process the results
1274 contentLevelCount
= SecCmsMessageContentLevelCount(cmsMessage
);
1277 printDataAsHex("encDigest",encDigest
, 0);
1279 for (ix
= 0; ix
< contentLevelCount
; ++ix
)
1281 dtprintf("\n----- Content Level %d -----\n", ix
);
1282 // get content information
1283 contentInfo
= SecCmsMessageContentLevel (cmsMessage
, ix
);
1284 contentTypeTag
= SecCmsContentInfoGetContentTypeTag (contentInfo
);
1286 // After 2nd round, contentInfo.content.data is the TSTInfo
1288 debugShowContentTypeOID(contentInfo
);
1290 switch (contentTypeTag
)
1292 case SEC_OID_PKCS7_SIGNED_DATA
:
1294 require((signedData
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(contentInfo
)) != NULL
, xit
);
1296 debugShowSignerInfo(signedData
);
1298 SECAlgorithmID
**digestAlgorithms
= SecCmsSignedDataGetDigestAlgs(signedData
);
1299 unsigned digestAlgCount
= SecCmsArrayCount((void **)digestAlgorithms
);
1300 dtprintf("digestAlgCount: %d\n", digestAlgCount
);
1301 if (signedData
->digests
)
1305 for (jx
=0;jx
< digestAlgCount
;jx
++)
1307 sprintf(buffer
, " digest[%u]", jx
);
1308 printDataAsHex(buffer
,signedData
->digests
[jx
], 0);
1313 dtprintf("No digests\n");
1314 CSSM_DATA_PTR innerContent
= SecCmsContentInfoGetInnerContent(contentInfo
);
1317 dtprintf("inner content length: %ld\n", innerContent
->Length
);
1318 SecAsn1TSAMessageImprint fakeMessageImprint
= {{{0}},};
1319 OSStatus status
= createTSAMessageImprint(signedData
, innerContent
, &fakeMessageImprint
);
1320 require_noerr_action(status
, xit
, dtprintf("createTSAMessageImprint status: %d\n", (int)status
); result
= status
);
1321 printDataAsHex("inner content hash",&fakeMessageImprint
.hashedMessage
, 0);
1322 CSSM_DATA_PTR digestdata
= &fakeMessageImprint
.hashedMessage
;
1323 CSSM_DATA_PTR digests
[2] = {digestdata
, NULL
};
1324 status
= SecCmsSignedDataSetDigests(signedData
, digestAlgorithms
, (CSSM_DATA_PTR
*)&digests
);
1325 require_noerr_action(status
, xit
, dtprintf("createTSAMessageImprint status: %d\n", (int)status
); result
= status
);
1328 dtprintf("no inner content\n");
1332 Import the certificates. We leave this as a warning, since
1333 there are configurations where the certificates are not returned.
1335 signingCerts
= SecCmsSignedDataGetCertificateList(signedData
);
1336 if (signingCerts
== NULL
)
1337 { dtprintf("SecCmsSignedDataGetCertificateList returned NULL\n"); }
1340 if (!signerinfo
->timestampCertList
)
1341 signerinfo
->timestampCertList
= CFArrayCreateMutable(kCFAllocatorDefault
, 10, &kCFTypeArrayCallBacks
);
1342 saveTSACertificates(signingCerts
, signerinfo
->timestampCertList
);
1343 require_noerr(result
= setTSALeafValidityDates(signerinfo
), xit
);
1344 debugSaveCertificates(signingCerts
);
1347 int numberOfSigners
= SecCmsSignedDataSignerInfoCount (signedData
);
1349 if (numberOfSigners
> 0) {
1350 /* @@@ assume there's only one signer since SecCms can't handle multiple signers anyway */
1351 signerinfo
->timestampCert
= CFRetainSafe(SecCmsSignerInfoGetSigningCertificate(signedData
->signerInfos
[0], NULL
));
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 SecCertificateRef signerCert
= SecCmsSignerInfoGetTimestampSigningCert(signerinfo
);
1374 result
= verifyTSTInfo(contentInfo
->rawContent
, signerCert
, &tstInfo
, &signerinfo
->timestampTime
, expectedNonce
);
1375 if (signerinfo
->timestampTime
)
1377 const char *tstamp
= cfabsoluteTimeToString(signerinfo
->timestampTime
);
1380 dtprintf("Timestamp Authority timestamp: %s\n", tstamp
);
1381 free((void *)tstamp
);
1388 dtprintf("otherContent : %p\n", (char *)SecCmsContentInfoGetContent (contentInfo
));
1392 dtprintf("ContentTypeTag : %x\n", contentTypeTag
);
1398 SecCmsMessageDestroy(cmsMessage
);