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) {
489 return errSecTimestampServiceNotAvailable
;
494 free((void *)respStr
);
499 static OSStatus
sendTSARequestWithXPC(const unsigned char *tsaReq
, size_t tsaReqLength
, const unsigned char *tsaURL
, unsigned char **tsaResp
, size_t *tsaRespLength
)
501 __block OSStatus result
= noErr
;
502 int timeoutInSeconds
= 15;
503 extern xpc_object_t
xpc_create_with_format(const char * format
, ...);
505 dispatch_queue_t xpc_queue
= dispatch_queue_create("com.apple.security.XPCTimeStampingService", DISPATCH_QUEUE_SERIAL
);
506 __block dispatch_semaphore_t waitSemaphore
= dispatch_semaphore_create(0);
507 dispatch_time_t finishTime
= dispatch_time(DISPATCH_TIME_NOW
, timeoutInSeconds
* NSEC_PER_SEC
);
509 xpc_connection_t con
= xpc_connection_create("com.apple.security.XPCTimeStampingService", xpc_queue
);
511 xpc_connection_set_event_handler(con
, ^(xpc_object_t event
) {
512 xpc_type_t xtype
= xpc_get_type(event
);
513 if (XPC_TYPE_ERROR
== xtype
)
514 { tsaDebug("default: connection error: %s\n", xpc_dictionary_get_string(event
, XPC_ERROR_KEY_DESCRIPTION
)); }
516 { tsaDebug("default: unexpected connection event %p\n", event
); }
519 xpc_connection_resume(con
);
521 xpc_object_t tsaReqData
= xpc_data_create(tsaReq
, tsaReqLength
);
522 const char *urlstr
= (tsaURL
?(const char *)tsaURL
:"");
523 xpc_object_t url_as_xpc_string
= xpc_string_create(urlstr
);
525 xpc_object_t message
= xpc_create_with_format("{operation: TimeStampRequest, ServerURL: %value, TimeStampRequest: %value}", url_as_xpc_string
, tsaReqData
);
527 xpc_connection_send_message_with_reply(con
, message
, xpc_queue
, ^(xpc_object_t reply
)
529 tsaDebug("xpc_connection_send_message_with_reply handler called back\n");
530 dispatch_retain_safe(waitSemaphore
);
532 xpc_type_t xtype
= xpc_get_type(reply
);
533 if (XPC_TYPE_ERROR
== xtype
)
534 { tsaDebug("message error: %s\n", xpc_dictionary_get_string(reply
, XPC_ERROR_KEY_DESCRIPTION
)); }
535 else if (XPC_TYPE_CONNECTION
== xtype
)
536 { tsaDebug("received connection\n"); }
537 else if (XPC_TYPE_DICTIONARY
== xtype
)
541 // This is useful for debugging.
542 char *debug = xpc_copy_description(reply);
543 tsaDebug("DEBUG %s\n", debug);
548 xpc_object_t xpcTimeStampReply
= xpc_dictionary_get_value(reply
, "TimeStampReply");
549 size_t xpcTSRLength
= xpc_data_get_length(xpcTimeStampReply
);
550 tsaDebug("xpcTSRLength: %ld bytes of response\n", xpcTSRLength
);
552 xpc_object_t xpcTimeStampError
= xpc_dictionary_get_value(reply
, "TimeStampError");
553 xpc_object_t xpcTimeStampStatus
= xpc_dictionary_get_value(reply
, "TimeStampStatus");
555 if (xpcTimeStampError
|| xpcTimeStampStatus
)
558 if (xpcTimeStampError
)
560 size_t len
= xpc_string_get_length(xpcTimeStampError
);
561 char *buf
= (char *)malloc(len
);
562 strlcpy(buf
, xpc_string_get_string_ptr(xpcTimeStampError
), len
+1);
563 tsaDebug("xpcTimeStampError: %s\n", buf
);
568 if (xpcTimeStampStatus
)
570 result
= (OSStatus
)xpc_int64_get_value(xpcTimeStampStatus
);
571 tsaDebug("xpcTimeStampStatus: %d\n", (int)result
);
575 result
= remapHTTPErrorCodes(result
);
577 if ((result
== noErr
) && tsaResp
&& tsaRespLength
)
579 *tsaRespLength
= xpcTSRLength
;
580 *tsaResp
= (unsigned char *)malloc(xpcTSRLength
);
582 size_t bytesCopied
= xpc_data_get_bytes(xpcTimeStampReply
, *tsaResp
, 0, xpcTSRLength
);
583 if (bytesCopied
!= xpcTSRLength
)
584 { tsaDebug("length mismatch: copied: %ld, xpc: %ld\n", bytesCopied
, xpcTSRLength
); }
586 if ((result
= checkForNonDERResponse(*tsaResp
,bytesCopied
)))
588 tsaDebug("received non-DER response from timestamp server\n");
593 tsaDebug("copied: %ld bytes of response\n", bytesCopied
);
596 tsaDebug("releasing connection\n");
600 { tsaDebug("unexpected message reply type %p\n", xtype
); }
601 if (waitSemaphore
) { dispatch_semaphore_signal(waitSemaphore
); }
602 dispatch_release_null(waitSemaphore
);
604 { tsaDebug("waiting up to %d seconds for response from XPC\n", timeoutInSeconds
); }
605 if (waitSemaphore
) { dispatch_semaphore_wait(waitSemaphore
, finishTime
); }
607 dispatch_release_null(waitSemaphore
);
608 xpc_release(tsaReqData
);
609 xpc_release(message
);
611 { tsaDebug("sendTSARequestWithXPC exit\n"); }
616 #pragma mark ----- TimeStamp request -----
618 #include "tsaTemplates.h"
619 #include <security_asn1/SecAsn1Coder.h>
620 #include <Security/oidsalg.h>
621 #include <AssertMacros.h>
622 #include <libkern/OSByteOrder.h>
624 extern const SecAsn1Template kSecAsn1TSATimeStampReqTemplate
;
625 extern const SecAsn1Template kSecAsn1TSATimeStampRespTemplateDER
;
627 CFMutableDictionaryRef
SecCmsTSAGetDefaultContext(CFErrorRef
*error
)
629 // Caller responsible for retain/release
630 // <rdar://problem/11077440> Update SecCmsTSAGetDefaultContext with actual URL for Apple Timestamp server
631 // URL will be in TimeStampingPrefs.plist
633 CFBundleRef secFWbundle
= NULL
;
634 CFURLRef resourceURL
= NULL
;
635 CFDataRef resourceData
= NULL
;
636 CFPropertyListRef prefs
= NULL
;
637 CFMutableDictionaryRef contextDict
= NULL
;
638 SInt32 errorCode
= 0;
639 CFOptionFlags options
= 0;
640 CFPropertyListFormat format
= 0;
641 OSStatus status
= noErr
;
643 require_action(secFWbundle
= CFBundleGetBundleWithIdentifier(CFSTR("com.apple.security")), xit
, status
= errSecInternalError
);
644 CFRetain(secFWbundle
);
646 require_action(resourceURL
= CFBundleCopyResourceURL(secFWbundle
, CFSTR("TimeStampingPrefs"), CFSTR("plist"), NULL
),
647 xit
, status
= errSecInvalidPrefsDomain
);
649 require(CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault
, resourceURL
, &resourceData
,
650 NULL
, NULL
, &errorCode
), xit
);
651 require_action(resourceData
, xit
, status
= errSecDataNotAvailable
);
653 prefs
= CFPropertyListCreateWithData(kCFAllocatorDefault
, resourceData
, options
, &format
, error
);
654 require_action(prefs
&& (CFGetTypeID(prefs
)==CFDictionaryGetTypeID()), xit
, status
= errSecInvalidPrefsDomain
);
656 contextDict
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, prefs
);
664 *error
= CFErrorCreate(kCFAllocatorDefault
, kCFErrorDomainOSStatus
, status
, NULL
);
666 CFRelease(secFWbundle
);
668 CFRelease(resourceURL
);
670 CFRelease(resourceData
);
677 static CFDataRef
_SecTSARequestCopyDEREncoding(SecAsn1TSAMessageImprint
*messageImprint
, bool noCerts
, uint64_t nonce
)
679 // Returns DER encoded TimeStampReq
680 // Modeled on _SecOCSPRequestCopyDEREncoding
681 // The Timestamp Authority supports 64 bit nonces (or more possibly)
683 SecAsn1CoderRef coder
= NULL
;
685 SecAsn1Item vers
= {1, &version
};
686 uint8_t creq
= noCerts
?0:1;
687 SecAsn1Item certReq
= {1, &creq
}; //jch - to request or not?
688 SecAsn1TSATimeStampReq tsreq
= {};
689 CFDataRef der
= NULL
;
690 uint64_t nonceVal
= OSSwapHostToBigConstInt64(nonce
);
691 SecAsn1Item nonceItem
= {sizeof(uint64_t), (unsigned char *)&nonceVal
};
693 uint8_t OID_FakePolicy_Data
[] = { 0x2A, 0x03, 0x04, 0x05, 0x06};
694 const CSSM_OID fakePolicyOID
= {sizeof(OID_FakePolicy_Data
),OID_FakePolicy_Data
};
696 tsreq
.version
= vers
;
698 tsreq
.messageImprint
= *messageImprint
;
699 tsreq
.certReq
= certReq
;
701 // skip reqPolicy, extensions for now - FAKES - jch
702 tsreq
.reqPolicy
= fakePolicyOID
; //policyID;
704 tsreq
.nonce
= nonceItem
;
706 // Encode the request
707 require_noerr(SecAsn1CoderCreate(&coder
), errOut
);
710 require_noerr(SecAsn1EncodeItem(coder
, &tsreq
,
711 &kSecAsn1TSATimeStampReqTemplate
, &encoded
), errOut
);
712 der
= CFDataCreate(kCFAllocatorDefault
, encoded
.Data
,
717 SecAsn1CoderRelease(coder
);
722 OSStatus
SecTSAResponseCopyDEREncoding(SecAsn1CoderRef coder
, const CSSM_DATA
*tsaResponse
, SecAsn1TimeStampRespDER
*respDER
)
724 // Partially decode the response
725 OSStatus status
= paramErr
;
727 require(tsaResponse
&& respDER
, errOut
);
728 require_noerr(SecAsn1DecodeData(coder
, tsaResponse
,
729 &kSecAsn1TSATimeStampRespTemplateDER
, respDER
), errOut
);
737 #pragma mark ----- TS Callback -----
739 OSStatus
SecCmsTSADefaultCallback(CFTypeRef context
, void *messageImprintV
, uint64_t nonce
, CSSM_DATA
*signedDERBlob
)
741 OSStatus result
= paramErr
;
742 const unsigned char *tsaReq
= NULL
;
743 size_t tsaReqLength
= 0;
744 CFDataRef cfreq
= NULL
;
745 unsigned char *tsaURL
= NULL
;
746 bool noCerts
= false;
748 if (!context
|| CFGetTypeID(context
)!=CFDictionaryGetTypeID())
751 SecAsn1TSAMessageImprint
*messageImprint
= (SecAsn1TSAMessageImprint
*)messageImprintV
;
752 if (!messageImprint
|| !signedDERBlob
)
755 CFBooleanRef cfnocerts
= (CFBooleanRef
)CFDictionaryGetValue((CFDictionaryRef
)context
, kTSAContextKeyNoCerts
);
756 if (cfnocerts
!= NULL
)
758 tsaDebug("[TSA] Request noCerts\n");
759 noCerts
= CFBooleanGetValue(cfnocerts
);
762 // We must spoof the nonce here, before sending the request.
763 // If we tried to alter the reply, then the signature would break instead.
764 CFBooleanRef cfBadNonce
= (CFBooleanRef
)CFDictionaryGetValue((CFDictionaryRef
)context
, kTSADebugContextKeyBadNonce
);
765 if (cfBadNonce
&& CFBooleanGetValue(cfBadNonce
))
767 tsaDebug("[TSA] Forcing bad TS Request by changing nonce\n");
771 printDataAsHex("[TSA] hashToTimeStamp:", &messageImprint
->hashedMessage
,128);
772 cfreq
= _SecTSARequestCopyDEREncoding(messageImprint
, noCerts
, nonce
);
775 tsaReq
= CFDataGetBytePtr(cfreq
);
776 tsaReqLength
= CFDataGetLength(cfreq
);
780 tsaWriteFileX("/tmp/tsareq.req", tsaReq
, tsaReqLength
);
784 CFTypeRef url
= CFDictionaryGetValue((CFDictionaryRef
)context
, kTSAContextKeyURL
);
787 tsaDebug("[TSA] missing URL for TSA (key: %s)\n", "kTSAContextKeyURL");
791 CFStringRef urlStr
= NULL
;
792 if (CFURLGetTypeID() == CFGetTypeID(url
)) {
793 urlStr
= CFURLGetString(url
);
795 require_quiet(CFStringGetTypeID() == CFGetTypeID(url
), xit
);
798 require_quiet(urlStr
, xit
);
801 If debugging, look at special values in the context to mess things up
804 CFBooleanRef cfBadReq
= (CFBooleanRef
)CFDictionaryGetValue((CFDictionaryRef
)context
, kTSADebugContextKeyBadReq
);
805 if (cfBadReq
&& CFBooleanGetValue(cfBadReq
))
807 tsaDebug("[TSA] Forcing bad TS Request by truncating length from %ld to %ld\n", tsaReqLength
, (tsaReqLength
-4));
811 // need to extract into buffer
812 CFIndex length
= CFStringGetLength(urlStr
); // in 16-bit character units
813 tsaURL
= malloc(6 * length
+ 1); // pessimistic
814 if (!CFStringGetCString(urlStr
, (char *)tsaURL
, 6 * length
+ 1, kCFStringEncodingUTF8
))
817 tsaDebug("[TSA] URL for timestamp server: %s\n", tsaURL
);
819 unsigned char *tsaResp
= NULL
;
820 size_t tsaRespLength
= 0;
821 tsaDebug("calling sendTSARequestWithXPC with %ld bytes of request\n", tsaReqLength
);
823 require_noerr(result
= sendTSARequestWithXPC(tsaReq
, tsaReqLength
, tsaURL
, &tsaResp
, &tsaRespLength
), xit
);
825 tsaDebug("sendTSARequestWithXPC copied: %ld bytes of response\n", tsaRespLength
);
827 signedDERBlob
->Data
= tsaResp
;
828 signedDERBlob
->Length
= tsaRespLength
;
834 free((void *)tsaURL
);
841 #pragma mark ----- TimeStamp Verification -----
843 static OSStatus
convertGeneralizedTimeToCFAbsoluteTime(const char *timeStr
, CFAbsoluteTime
*ptime
)
846 See http://userguide.icu-project.org/formatparse/datetime for date/time format.
847 The "Z" signal a GMT time, but CFDateFormatterGetAbsoluteTimeFromString returns
848 values based on local time.
851 OSStatus result
= noErr
;
852 CFDateFormatterRef formatter
= NULL
;
853 CFStringRef time_string
= NULL
;
854 CFTimeZoneRef gmt
= NULL
;
855 CFLocaleRef locale
= NULL
;
856 CFRange
*rangep
= NULL
;
858 require(timeStr
&& timeStr
[0] && ptime
, xit
);
859 require(formatter
= CFDateFormatterCreate(kCFAllocatorDefault
, locale
, kCFDateFormatterNoStyle
, kCFDateFormatterNoStyle
), xit
);
860 // CFRetain(formatter);
861 CFDateFormatterSetFormat(formatter
, CFSTR("yyyyMMddHHmmss'Z'")); // GeneralizedTime
862 gmt
= CFTimeZoneCreateWithTimeIntervalFromGMT(NULL
, 0);
863 CFDateFormatterSetProperty(formatter
, kCFDateFormatterTimeZone
, gmt
);
865 time_string
= CFStringCreateWithCString(kCFAllocatorDefault
, timeStr
, kCFStringEncodingUTF8
);
866 if (!time_string
|| !CFDateFormatterGetAbsoluteTimeFromString(formatter
, time_string
, rangep
, ptime
))
868 dtprintf("%s is not a valid date\n", timeStr
);
874 CFRelease(formatter
);
876 CFRelease(time_string
);
883 static OSStatus
SecTSAValidateTimestamp(const SecAsn1TSATSTInfo
*tstInfo
, SecCertificateRef signerCert
, CFAbsoluteTime
*timestampTime
)
885 // See <rdar://problem/11077708> Properly handle revocation information of timestamping certificate
886 OSStatus result
= paramErr
;
887 CFAbsoluteTime genTime
= 0;
888 char timeStr
[32] = {0,};
890 require(tstInfo
&& signerCert
&& (tstInfo
->genTime
.Length
< 16), xit
);;
892 memcpy(timeStr
, tstInfo
->genTime
.Data
, tstInfo
->genTime
.Length
);
893 timeStr
[tstInfo
->genTime
.Length
] = 0;
894 require_noerr(convertGeneralizedTimeToCFAbsoluteTime(timeStr
, &genTime
), xit
);
895 if (SecCertificateIsValidX(signerCert
, genTime
)) // iOS?
898 result
= errSecTimestampInvalid
;
900 *timestampTime
= genTime
;
905 static OSStatus
verifyTSTInfo(const CSSM_DATA_PTR content
, SecCmsSignerInfoRef signerinfo
, SecAsn1TSATSTInfo
*tstInfo
, CFAbsoluteTime
*timestampTime
, uint64_t expectedNonce
, CSSM_DATA_PTR encDigest
)
907 OSStatus status
= paramErr
;
908 SecAsn1CoderRef coder
= NULL
;
913 SecCertificateRef signerCert
= SecCmsSignerInfoGetTimestampSigningCert(signerinfo
);
914 SecAsn1TSAMessageImprint expectedMessageImprint
;
916 require_noerr(SecAsn1CoderCreate(&coder
), xit
);
917 require_noerr(SecAsn1Decode(coder
, content
->Data
, content
->Length
,
918 kSecAsn1TSATSTInfoTemplate
, tstInfo
), xit
);
919 displayTSTInfo(tstInfo
);
922 if (tstInfo
->nonce
.Data
&& expectedNonce
!=0)
924 uint64_t nonce
= tsaDER_ToInt(&tstInfo
->nonce
);
925 // if (expectedNonce!=nonce)
926 dtprintf("verifyTSTInfo nonce: actual: %lld, expected: %lld\n", nonce
, expectedNonce
);
927 require_action(expectedNonce
==nonce
, xit
, status
= errSecTimestampRejection
);
930 // Check the times in the timestamp
931 require_noerr(status
= SecTSAValidateTimestamp(tstInfo
, signerCert
, timestampTime
), xit
);
932 dtprintf("SecTSAValidateTimestamp result: %ld\n", (long)status
);
934 // Check the message imprint against the encDigest from the signerInfo containing this timestamp
935 SECOidTag hashAlg
= SECOID_GetAlgorithmTag(&tstInfo
->messageImprint
.hashAlgorithm
);
936 require_action(hashAlg
== SEC_OID_SHA256
|| hashAlg
== SEC_OID_SHA1
, xit
, status
= errSecInvalidDigestAlgorithm
);
937 require_noerr(status
= createTSAMessageImprint(signerinfo
, &tstInfo
->messageImprint
.hashAlgorithm
,
938 encDigest
, &expectedMessageImprint
), xit
);
939 require_action(CERT_CompareCssmData(&expectedMessageImprint
.hashedMessage
, &tstInfo
->messageImprint
.hashedMessage
), xit
,
940 status
= errSecTimestampInvalid
; secerror("Timestamp MessageImprint did not match the signature's hash"));
944 SecAsn1CoderRelease(coder
);
948 static void debugShowExtendedTrustResult(int index
, CFDictionaryRef extendedResult
)
953 CFStringRef xresStr
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
,
954 CFSTR("Extended trust result for signer #%d : %@"), index
, extendedResult
);
965 extern const char *cssmErrorString(CSSM_RETURN error
);
967 static void statusBitTest(CSSM_TP_APPLE_CERT_STATUS certStatus
, uint32 bit
, const char *str
)
969 if (certStatus
& bit
)
970 dtprintf("%s ", str
);
974 static void debugShowCertEvidenceInfo(uint16_t certCount
, const CSSM_TP_APPLE_EVIDENCE_INFO
*info
)
977 CSSM_TP_APPLE_CERT_STATUS cs
;
978 // const CSSM_TP_APPLE_EVIDENCE_INFO *pinfo = info;
980 for (ix
=0; info
&& (ix
<certCount
); ix
++, ++info
)
982 cs
= info
->StatusBits
;
983 dtprintf(" cert %u:\n", ix
);
984 dtprintf(" StatusBits : 0x%x", (unsigned)cs
);
988 statusBitTest(cs
, CSSM_CERT_STATUS_EXPIRED
, "EXPIRED");
989 statusBitTest(cs
, CSSM_CERT_STATUS_NOT_VALID_YET
,
991 statusBitTest(cs
, CSSM_CERT_STATUS_IS_IN_INPUT_CERTS
,
992 "IS_IN_INPUT_CERTS");
993 statusBitTest(cs
, CSSM_CERT_STATUS_IS_IN_ANCHORS
,
995 statusBitTest(cs
, CSSM_CERT_STATUS_IS_ROOT
, "IS_ROOT");
996 statusBitTest(cs
, CSSM_CERT_STATUS_IS_FROM_NET
, "IS_FROM_NET");
1002 dtprintf(" NumStatusCodes : %u ", info
->NumStatusCodes
);
1003 CSSM_RETURN
*pstatuscode
= info
->StatusCodes
;
1005 for (jx
=0; pstatuscode
&& (jx
<info
->NumStatusCodes
); jx
++, ++pstatuscode
)
1006 dtprintf("%s ", cssmErrorString(*pstatuscode
));
1009 dtprintf(" Index: %u\n", info
->Index
);
1016 static const char *trustResultTypeString(SecTrustResultType trustResultType
)
1018 switch (trustResultType
)
1020 case kSecTrustResultProceed
: return "TrustResultProceed";
1021 case kSecTrustResultUnspecified
: return "TrustResultUnspecified";
1022 case kSecTrustResultDeny
: return "TrustResultDeny"; // user reject
1023 case kSecTrustResultInvalid
: return "TrustResultInvalid";
1024 case kSecTrustResultRecoverableTrustFailure
: return "TrustResultRecoverableTrustFailure";
1025 case kSecTrustResultFatalTrustFailure
: return "TrustResultUnspecified";
1026 case kSecTrustResultOtherError
: return "TrustResultOtherError";
1027 default: return "TrustResultUnknown";
1033 static OSStatus
verifySigners(SecCmsSignedDataRef signedData
, int numberOfSigners
, CFTypeRef timeStampPolicy
)
1035 // See <rdar://problem/11077588> Bubble up SecTrustEvaluate of timestamp response to high level callers
1036 // Also <rdar://problem/11077708> Properly handle revocation information of timestamping certificate
1038 SecTrustRef trustRef
= NULL
;
1039 CFTypeRef policy
= CFRetainSafe(timeStampPolicy
);
1040 int result
=errSecInternalError
;
1044 require(policy
= SecPolicyCreateWithOID(kSecPolicyAppleTimeStamping
), xit
);
1048 for (jx
= 0; jx
< numberOfSigners
; ++jx
)
1050 SecTrustResultType trustResultType
;
1051 CFDictionaryRef extendedResult
= NULL
;
1052 CFArrayRef certChain
= NULL
;
1053 uint16_t certCount
= 0;
1055 CSSM_TP_APPLE_EVIDENCE_INFO
*statusChain
= NULL
;
1057 // SecCmsSignedDataVerifySignerInfo returns trustRef, which we can call SecTrustEvaluate on
1058 // usually (always?) if result is noErr, the SecTrust*Result calls will return errSecTrustNotAvailable
1059 result
= SecCmsSignedDataVerifySignerInfo (signedData
, jx
, NULL
, policy
, &trustRef
);
1060 dtprintf("[%s] SecCmsSignedDataVerifySignerInfo: result: %d, signer: %d\n",
1061 __FUNCTION__
, result
, jx
);
1062 require_noerr(result
, xit
);
1064 result
= SecTrustEvaluate (trustRef
, &trustResultType
);
1065 dtprintf("[%s] SecTrustEvaluate: result: %d, trustResult: %s (%d)\n",
1066 __FUNCTION__
, result
, trustResultTypeString(trustResultType
), trustResultType
);
1069 switch (trustResultType
)
1071 case kSecTrustResultProceed
:
1072 case kSecTrustResultUnspecified
:
1074 case kSecTrustResultDeny
: // user reject
1075 result
= errSecTimestampNotTrusted
; // SecCmsVSTimestampNotTrusted ?
1077 case kSecTrustResultInvalid
:
1078 assert(false); // should never happen
1079 result
= errSecTimestampNotTrusted
; // SecCmsVSTimestampNotTrusted ?
1081 case kSecTrustResultRecoverableTrustFailure
:
1082 case kSecTrustResultFatalTrustFailure
:
1083 case kSecTrustResultOtherError
:
1087 There are two "errors" that need to be resolved externally:
1088 CSSMERR_TP_CERT_EXPIRED can be OK if the timestamp was made
1089 before the TSA chain expired; CSSMERR_TP_CERT_NOT_VALID_YET
1090 can happen in the case where the user's clock was set to 0.
1091 We don't want to prevent them using apps automatically, so
1092 return noErr and let codesign or whover decide.
1094 OSStatus resultCode
;
1095 require_action(SecTrustGetCssmResultCode(trustRef
, &resultCode
)==noErr
, xit
, result
= errSecTimestampNotTrusted
);
1096 result
= (resultCode
== CSSMERR_TP_CERT_EXPIRED
|| resultCode
== CSSMERR_TP_CERT_NOT_VALID_YET
)?noErr
:errSecTimestampNotTrusted
;
1101 rx
= SecTrustGetResult(trustRef
, &trustResultType
, &certChain
, &statusChain
);
1102 dtprintf("[%s] SecTrustGetResult: result: %d, type: %d\n", __FUNCTION__
,rx
, trustResultType
);
1103 certCount
= certChain
?CFArrayGetCount(certChain
):0;
1104 debugShowCertEvidenceInfo(certCount
, statusChain
);
1105 CFReleaseNull(certChain
);
1107 rx
= SecTrustCopyExtendedResult(trustRef
, &extendedResult
);
1108 dtprintf("[%s] SecTrustCopyExtendedResult: result: %d\n", __FUNCTION__
, rx
);
1111 debugShowExtendedTrustResult(jx
, extendedResult
);
1112 CFRelease(extendedResult
);
1116 CFReleaseNull(trustRef
);
1121 CFReleaseNull(trustRef
);
1127 static OSStatus
impExpImportCertUnCommon(
1128 const CSSM_DATA
*cdata
,
1129 SecKeychainRef importKeychain
, // optional
1130 CFMutableArrayRef outArray
) // optional, append here
1132 // The only difference between this and impExpImportCertCommon is that we append to outArray
1133 // before attempting to add to the keychain
1134 OSStatus status
= noErr
;
1135 SecCertificateRef certRef
= NULL
;
1137 require_action(cdata
, xit
, status
= errSecUnsupportedFormat
);
1139 /* Pass kCFAllocatorNull as bytesDeallocator to assure the bytes aren't freed */
1140 CFDataRef data
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, (const UInt8
*)cdata
->Data
, (CFIndex
)cdata
->Length
, kCFAllocatorNull
);
1141 require_action(data
, xit
, status
= errSecUnsupportedFormat
);
1143 certRef
= SecCertificateCreateWithData(kCFAllocatorDefault
, data
);
1144 CFRelease(data
); /* certRef has its own copy of the data now */
1146 dtprintf("impExpHandleCert error\n");
1147 return errSecUnsupportedFormat
;
1151 CFArrayAppendValue(outArray
, certRef
);
1155 status
= SecCertificateAddToKeychain(certRef
, importKeychain
);
1156 if (status
!=noErr
&& status
!=errSecDuplicateItem
)
1157 { dtprintf("SecCertificateAddToKeychain error: %ld\n", (long)status
); }
1167 static void saveTSACertificates(CSSM_DATA
**signingCerts
, CFMutableArrayRef outArray
)
1169 SecKeychainRef defaultKeychain
= NULL
;
1170 // Don't save certificates in keychain to avoid securityd issues
1171 // if (SecKeychainCopyDefault(&defaultKeychain))
1172 // defaultKeychain = NULL;
1174 unsigned certCount
= SecCmsArrayCount((void **)signingCerts
);
1176 for (dex
=0; dex
<certCount
; dex
++)
1178 OSStatus rx
= impExpImportCertUnCommon(signingCerts
[dex
], defaultKeychain
, outArray
);
1179 if (rx
!=noErr
&& rx
!=errSecDuplicateItem
)
1180 dtprintf("impExpImportCertCommon failed: %ld\n", (long)rx
);
1182 if (defaultKeychain
)
1183 CFRelease(defaultKeychain
);
1186 static const char *cfabsoluteTimeToString(CFAbsoluteTime abstime
)
1188 CFGregorianDate greg
= CFAbsoluteTimeGetGregorianDate(abstime
, NULL
);
1190 if (19 != snprintf(str
, 20, "%4.4d-%2.2d-%2.2d_%2.2d:%2.2d:%2.2d",
1191 (int)greg
.year
, greg
.month
, greg
.day
, greg
.hour
, greg
.minute
, (int)greg
.second
))
1193 char *data
= (char *)malloc(20);
1194 strncpy(data
, str
, 20);
1198 static OSStatus
setTSALeafValidityDates(SecCmsSignerInfoRef signerinfo
)
1200 SecCertificateRef tsaLeaf
= SecCmsSignerInfoGetSigningCertificate(signerinfo
, NULL
);
1203 return SecCmsVSSigningCertNotFound
;
1205 signerinfo
->tsaLeafNotBefore
= SecCertificateNotValidBefore(tsaLeaf
); /* Start date for Timestamp Authority leaf */
1206 signerinfo
->tsaLeafNotAfter
= SecCertificateNotValidAfter(tsaLeaf
); /* Expiration date for Timestamp Authority leaf */
1208 const char *nbefore
= cfabsoluteTimeToString(signerinfo
->tsaLeafNotBefore
);
1209 const char *nafter
= cfabsoluteTimeToString(signerinfo
->tsaLeafNotAfter
);
1210 if (nbefore
&& nafter
)
1212 dtprintf("Timestamp Authority leaf valid from %s to %s\n", nbefore
, nafter
);
1213 free((void *)nbefore
);free((void *)nafter
);
1216 return errSecSuccess
;
1220 From RFC 3161: Time-Stamp Protocol (TSP),August 2001, APPENDIX B:
1222 B) The validity of the digital signature may then be verified in the
1225 1) The time-stamp token itself MUST be verified and it MUST be
1226 verified that it applies to the signature of the signer.
1228 2) The date/time indicated by the TSA in the TimeStampToken
1231 3) The certificate used by the signer MUST be identified and
1234 4) The date/time indicated by the TSA MUST be within the
1235 validity period of the signer's certificate.
1237 5) The revocation information about that certificate, at the
1238 date/time of the Time-Stamping operation, MUST be retrieved.
1240 6) Should the certificate be revoked, then the date/time of
1241 revocation shall be later than the date/time indicated by
1244 If all these conditions are successful, then the digital signature
1245 shall be declared as valid.
1249 OSStatus
decodeTimeStampToken(SecCmsSignerInfoRef signerinfo
, CSSM_DATA_PTR inData
, CSSM_DATA_PTR encDigest
, uint64_t expectedNonce
)
1251 return decodeTimeStampTokenWithPolicy(signerinfo
, NULL
, inData
, encDigest
, expectedNonce
);
1254 OSStatus
decodeTimeStampTokenWithPolicy(SecCmsSignerInfoRef signerinfo
, CFTypeRef timeStampPolicy
, CSSM_DATA_PTR inData
, CSSM_DATA_PTR encDigest
, uint64_t expectedNonce
)
1257 We update signerinfo with timestamp and tsa certificate chain.
1258 encDigest is the original signed blob, which we must hash and compare.
1259 inData comes from the unAuthAttr section of the CMS message
1261 These are set in signerinfo as side effects:
1267 SecCmsDecoderRef decoderContext
= NULL
;
1268 SecCmsMessageRef cmsMessage
= NULL
;
1269 SecCmsContentInfoRef contentInfo
;
1270 SecCmsSignedDataRef signedData
;
1271 SECOidTag contentTypeTag
;
1272 int contentLevelCount
;
1274 OSStatus result
= errSecUnknownFormat
;
1275 CSSM_DATA
**signingCerts
= NULL
;
1277 dtprintf("decodeTimeStampToken top: PORT_GetError() %d -----\n", PORT_GetError());
1280 /* decode the message */
1281 require_noerr(result
= SecCmsDecoderCreate (NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &decoderContext
), xit
);
1282 result
= SecCmsDecoderUpdate(decoderContext
, inData
->Data
, inData
->Length
);
1284 result
= errSecTimestampInvalid
;
1285 SecCmsDecoderDestroy(decoderContext
);
1289 require_noerr(result
= SecCmsDecoderFinish(decoderContext
, &cmsMessage
), xit
);
1291 // process the results
1292 contentLevelCount
= SecCmsMessageContentLevelCount(cmsMessage
);
1295 printDataAsHex("encDigest",encDigest
, 0);
1298 for (ix
= 0; ix
< contentLevelCount
; ++ix
) {
1299 dtprintf("\n----- Content Level %d -----\n", ix
);
1300 // get content information
1301 contentInfo
= SecCmsMessageContentLevel (cmsMessage
, ix
);
1302 contentTypeTag
= SecCmsContentInfoGetContentTypeTag (contentInfo
);
1304 // After 2nd round, contentInfo.content.data is the TSTInfo
1306 debugShowContentTypeOID(contentInfo
);
1308 switch (contentTypeTag
) {
1309 case SEC_OID_PKCS7_SIGNED_DATA
: {
1310 require((signedData
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(contentInfo
)) != NULL
, xit
);
1312 debugShowSignerInfo(signedData
);
1314 SECAlgorithmID
**digestAlgorithms
= SecCmsSignedDataGetDigestAlgs(signedData
);
1315 unsigned digestAlgCount
= SecCmsArrayCount((void **)digestAlgorithms
);
1316 dtprintf("digestAlgCount: %d\n", digestAlgCount
);
1317 if (signedData
->digests
) {
1320 for (jx
=0;jx
< digestAlgCount
;jx
++) {
1321 sprintf(buffer
, " digest[%u]", jx
);
1322 printDataAsHex(buffer
,signedData
->digests
[jx
], 0);
1325 dtprintf("digests not yet computed\n");
1326 CSSM_DATA_PTR innerContent
= SecCmsContentInfoGetInnerContent(contentInfo
);
1329 dtprintf("inner content length: %ld\n", innerContent
->Length
);
1330 SecAsn1TSAMessageImprint fakeMessageImprint
= {{{0}},};
1331 SecCmsSignerInfoRef tsaSigner
= SecCmsSignedDataGetSignerInfo(signedData
, 0);
1332 OSStatus status
= createTSAMessageImprint(tsaSigner
, &tsaSigner
->digestAlg
, innerContent
, &fakeMessageImprint
);
1333 require_noerr_action(status
, xit
, dtprintf("createTSAMessageImprint status: %d\n", (int)status
); result
= status
);
1334 printDataAsHex("inner content hash",&fakeMessageImprint
.hashedMessage
, 0);
1335 CSSM_DATA_PTR digestdata
= &fakeMessageImprint
.hashedMessage
;
1336 CSSM_DATA_PTR digests
[2] = {digestdata
, NULL
};
1337 status
= SecCmsSignedDataSetDigests(signedData
, digestAlgorithms
, (CSSM_DATA_PTR
*)&digests
);
1338 require_noerr_action(status
, xit
, dtprintf("createTSAMessageImprint status: %d\n", (int)status
); result
= status
);
1340 dtprintf("no inner content\n");
1345 Import the certificates. We leave this as a warning, since
1346 there are configurations where the certificates are not returned.
1348 signingCerts
= SecCmsSignedDataGetCertificateList(signedData
);
1349 if (signingCerts
== NULL
) {
1350 dtprintf("SecCmsSignedDataGetCertificateList returned NULL\n");
1352 if (!signerinfo
->timestampCertList
) {
1353 signerinfo
->timestampCertList
= CFArrayCreateMutable(kCFAllocatorDefault
, 10, &kCFTypeArrayCallBacks
);
1355 saveTSACertificates(signingCerts
, signerinfo
->timestampCertList
);
1356 require_noerr(result
= setTSALeafValidityDates(signerinfo
), xit
);
1357 debugSaveCertificates(signingCerts
);
1360 int numberOfSigners
= SecCmsSignedDataSignerInfoCount (signedData
);
1362 if (numberOfSigners
> 0) {
1363 /* @@@ assume there's only one signer since SecCms can't handle multiple signers anyway */
1364 signerinfo
->timestampCert
= CFRetainSafe(SecCmsSignerInfoGetSigningCertificate(signedData
->signerInfos
[0], NULL
));
1367 result
= verifySigners(signedData
, numberOfSigners
, timeStampPolicy
);
1369 dtprintf("verifySigners failed: %ld\n", (long)result
); // warning
1370 goto xit
; // remap to SecCmsVSTimestampNotTrusted ?
1375 case SEC_OID_PKCS9_SIGNING_CERTIFICATE
: {
1376 dtprintf("SEC_OID_PKCS9_SIGNING_CERTIFICATE seen\n");
1379 case SEC_OID_PKCS9_ID_CT_TSTInfo
: {
1380 SecAsn1TSATSTInfo tstInfo
= {{0},};
1381 result
= verifyTSTInfo(contentInfo
->rawContent
, signerinfo
, &tstInfo
, &signerinfo
->timestampTime
, expectedNonce
, encDigest
);
1382 if (signerinfo
->timestampTime
) {
1383 const char *tstamp
= cfabsoluteTimeToString(signerinfo
->timestampTime
);
1385 dtprintf("Timestamp Authority timestamp: %s\n", tstamp
);
1386 free((void *)tstamp
);
1391 case SEC_OID_OTHER
: {
1392 dtprintf("otherContent : %p\n", (char *)SecCmsContentInfoGetContent (contentInfo
));
1396 dtprintf("ContentTypeTag : %x\n", contentTypeTag
);
1402 SecCmsMessageDestroy(cmsMessage
);