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
);