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>
51 #include <utilities/debugging.h>
53 #include "tsaSupport.h"
54 #include "tsaSupportPriv.h"
55 #include "tsaTemplates.h"
63 const CFStringRef kTSAContextKeyURL
= CFSTR("ServerURL");
64 const CFStringRef kTSAContextKeyNoCerts
= CFSTR("NoCerts");
65 const CFStringRef kTSADebugContextKeyBadReq
= CFSTR("DebugBadReq");
66 const CFStringRef kTSADebugContextKeyBadNonce
= CFSTR("DebugBadNonce");
68 extern const SecAsn1Template kSecAsn1TSATSTInfoTemplate
[];
70 extern OSStatus
impExpImportCertCommon(
71 const CSSM_DATA
*cdata
,
72 SecKeychainRef importKeychain
, // optional
73 CFMutableArrayRef outArray
); // optional, append here
75 #pragma mark ----- Debug Logs -----
78 #define TSA_USE_SYSLOG 1
85 #define tsaDebug(fmt, ...) \
88 struct timeval time_now; \
89 gettimeofday(&time_now, NULL); \
90 struct tm* time_info = localtime(&time_now.tv_sec); \
91 strftime(buf, sizeof(buf), "[%Y-%m-%d %H:%M:%S]", time_info); \
92 fprintf(stderr, "%s " fmt, buf, ## __VA_ARGS__); \
93 syslog(LOG_ERR, " " fmt, ## __VA_ARGS__); \
95 #define tsa_secinfo(scope, format...) \
97 syslog(LOG_NOTICE, format); \
98 secinfo(scope, format); \
102 #define tsaDebug(args...) tsa_secinfo("tsa", ## args)
103 #define tsa_secinfo(scope, format...) \
104 secinfo(scope, format)
108 #define TSTINFO_DEBUG 1 //jch
112 #define dtprintf(args...) tsaDebug(args)
114 #define dtprintf(args...)
117 #define kHTTPResponseCodeContinue 100
118 #define kHTTPResponseCodeOK 200
119 #define kHTTPResponseCodeNoContent 204
120 #define kHTTPResponseCodeBadRequest 400
121 #define kHTTPResponseCodeUnauthorized 401
122 #define kHTTPResponseCodeForbidden 403
123 #define kHTTPResponseCodeNotFound 404
124 #define kHTTPResponseCodeConflict 409
125 #define kHTTPResponseCodeExpectationFailed 417
126 #define kHTTPResponseCodeServFail 500
127 #define kHTTPResponseCodeServiceUnavailable 503
128 #define kHTTPResponseCodeInsufficientStorage 507
130 #pragma mark ----- Debug/Utilities -----
132 static OSStatus
remapHTTPErrorCodes(OSStatus status
)
136 case kHTTPResponseCodeOK
:
137 case kHTTPResponseCodeContinue
:
139 case kHTTPResponseCodeBadRequest
:
140 return errSecTimestampBadRequest
;
141 case kHTTPResponseCodeNoContent
:
142 case kHTTPResponseCodeUnauthorized
:
143 case kHTTPResponseCodeForbidden
:
144 case kHTTPResponseCodeNotFound
:
145 case kHTTPResponseCodeConflict
:
146 case kHTTPResponseCodeExpectationFailed
:
147 case kHTTPResponseCodeServFail
:
148 case kHTTPResponseCodeInsufficientStorage
:
149 case kHTTPResponseCodeServiceUnavailable
:
150 return errSecTimestampServiceNotAvailable
;
158 static void printDataAsHex(const char *title
, const CSSM_DATA
*d
, unsigned maxToPrint
) // 0 means print it all
163 uint32 len
= (uint32
)d
->Length
;
168 const int wrapwid
= 24; // large enough so SHA-1 hashes fit on one line...
170 if ((maxToPrint
!= 0) && (len
> maxToPrint
)) {
175 bufferSize
= wrapwid
+3*len
;
176 buffer
= (char *)malloc(bufferSize
);
178 offset
= sprintf(buffer
, "%s [len = %u]\n", title
, len
);
179 dtprintf("%s", buffer
);
182 for (i
=0; (i
< len
) && (offset
+3 < bufferSize
); i
++, offset
+= sz
) {
183 sz
= sprintf(buffer
+ offset
, " %02x", (unsigned int)cp
[i
] & 0xff);
184 if ((i
% wrapwid
) == (wrapwid
-1)) {
185 dtprintf("%s\n", buffer
);
191 sz
=sprintf(buffer
+ offset
, more
?" ...\n":"\n");
195 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);
212 rtn
= (int)write(fd
, bytes
, numBytes
);
213 if(rtn
!= (int)numBytes
)
216 fprintf(stderr
, "writeFile: short write\n");
227 char *cfStringToChar(CFStringRef inStr
)
231 const char *str
= NULL
;
234 return strdup(""); // return a null string
237 if ((str
= CFStringGetCStringPtr(inStr
, kCFStringEncodingUTF8
))) {
238 result
= strdup(str
);
240 // need to extract into buffer
241 CFIndex length
= CFStringGetLength(inStr
); // in 16-bit character units
242 CFIndex bytesToAllocate
= CFStringGetMaximumSizeForEncoding(length
, kCFStringEncodingUTF8
) + 1;
243 result
= malloc(bytesToAllocate
);
244 if (!CFStringGetCString(inStr
, result
, bytesToAllocate
, kCFStringEncodingUTF8
))
251 /* Oids longer than this are considered invalid. */
252 #define MAX_OID_SIZE 32
255 /* FIXME: There are other versions of this in SecCertifcate.c and SecCertificateP.c */
256 static CFStringRef
SecDERItemCopyOIDDecimalRepresentation(CFAllocatorRef allocator
, const CSSM_OID
*oid
)
258 if (oid
->Length
== 0)
259 return CFSTR("<NULL>");
261 if (oid
->Length
> MAX_OID_SIZE
)
262 return CFSTR("Oid too long");
264 CFMutableStringRef result
= CFStringCreateMutable(allocator
, 0);
266 // The first two levels are encoded into one byte, since the root levelq
267 // has only 3 nodes (40*x + y). However if x = joint-iso-itu-t(2) then
268 // y may be > 39, so we have to add special-case handling for this.
269 uint32_t x
= oid
->Data
[0] / 40;
270 uint32_t y
= oid
->Data
[0] % 40;
273 // Handle special case for large y if x = 2
277 CFStringAppendFormat(result
, NULL
, CFSTR("%u.%u"), x
, y
);
280 for (x
= 1; x
< oid
->Length
; ++x
)
282 value
= (value
<< 7) | (oid
->Data
[x
] & 0x7F);
283 /* @@@ value may not span more than 4 bytes. */
284 /* A max number of 20 values is allowed. */
285 if (!(oid
->Data
[x
] & 0x80))
287 CFStringAppendFormat(result
, NULL
, CFSTR(".%lu"), (unsigned long)value
);
295 static void debugSaveCertificates(CSSM_DATA
**outCerts
)
300 CSSM_DATA_PTR
*certp
;
302 const char *certNameBase
= "/tmp/tsa-resp-cert-";
303 char fname
[PATH_MAX
];
304 unsigned certCount
= SecCmsArrayCount((void **)outCerts
);
305 dtprintf("Found %d certs\n",certCount
);
307 for (certp
=outCerts
;*certp
;certp
++, ++jx
)
310 strncpy(fname
, certNameBase
, strlen(certNameBase
)+1);
311 sprintf(numstr
,"%u", jx
);
312 strcat(fname
,numstr
);
313 tsaWriteFileX(fname
, (*certp
)->Data
, (*certp
)->Length
);
315 break; //something wrong
321 static void debugShowSignerInfo(SecCmsSignedDataRef signedData
)
324 int numberOfSigners
= SecCmsSignedDataSignerInfoCount (signedData
);
325 dtprintf("numberOfSigners : %d\n", numberOfSigners
);
327 for (ix
=0;ix
< numberOfSigners
;ix
++)
329 SecCmsSignerInfoRef sigi
= SecCmsSignedDataGetSignerInfo(signedData
,ix
);
332 CFStringRef commonName
= SecCmsSignerInfoGetSignerCommonName(sigi
);
333 const char *signerhdr
= " signer : ";
336 char *cn
= cfStringToChar(commonName
);
337 dtprintf("%s%s\n", signerhdr
, cn
);
340 CFReleaseNull(commonName
);
343 dtprintf("%s<NULL>\n", signerhdr
);
349 static void debugShowContentTypeOID(SecCmsContentInfoRef contentInfo
)
353 CSSM_OID
*typeOID
= SecCmsContentInfoGetContentTypeOID(contentInfo
);
356 CFStringRef oidCFStr
= SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault
, typeOID
);
357 char *oidstr
= cfStringToChar(oidCFStr
);
358 printDataAsHex("oid:", typeOID
, (unsigned int)typeOID
->Length
);
359 dtprintf("\toid: %s\n", oidstr
);
368 uint64_t tsaDER_ToInt(const CSSM_DATA
*DER_Data
)
373 while(i
< DER_Data
->Length
) {
374 rtn
|= DER_Data
->Data
[i
];
375 if(++i
== DER_Data
->Length
) {
383 void displayTSTInfo(SecAsn1TSATSTInfo
*tstInfo
)
386 dtprintf("--- TSTInfo ---\n");
390 if (tstInfo
->version
.Data
)
392 uint64_t vers
= tsaDER_ToInt(&tstInfo
->version
);
393 dtprintf("Version:\t\t%u\n", (int)vers
);
396 if (tstInfo
->serialNumber
.Data
)
398 uint64_t sn
= tsaDER_ToInt(&tstInfo
->serialNumber
);
399 dtprintf("SerialNumber:\t%llu\n", sn
);
402 if (tstInfo
->ordering
.Data
)
404 uint64_t ord
= tsaDER_ToInt(&tstInfo
->ordering
);
405 dtprintf("Ordering:\t\t%s\n", ord
?"yes":"no");
408 if (tstInfo
->nonce
.Data
)
410 uint64_t nonce
= tsaDER_ToInt(&tstInfo
->nonce
);
411 dtprintf("Nonce:\t\t%llu\n", nonce
);
414 dtprintf("Nonce:\t\tnot specified\n");
416 if (tstInfo
->genTime
.Data
)
418 char buf
[tstInfo
->genTime
.Length
+1];
419 memcpy(buf
, (const char *)tstInfo
->genTime
.Data
, tstInfo
->genTime
.Length
);
420 buf
[tstInfo
->genTime
.Length
]=0;
421 dtprintf("GenTime:\t\t%s\n", buf
);
424 dtprintf("-- MessageImprint --\n");
425 if (true) // SecAsn1TSAMessageImprint
427 printDataAsHex(" Algorithm:",&tstInfo
->messageImprint
.hashAlgorithm
.algorithm
, 0);
428 printDataAsHex(" Message :", &tstInfo
->messageImprint
.hashedMessage
, 0);//tstInfo->messageImprint.hashedMessage.Length);
433 #pragma mark ----- TimeStamp Response using XPC -----
435 #include <xpc/private.h>
437 static OSStatus
checkForNonDERResponse(const unsigned char *resp
, size_t respLen
)
440 Good start is something like 30 82 0c 03 30 15 02 01 00 30 10 0c 0e 4f 70 65
442 URL: http://timestamp-int.corp.apple.com/signserver/process?TimeStampSigner
443 Resp: Http/1.1 Service Unavailable
445 URL: http://timestamp-int.corp.apple.com/ts01
448 URL: http://cutandtaste.com/404 (or other forced 404 site)
452 OSStatus status
= noErr
;
453 const char ader
[2] = { 0x30, 0x82 };
454 char *respStr
= NULL
;
456 size_t badResponseCount
;
458 const char *badResponses
[] =
461 "Http/1.1 Service Unavailable",
465 require_action(resp
&& respLen
, xit
, status
= errSecTimestampServiceNotAvailable
);
467 // This is usual case
468 if ((respLen
> 1) && (memcmp(resp
, ader
, 2)==0)) // might be good; pass on to DER decoder
471 badResponseCount
= sizeof(badResponses
)/sizeof(char *);
473 for (ix
= 0; ix
< badResponseCount
; ++ix
)
474 if (strlen(badResponses
[ix
]) > maxlen
)
475 maxlen
= strlen(badResponses
[ix
]);
477 // Prevent a large response from allocating a ton of memory
478 if (respLen
> maxlen
)
481 respStr
= (char *)malloc(respLen
+1);
482 strlcpy(respStr
, (const char *)resp
, respLen
);
484 for (ix
= 0; ix
< badResponseCount
; ++ix
)
485 if (strcmp(respStr
, badResponses
[ix
])==0)
486 return errSecTimestampServiceNotAvailable
;
490 free((void *)respStr
);
495 static OSStatus
sendTSARequestWithXPC(const unsigned char *tsaReq
, size_t tsaReqLength
, const unsigned char *tsaURL
, unsigned char **tsaResp
, size_t *tsaRespLength
)
497 __block OSStatus result
= noErr
;
498 int timeoutInSeconds
= 15;
499 extern xpc_object_t
xpc_create_with_format(const char * format
, ...);
501 dispatch_queue_t xpc_queue
= dispatch_queue_create("com.apple.security.XPCTimeStampingService", DISPATCH_QUEUE_SERIAL
);
502 __block dispatch_semaphore_t waitSemaphore
= dispatch_semaphore_create(0);
503 dispatch_time_t finishTime
= dispatch_time(DISPATCH_TIME_NOW
, timeoutInSeconds
* NSEC_PER_SEC
);
505 xpc_connection_t con
= xpc_connection_create("com.apple.security.XPCTimeStampingService", xpc_queue
);
507 xpc_connection_set_event_handler(con
, ^(xpc_object_t event
) {
508 xpc_type_t xtype
= xpc_get_type(event
);
509 if (XPC_TYPE_ERROR
== xtype
)
510 { tsaDebug("default: connection error: %s\n", xpc_dictionary_get_string(event
, XPC_ERROR_KEY_DESCRIPTION
)); }
512 { tsaDebug("default: unexpected connection event %p\n", event
); }
515 xpc_connection_resume(con
);
517 xpc_object_t tsaReqData
= xpc_data_create(tsaReq
, tsaReqLength
);
518 const char *urlstr
= (tsaURL
?(const char *)tsaURL
:"");
519 xpc_object_t url_as_xpc_string
= xpc_string_create(urlstr
);
521 xpc_object_t message
= xpc_create_with_format("{operation: TimeStampRequest, ServerURL: %value, TimeStampRequest: %value}", url_as_xpc_string
, tsaReqData
);
523 xpc_connection_send_message_with_reply(con
, message
, xpc_queue
, ^(xpc_object_t reply
)
525 tsaDebug("xpc_connection_send_message_with_reply handler called back\n");
526 dispatch_retain_safe(waitSemaphore
);
528 xpc_type_t xtype
= xpc_get_type(reply
);
529 if (XPC_TYPE_ERROR
== xtype
)
530 { tsaDebug("message error: %s\n", xpc_dictionary_get_string(reply
, XPC_ERROR_KEY_DESCRIPTION
)); }
531 else if (XPC_TYPE_CONNECTION
== xtype
)
532 { tsaDebug("received connection\n"); }
533 else if (XPC_TYPE_DICTIONARY
== xtype
)
537 // This is useful for debugging.
538 char *debug = xpc_copy_description(reply);
539 tsaDebug("DEBUG %s\n", debug);
544 xpc_object_t xpcTimeStampReply
= xpc_dictionary_get_value(reply
, "TimeStampReply");
545 size_t xpcTSRLength
= xpc_data_get_length(xpcTimeStampReply
);
546 tsaDebug("xpcTSRLength: %ld bytes of response\n", xpcTSRLength
);
548 xpc_object_t xpcTimeStampError
= xpc_dictionary_get_value(reply
, "TimeStampError");
549 xpc_object_t xpcTimeStampStatus
= xpc_dictionary_get_value(reply
, "TimeStampStatus");
551 if (xpcTimeStampError
|| xpcTimeStampStatus
)
554 if (xpcTimeStampError
)
556 size_t len
= xpc_string_get_length(xpcTimeStampError
);
557 char *buf
= (char *)malloc(len
);
558 strlcpy(buf
, xpc_string_get_string_ptr(xpcTimeStampError
), len
+1);
559 tsaDebug("xpcTimeStampError: %s\n", buf
);
564 if (xpcTimeStampStatus
)
566 result
= (OSStatus
)xpc_int64_get_value(xpcTimeStampStatus
);
567 tsaDebug("xpcTimeStampStatus: %d\n", (int)result
);
571 result
= remapHTTPErrorCodes(result
);
573 if ((result
== noErr
) && tsaResp
&& tsaRespLength
)
575 *tsaRespLength
= xpcTSRLength
;
576 *tsaResp
= (unsigned char *)malloc(xpcTSRLength
);
578 size_t bytesCopied
= xpc_data_get_bytes(xpcTimeStampReply
, *tsaResp
, 0, xpcTSRLength
);
579 if (bytesCopied
!= xpcTSRLength
)
580 { tsaDebug("length mismatch: copied: %ld, xpc: %ld\n", bytesCopied
, xpcTSRLength
); }
582 if ((result
= checkForNonDERResponse(*tsaResp
,bytesCopied
)))
584 tsaDebug("received non-DER response from timestamp server\n");
589 tsaDebug("copied: %ld bytes of response\n", bytesCopied
);
592 tsaDebug("releasing connection\n");
596 { tsaDebug("unexpected message reply type %p\n", xtype
); }
597 if (waitSemaphore
) { dispatch_semaphore_signal(waitSemaphore
); }
598 dispatch_release_null(waitSemaphore
);
600 { tsaDebug("waiting up to %d seconds for response from XPC\n", timeoutInSeconds
); }
601 if (waitSemaphore
) { dispatch_semaphore_wait(waitSemaphore
, finishTime
); }
603 dispatch_release_null(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 CFRetain(secFWbundle
);
642 require_action(resourceURL
= CFBundleCopyResourceURL(secFWbundle
, CFSTR("TimeStampingPrefs"), CFSTR("plist"), NULL
),
643 xit
, status
= errSecInvalidPrefsDomain
);
645 require(CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault
, resourceURL
, &resourceData
,
646 NULL
, NULL
, &errorCode
), xit
);
647 require_action(resourceData
, xit
, status
= errSecDataNotAvailable
);
649 prefs
= CFPropertyListCreateWithData(kCFAllocatorDefault
, resourceData
, options
, &format
, error
);
650 require_action(prefs
&& (CFGetTypeID(prefs
)==CFDictionaryGetTypeID()), xit
, status
= errSecInvalidPrefsDomain
);
652 contextDict
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, prefs
);
660 *error
= CFErrorCreate(kCFAllocatorDefault
, kCFErrorDomainOSStatus
, status
, NULL
);
662 CFRelease(secFWbundle
);
664 CFRelease(resourceURL
);
666 CFRelease(resourceData
);
673 static CFDataRef
_SecTSARequestCopyDEREncoding(SecAsn1TSAMessageImprint
*messageImprint
, bool noCerts
, uint64_t nonce
)
675 // Returns DER encoded TimeStampReq
676 // Modeled on _SecOCSPRequestCopyDEREncoding
677 // The Timestamp Authority supports 64 bit nonces (or more possibly)
679 SecAsn1CoderRef coder
= NULL
;
681 SecAsn1Item vers
= {1, &version
};
682 uint8_t creq
= noCerts
?0:1;
683 SecAsn1Item certReq
= {1, &creq
}; //jch - to request or not?
684 SecAsn1TSATimeStampReq tsreq
= {};
685 CFDataRef der
= NULL
;
686 uint64_t nonceVal
= OSSwapHostToBigConstInt64(nonce
);
687 SecAsn1Item nonceItem
= {sizeof(uint64_t), (unsigned char *)&nonceVal
};
689 uint8_t OID_FakePolicy_Data
[] = { 0x2A, 0x03, 0x04, 0x05, 0x06};
690 const CSSM_OID fakePolicyOID
= {sizeof(OID_FakePolicy_Data
),OID_FakePolicy_Data
};
692 tsreq
.version
= vers
;
694 tsreq
.messageImprint
= *messageImprint
;
695 tsreq
.certReq
= certReq
;
697 // skip reqPolicy, extensions for now - FAKES - jch
698 tsreq
.reqPolicy
= fakePolicyOID
; //policyID;
700 tsreq
.nonce
= nonceItem
;
702 // Encode the request
703 require_noerr(SecAsn1CoderCreate(&coder
), errOut
);
706 require_noerr(SecAsn1EncodeItem(coder
, &tsreq
,
707 &kSecAsn1TSATimeStampReqTemplate
, &encoded
), errOut
);
708 der
= CFDataCreate(kCFAllocatorDefault
, encoded
.Data
,
713 SecAsn1CoderRelease(coder
);
718 OSStatus
SecTSAResponseCopyDEREncoding(SecAsn1CoderRef coder
, const CSSM_DATA
*tsaResponse
, SecAsn1TimeStampRespDER
*respDER
)
720 // Partially decode the response
721 OSStatus status
= paramErr
;
723 require(tsaResponse
&& respDER
, errOut
);
724 require_noerr(SecAsn1DecodeData(coder
, tsaResponse
,
725 &kSecAsn1TSATimeStampRespTemplateDER
, respDER
), errOut
);
733 #pragma mark ----- TS Callback -----
735 OSStatus
SecCmsTSADefaultCallback(CFTypeRef context
, void *messageImprintV
, uint64_t nonce
, CSSM_DATA
*signedDERBlob
)
737 OSStatus result
= paramErr
;
738 const unsigned char *tsaReq
= NULL
;
739 size_t tsaReqLength
= 0;
740 CFDataRef cfreq
= NULL
;
741 unsigned char *tsaURL
= NULL
;
742 bool noCerts
= false;
744 if (!context
|| CFGetTypeID(context
)!=CFDictionaryGetTypeID())
747 SecAsn1TSAMessageImprint
*messageImprint
= (SecAsn1TSAMessageImprint
*)messageImprintV
;
748 if (!messageImprint
|| !signedDERBlob
)
751 CFBooleanRef cfnocerts
= (CFBooleanRef
)CFDictionaryGetValue((CFDictionaryRef
)context
, kTSAContextKeyNoCerts
);
754 tsaDebug("[TSA] Request noCerts\n");
755 noCerts
= CFBooleanGetValue(cfnocerts
);
758 // We must spoof the nonce here, before sending the request.
759 // If we tried to alter the reply, then the signature would break instead.
760 CFBooleanRef cfBadNonce
= (CFBooleanRef
)CFDictionaryGetValue((CFDictionaryRef
)context
, kTSADebugContextKeyBadNonce
);
761 if (cfBadNonce
&& CFBooleanGetValue(cfBadNonce
))
763 tsaDebug("[TSA] Forcing bad TS Request by changing nonce\n");
767 printDataAsHex("[TSA] hashToTimeStamp:", &messageImprint
->hashedMessage
,128);
768 cfreq
= _SecTSARequestCopyDEREncoding(messageImprint
, noCerts
, nonce
);
771 tsaReq
= CFDataGetBytePtr(cfreq
);
772 tsaReqLength
= CFDataGetLength(cfreq
);
776 tsaWriteFileX("/tmp/tsareq.req", tsaReq
, tsaReqLength
);
780 CFTypeRef url
= CFDictionaryGetValue((CFDictionaryRef
)context
, kTSAContextKeyURL
);
783 tsaDebug("[TSA] missing URL for TSA (key: %s)\n", "kTSAContextKeyURL");
787 CFStringRef urlStr
= NULL
;
788 if (CFURLGetTypeID() == CFGetTypeID(url
)) {
789 urlStr
= CFURLGetString(url
);
791 require_quiet(CFStringGetTypeID() == CFGetTypeID(url
), xit
);
794 require_quiet(urlStr
, xit
);
797 If debugging, look at special values in the context to mess things up
800 CFBooleanRef cfBadReq
= (CFBooleanRef
)CFDictionaryGetValue((CFDictionaryRef
)context
, kTSADebugContextKeyBadReq
);
801 if (cfBadReq
&& CFBooleanGetValue(cfBadReq
))
803 tsaDebug("[TSA] Forcing bad TS Request by truncating length from %ld to %ld\n", tsaReqLength
, (tsaReqLength
-4));
807 // need to extract into buffer
808 CFIndex length
= CFStringGetLength(urlStr
); // in 16-bit character units
809 tsaURL
= malloc(6 * length
+ 1); // pessimistic
810 if (!CFStringGetCString(urlStr
, (char *)tsaURL
, 6 * length
+ 1, kCFStringEncodingUTF8
))
813 tsaDebug("[TSA] URL for timestamp server: %s\n", tsaURL
);
815 unsigned char *tsaResp
= NULL
;
816 size_t tsaRespLength
= 0;
817 tsaDebug("calling sendTSARequestWithXPC with %ld bytes of request\n", tsaReqLength
);
819 require_noerr(result
= sendTSARequestWithXPC(tsaReq
, tsaReqLength
, tsaURL
, &tsaResp
, &tsaRespLength
), xit
);
821 tsaDebug("sendTSARequestWithXPC copied: %ld bytes of response\n", tsaRespLength
);
823 signedDERBlob
->Data
= tsaResp
;
824 signedDERBlob
->Length
= tsaRespLength
;
830 free((void *)tsaURL
);
837 #pragma mark ----- TimeStamp Verification -----
839 static OSStatus
convertGeneralizedTimeToCFAbsoluteTime(const char *timeStr
, CFAbsoluteTime
*ptime
)
842 See http://userguide.icu-project.org/formatparse/datetime for date/time format.
843 The "Z" signal a GMT time, but CFDateFormatterGetAbsoluteTimeFromString returns
844 values based on local time.
847 OSStatus result
= noErr
;
848 CFDateFormatterRef formatter
= NULL
;
849 CFStringRef time_string
= NULL
;
850 CFTimeZoneRef gmt
= NULL
;
851 CFLocaleRef locale
= NULL
;
852 CFRange
*rangep
= NULL
;
854 require(timeStr
&& timeStr
[0] && ptime
, xit
);
855 require(formatter
= CFDateFormatterCreate(kCFAllocatorDefault
, locale
, kCFDateFormatterNoStyle
, kCFDateFormatterNoStyle
), xit
);
856 // CFRetain(formatter);
857 CFDateFormatterSetFormat(formatter
, CFSTR("yyyyMMddHHmmss'Z'")); // GeneralizedTime
858 gmt
= CFTimeZoneCreateWithTimeIntervalFromGMT(NULL
, 0);
859 CFDateFormatterSetProperty(formatter
, kCFDateFormatterTimeZone
, gmt
);
861 time_string
= CFStringCreateWithCString(kCFAllocatorDefault
, timeStr
, kCFStringEncodingUTF8
);
862 if (!time_string
|| !CFDateFormatterGetAbsoluteTimeFromString(formatter
, time_string
, rangep
, ptime
))
864 dtprintf("%s is not a valid date\n", timeStr
);
870 CFRelease(formatter
);
872 CFRelease(time_string
);
879 static OSStatus
SecTSAValidateTimestamp(const SecAsn1TSATSTInfo
*tstInfo
, SecCertificateRef signerCert
, CFAbsoluteTime
*timestampTime
)
881 // See <rdar://problem/11077708> Properly handle revocation information of timestamping certificate
882 OSStatus result
= paramErr
;
883 CFAbsoluteTime genTime
= 0;
884 char timeStr
[32] = {0,};
886 require(tstInfo
&& signerCert
&& (tstInfo
->genTime
.Length
< 16), xit
);;
888 memcpy(timeStr
, tstInfo
->genTime
.Data
, tstInfo
->genTime
.Length
);
889 timeStr
[tstInfo
->genTime
.Length
] = 0;
890 require_noerr(convertGeneralizedTimeToCFAbsoluteTime(timeStr
, &genTime
), xit
);
891 if (SecCertificateIsValidX(signerCert
, genTime
)) // iOS?
894 result
= errSecTimestampInvalid
;
896 *timestampTime
= genTime
;
901 static OSStatus
verifyTSTInfo(const CSSM_DATA_PTR content
, SecCmsSignerInfoRef signerinfo
, SecAsn1TSATSTInfo
*tstInfo
, CFAbsoluteTime
*timestampTime
, uint64_t expectedNonce
, CSSM_DATA_PTR encDigest
)
903 OSStatus status
= paramErr
;
904 SecAsn1CoderRef coder
= NULL
;
909 SecCertificateRef signerCert
= SecCmsSignerInfoGetTimestampSigningCert(signerinfo
);
910 SecAsn1TSAMessageImprint expectedMessageImprint
;
912 require_noerr(SecAsn1CoderCreate(&coder
), xit
);
913 require_noerr(SecAsn1Decode(coder
, content
->Data
, content
->Length
,
914 kSecAsn1TSATSTInfoTemplate
, tstInfo
), xit
);
915 displayTSTInfo(tstInfo
);
918 if (tstInfo
->nonce
.Data
&& expectedNonce
!=0)
920 uint64_t nonce
= tsaDER_ToInt(&tstInfo
->nonce
);
921 // if (expectedNonce!=nonce)
922 dtprintf("verifyTSTInfo nonce: actual: %lld, expected: %lld\n", nonce
, expectedNonce
);
923 require_action(expectedNonce
==nonce
, xit
, status
= errSecTimestampRejection
);
926 // Check the times in the timestamp
927 require_noerr(status
= SecTSAValidateTimestamp(tstInfo
, signerCert
, timestampTime
), xit
);
928 dtprintf("SecTSAValidateTimestamp result: %ld\n", (long)status
);
930 // Check the message imprint against the encDigest from the signerInfo containing this timestamp
931 SECOidTag hashAlg
= SECOID_GetAlgorithmTag(&tstInfo
->messageImprint
.hashAlgorithm
);
932 require_action(hashAlg
== SEC_OID_SHA256
|| hashAlg
== SEC_OID_SHA1
, xit
, status
= errSecInvalidDigestAlgorithm
);
933 require_noerr(status
= createTSAMessageImprint(signerinfo
, &tstInfo
->messageImprint
.hashAlgorithm
,
934 encDigest
, &expectedMessageImprint
), xit
);
935 require_action(CERT_CompareCssmData(&expectedMessageImprint
.hashedMessage
, &tstInfo
->messageImprint
.hashedMessage
), xit
,
936 status
= errSecTimestampInvalid
; secerror("Timestamp MessageImprint did not match the signature's hash"));
940 SecAsn1CoderRelease(coder
);
944 static void debugShowExtendedTrustResult(int index
, CFDictionaryRef extendedResult
)
949 CFStringRef xresStr
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
,
950 CFSTR("Extended trust result for signer #%d : %@"), index
, extendedResult
);
961 extern const char *cssmErrorString(CSSM_RETURN error
);
963 static void statusBitTest(CSSM_TP_APPLE_CERT_STATUS certStatus
, uint32 bit
, const char *str
)
965 if (certStatus
& bit
)
966 dtprintf("%s ", str
);
970 static void debugShowCertEvidenceInfo(uint16_t certCount
, const CSSM_TP_APPLE_EVIDENCE_INFO
*info
)
973 CSSM_TP_APPLE_CERT_STATUS cs
;
974 // const CSSM_TP_APPLE_EVIDENCE_INFO *pinfo = info;
976 for (ix
=0; info
&& (ix
<certCount
); ix
++, ++info
)
978 cs
= info
->StatusBits
;
979 dtprintf(" cert %u:\n", ix
);
980 dtprintf(" StatusBits : 0x%x", (unsigned)cs
);
984 statusBitTest(cs
, CSSM_CERT_STATUS_EXPIRED
, "EXPIRED");
985 statusBitTest(cs
, CSSM_CERT_STATUS_NOT_VALID_YET
,
987 statusBitTest(cs
, CSSM_CERT_STATUS_IS_IN_INPUT_CERTS
,
988 "IS_IN_INPUT_CERTS");
989 statusBitTest(cs
, CSSM_CERT_STATUS_IS_IN_ANCHORS
,
991 statusBitTest(cs
, CSSM_CERT_STATUS_IS_ROOT
, "IS_ROOT");
992 statusBitTest(cs
, CSSM_CERT_STATUS_IS_FROM_NET
, "IS_FROM_NET");
998 dtprintf(" NumStatusCodes : %u ", info
->NumStatusCodes
);
999 CSSM_RETURN
*pstatuscode
= info
->StatusCodes
;
1001 for (jx
=0; pstatuscode
&& (jx
<info
->NumStatusCodes
); jx
++, ++pstatuscode
)
1002 dtprintf("%s ", cssmErrorString(*pstatuscode
));
1005 dtprintf(" Index: %u\n", info
->Index
);
1012 static const char *trustResultTypeString(SecTrustResultType trustResultType
)
1014 switch (trustResultType
)
1016 case kSecTrustResultProceed
: return "TrustResultProceed";
1017 case kSecTrustResultUnspecified
: return "TrustResultUnspecified";
1018 case kSecTrustResultDeny
: return "TrustResultDeny"; // user reject
1019 case kSecTrustResultInvalid
: return "TrustResultInvalid";
1020 case kSecTrustResultRecoverableTrustFailure
: return "TrustResultRecoverableTrustFailure";
1021 case kSecTrustResultFatalTrustFailure
: return "TrustResultUnspecified";
1022 case kSecTrustResultOtherError
: return "TrustResultOtherError";
1023 default: return "TrustResultUnknown";
1029 static OSStatus
verifySigners(SecCmsSignedDataRef signedData
, int numberOfSigners
, CFTypeRef timeStampPolicy
)
1031 // See <rdar://problem/11077588> Bubble up SecTrustEvaluate of timestamp response to high level callers
1032 // Also <rdar://problem/11077708> Properly handle revocation information of timestamping certificate
1034 SecTrustRef trustRef
= NULL
;
1035 CFTypeRef policy
= CFRetainSafe(timeStampPolicy
);
1036 int result
=errSecInternalError
;
1040 require(policy
= SecPolicyCreateWithOID(kSecPolicyAppleTimeStamping
), xit
);
1044 for (jx
= 0; jx
< numberOfSigners
; ++jx
)
1046 SecTrustResultType trustResultType
;
1047 CFDictionaryRef extendedResult
= NULL
;
1048 CFArrayRef certChain
= NULL
;
1049 uint16_t certCount
= 0;
1051 CSSM_TP_APPLE_EVIDENCE_INFO
*statusChain
= NULL
;
1053 // SecCmsSignedDataVerifySignerInfo returns trustRef, which we can call SecTrustEvaluate on
1054 // usually (always?) if result is noErr, the SecTrust*Result calls will return errSecTrustNotAvailable
1055 result
= SecCmsSignedDataVerifySignerInfo (signedData
, jx
, NULL
, policy
, &trustRef
);
1056 dtprintf("[%s] SecCmsSignedDataVerifySignerInfo: result: %d, signer: %d\n",
1057 __FUNCTION__
, result
, jx
);
1058 require_noerr(result
, xit
);
1060 result
= SecTrustEvaluate (trustRef
, &trustResultType
);
1061 dtprintf("[%s] SecTrustEvaluate: result: %d, trustResult: %s (%d)\n",
1062 __FUNCTION__
, result
, trustResultTypeString(trustResultType
), trustResultType
);
1065 switch (trustResultType
)
1067 case kSecTrustResultProceed
:
1068 case kSecTrustResultUnspecified
:
1070 case kSecTrustResultDeny
: // user reject
1071 result
= errSecTimestampNotTrusted
; // SecCmsVSTimestampNotTrusted ?
1073 case kSecTrustResultInvalid
:
1074 assert(false); // should never happen
1075 result
= errSecTimestampNotTrusted
; // SecCmsVSTimestampNotTrusted ?
1077 case kSecTrustResultRecoverableTrustFailure
:
1078 case kSecTrustResultFatalTrustFailure
:
1079 case kSecTrustResultOtherError
:
1083 There are two "errors" that need to be resolved externally:
1084 CSSMERR_TP_CERT_EXPIRED can be OK if the timestamp was made
1085 before the TSA chain expired; CSSMERR_TP_CERT_NOT_VALID_YET
1086 can happen in the case where the user's clock was set to 0.
1087 We don't want to prevent them using apps automatically, so
1088 return noErr and let codesign or whover decide.
1090 OSStatus resultCode
;
1091 require_action(SecTrustGetCssmResultCode(trustRef
, &resultCode
)==noErr
, xit
, result
= errSecTimestampNotTrusted
);
1092 result
= (resultCode
== CSSMERR_TP_CERT_EXPIRED
|| resultCode
== CSSMERR_TP_CERT_NOT_VALID_YET
)?noErr
:errSecTimestampNotTrusted
;
1097 rx
= SecTrustGetResult(trustRef
, &trustResultType
, &certChain
, &statusChain
);
1098 dtprintf("[%s] SecTrustGetResult: result: %d, type: %d\n", __FUNCTION__
,rx
, trustResultType
);
1099 certCount
= certChain
?CFArrayGetCount(certChain
):0;
1100 debugShowCertEvidenceInfo(certCount
, statusChain
);
1101 CFReleaseNull(certChain
);
1103 rx
= SecTrustCopyExtendedResult(trustRef
, &extendedResult
);
1104 dtprintf("[%s] SecTrustCopyExtendedResult: result: %d\n", __FUNCTION__
, rx
);
1107 debugShowExtendedTrustResult(jx
, extendedResult
);
1108 CFRelease(extendedResult
);
1112 CFReleaseNull(trustRef
);
1117 CFReleaseNull(trustRef
);
1123 static OSStatus
impExpImportCertUnCommon(
1124 const CSSM_DATA
*cdata
,
1125 SecKeychainRef importKeychain
, // optional
1126 CFMutableArrayRef outArray
) // optional, append here
1128 // The only difference between this and impExpImportCertCommon is that we append to outArray
1129 // before attempting to add to the keychain
1130 OSStatus status
= noErr
;
1131 SecCertificateRef certRef
= NULL
;
1133 require_action(cdata
, xit
, status
= errSecUnsupportedFormat
);
1135 /* Pass kCFAllocatorNull as bytesDeallocator to assure the bytes aren't freed */
1136 CFDataRef data
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, (const UInt8
*)cdata
->Data
, (CFIndex
)cdata
->Length
, kCFAllocatorNull
);
1137 require_action(data
, xit
, status
= errSecUnsupportedFormat
);
1139 certRef
= SecCertificateCreateWithData(kCFAllocatorDefault
, data
);
1140 CFRelease(data
); /* certRef has its own copy of the data now */
1142 dtprintf("impExpHandleCert error\n");
1143 return errSecUnsupportedFormat
;
1147 CFArrayAppendValue(outArray
, certRef
);
1151 status
= SecCertificateAddToKeychain(certRef
, importKeychain
);
1152 if (status
!=noErr
&& status
!=errSecDuplicateItem
)
1153 { dtprintf("SecCertificateAddToKeychain error: %ld\n", (long)status
); }
1162 static void saveTSACertificates(CSSM_DATA
**signingCerts
, CFMutableArrayRef outArray
)
1164 SecKeychainRef defaultKeychain
= NULL
;
1165 // Don't save certificates in keychain to avoid securityd issues
1166 // if (SecKeychainCopyDefault(&defaultKeychain))
1167 // defaultKeychain = NULL;
1169 unsigned certCount
= SecCmsArrayCount((void **)signingCerts
);
1171 for (dex
=0; dex
<certCount
; dex
++)
1173 OSStatus rx
= impExpImportCertUnCommon(signingCerts
[dex
], defaultKeychain
, outArray
);
1174 if (rx
!=noErr
&& rx
!=errSecDuplicateItem
)
1175 dtprintf("impExpImportCertCommon failed: %ld\n", (long)rx
);
1177 if (defaultKeychain
)
1178 CFRelease(defaultKeychain
);
1181 static const char *cfabsoluteTimeToString(CFAbsoluteTime abstime
)
1183 CFGregorianDate greg
= CFAbsoluteTimeGetGregorianDate(abstime
, NULL
);
1185 if (19 != snprintf(str
, 20, "%4.4d-%2.2d-%2.2d_%2.2d:%2.2d:%2.2d",
1186 (int)greg
.year
, greg
.month
, greg
.day
, greg
.hour
, greg
.minute
, (int)greg
.second
))
1188 char *data
= (char *)malloc(20);
1189 strncpy(data
, str
, 20);
1193 static OSStatus
setTSALeafValidityDates(SecCmsSignerInfoRef signerinfo
)
1195 SecCertificateRef tsaLeaf
= SecCmsSignerInfoGetSigningCertificate(signerinfo
, NULL
);
1198 return SecCmsVSSigningCertNotFound
;
1200 signerinfo
->tsaLeafNotBefore
= SecCertificateNotValidBefore(tsaLeaf
); /* Start date for Timestamp Authority leaf */
1201 signerinfo
->tsaLeafNotAfter
= SecCertificateNotValidAfter(tsaLeaf
); /* Expiration date for Timestamp Authority leaf */
1203 const char *nbefore
= cfabsoluteTimeToString(signerinfo
->tsaLeafNotBefore
);
1204 const char *nafter
= cfabsoluteTimeToString(signerinfo
->tsaLeafNotAfter
);
1205 if (nbefore
&& nafter
)
1207 dtprintf("Timestamp Authority leaf valid from %s to %s\n", nbefore
, nafter
);
1208 free((void *)nbefore
);free((void *)nafter
);
1211 return errSecSuccess
;
1215 From RFC 3161: Time-Stamp Protocol (TSP),August 2001, APPENDIX B:
1217 B) The validity of the digital signature may then be verified in the
1220 1) The time-stamp token itself MUST be verified and it MUST be
1221 verified that it applies to the signature of the signer.
1223 2) The date/time indicated by the TSA in the TimeStampToken
1226 3) The certificate used by the signer MUST be identified and
1229 4) The date/time indicated by the TSA MUST be within the
1230 validity period of the signer's certificate.
1232 5) The revocation information about that certificate, at the
1233 date/time of the Time-Stamping operation, MUST be retrieved.
1235 6) Should the certificate be revoked, then the date/time of
1236 revocation shall be later than the date/time indicated by
1239 If all these conditions are successful, then the digital signature
1240 shall be declared as valid.
1244 OSStatus
decodeTimeStampToken(SecCmsSignerInfoRef signerinfo
, CSSM_DATA_PTR inData
, CSSM_DATA_PTR encDigest
, uint64_t expectedNonce
)
1246 return decodeTimeStampTokenWithPolicy(signerinfo
, NULL
, inData
, encDigest
, expectedNonce
);
1249 OSStatus
decodeTimeStampTokenWithPolicy(SecCmsSignerInfoRef signerinfo
, CFTypeRef timeStampPolicy
, CSSM_DATA_PTR inData
, CSSM_DATA_PTR encDigest
, uint64_t expectedNonce
)
1252 We update signerinfo with timestamp and tsa certificate chain.
1253 encDigest is the original signed blob, which we must hash and compare.
1254 inData comes from the unAuthAttr section of the CMS message
1256 These are set in signerinfo as side effects:
1262 SecCmsDecoderRef decoderContext
= NULL
;
1263 SecCmsMessageRef cmsMessage
= NULL
;
1264 SecCmsContentInfoRef contentInfo
;
1265 SecCmsSignedDataRef signedData
;
1266 SECOidTag contentTypeTag
;
1267 int contentLevelCount
;
1269 OSStatus result
= errSecUnknownFormat
;
1270 CSSM_DATA
**signingCerts
= NULL
;
1272 dtprintf("decodeTimeStampToken top: PORT_GetError() %d -----\n", PORT_GetError());
1275 /* decode the message */
1276 require_noerr(result
= SecCmsDecoderCreate (NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &decoderContext
), xit
);
1277 result
= SecCmsDecoderUpdate(decoderContext
, inData
->Data
, inData
->Length
);
1279 result
= errSecTimestampInvalid
;
1280 SecCmsDecoderDestroy(decoderContext
);
1284 require_noerr(result
= SecCmsDecoderFinish(decoderContext
, &cmsMessage
), xit
);
1286 // process the results
1287 contentLevelCount
= SecCmsMessageContentLevelCount(cmsMessage
);
1290 printDataAsHex("encDigest",encDigest
, 0);
1293 for (ix
= 0; ix
< contentLevelCount
; ++ix
) {
1294 dtprintf("\n----- Content Level %d -----\n", ix
);
1295 // get content information
1296 contentInfo
= SecCmsMessageContentLevel (cmsMessage
, ix
);
1297 contentTypeTag
= SecCmsContentInfoGetContentTypeTag (contentInfo
);
1299 // After 2nd round, contentInfo.content.data is the TSTInfo
1301 debugShowContentTypeOID(contentInfo
);
1303 switch (contentTypeTag
) {
1304 case SEC_OID_PKCS7_SIGNED_DATA
: {
1305 require((signedData
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(contentInfo
)) != NULL
, xit
);
1307 debugShowSignerInfo(signedData
);
1309 SECAlgorithmID
**digestAlgorithms
= SecCmsSignedDataGetDigestAlgs(signedData
);
1310 unsigned digestAlgCount
= SecCmsArrayCount((void **)digestAlgorithms
);
1311 dtprintf("digestAlgCount: %d\n", digestAlgCount
);
1312 if (signedData
->digests
) {
1315 for (jx
=0;jx
< digestAlgCount
;jx
++) {
1316 sprintf(buffer
, " digest[%u]", jx
);
1317 printDataAsHex(buffer
,signedData
->digests
[jx
], 0);
1320 dtprintf("digests not yet computed\n");
1321 CSSM_DATA_PTR innerContent
= SecCmsContentInfoGetInnerContent(contentInfo
);
1324 dtprintf("inner content length: %ld\n", innerContent
->Length
);
1325 SecAsn1TSAMessageImprint fakeMessageImprint
= {{{0}},};
1326 SecCmsSignerInfoRef tsaSigner
= SecCmsSignedDataGetSignerInfo(signedData
, 0);
1327 OSStatus status
= createTSAMessageImprint(tsaSigner
, &tsaSigner
->digestAlg
, innerContent
, &fakeMessageImprint
);
1328 require_noerr_action(status
, xit
, dtprintf("createTSAMessageImprint status: %d\n", (int)status
); result
= status
);
1329 printDataAsHex("inner content hash",&fakeMessageImprint
.hashedMessage
, 0);
1330 CSSM_DATA_PTR digestdata
= &fakeMessageImprint
.hashedMessage
;
1331 CSSM_DATA_PTR digests
[2] = {digestdata
, NULL
};
1332 status
= SecCmsSignedDataSetDigests(signedData
, digestAlgorithms
, (CSSM_DATA_PTR
*)&digests
);
1333 require_noerr_action(status
, xit
, dtprintf("createTSAMessageImprint status: %d\n", (int)status
); result
= status
);
1335 dtprintf("no inner content\n");
1340 Import the certificates. We leave this as a warning, since
1341 there are configurations where the certificates are not returned.
1343 signingCerts
= SecCmsSignedDataGetCertificateList(signedData
);
1344 if (signingCerts
== NULL
) {
1345 dtprintf("SecCmsSignedDataGetCertificateList returned NULL\n");
1347 if (!signerinfo
->timestampCertList
) {
1348 signerinfo
->timestampCertList
= CFArrayCreateMutable(kCFAllocatorDefault
, 10, &kCFTypeArrayCallBacks
);
1350 saveTSACertificates(signingCerts
, signerinfo
->timestampCertList
);
1351 require_noerr(result
= setTSALeafValidityDates(signerinfo
), xit
);
1352 debugSaveCertificates(signingCerts
);
1355 int numberOfSigners
= SecCmsSignedDataSignerInfoCount (signedData
);
1357 if (numberOfSigners
> 0) {
1358 /* @@@ assume there's only one signer since SecCms can't handle multiple signers anyway */
1359 signerinfo
->timestampCert
= CFRetainSafe(SecCmsSignerInfoGetSigningCertificate(signedData
->signerInfos
[0], NULL
));
1362 result
= verifySigners(signedData
, numberOfSigners
, timeStampPolicy
);
1364 dtprintf("verifySigners failed: %ld\n", (long)result
); // warning
1365 goto xit
; // remap to SecCmsVSTimestampNotTrusted ?
1370 case SEC_OID_PKCS9_SIGNING_CERTIFICATE
: {
1371 dtprintf("SEC_OID_PKCS9_SIGNING_CERTIFICATE seen\n");
1374 case SEC_OID_PKCS9_ID_CT_TSTInfo
: {
1375 SecAsn1TSATSTInfo tstInfo
= {{0},};
1376 result
= verifyTSTInfo(contentInfo
->rawContent
, signerinfo
, &tstInfo
, &signerinfo
->timestampTime
, expectedNonce
, encDigest
);
1377 if (signerinfo
->timestampTime
) {
1378 const char *tstamp
= cfabsoluteTimeToString(signerinfo
->timestampTime
);
1380 dtprintf("Timestamp Authority timestamp: %s\n", tstamp
);
1381 free((void *)tstamp
);
1386 case SEC_OID_OTHER
: {
1387 dtprintf("otherContent : %p\n", (char *)SecCmsContentInfoGetContent (contentInfo
));
1391 dtprintf("ContentTypeTag : %x\n", contentTypeTag
);
1397 SecCmsMessageDestroy(cmsMessage
);