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>
51 #include <utilities/SecDispatchRelease.h>
53 #include "tsaSupport.h"
54 #include "tsaSupportPriv.h"
55 #include "tsaTemplates.h"
62 const CFStringRef kTSAContextKeyURL
= CFSTR("ServerURL");
63 const CFStringRef kTSAContextKeyNoCerts
= CFSTR("NoCerts");
64 const CFStringRef kTSADebugContextKeyBadReq
= CFSTR("DebugBadReq");
65 const CFStringRef kTSADebugContextKeyBadNonce
= CFSTR("DebugBadNonce");
67 extern const SecAsn1Template kSecAsn1TSATSTInfoTemplate
[];
69 extern OSStatus
impExpImportCertCommon(
70 const CSSM_DATA
*cdata
,
71 SecKeychainRef importKeychain
, // optional
72 CFMutableArrayRef outArray
); // optional, append here
74 #pragma mark ----- Debug Logs -----
77 #define TSA_USE_SYSLOG 1
84 #define tsaDebug(fmt, ...) \
87 struct timeval time_now; \
88 gettimeofday(&time_now, NULL); \
89 struct tm* time_info = localtime(&time_now.tv_sec); \
90 strftime(buf, sizeof(buf), "[%Y-%m-%d %H:%M:%S]", time_info); \
91 fprintf(stderr, "%s " fmt, buf, ## __VA_ARGS__); \
92 syslog(LOG_ERR, " " fmt, ## __VA_ARGS__); \
94 #define tsa_secinfo(scope, format...) \
96 syslog(LOG_NOTICE, format); \
97 secinfo(scope, format); \
101 #define tsaDebug(args...) tsa_secinfo("tsa", ## args)
102 #define tsa_secinfo(scope, format...) \
103 secinfo(scope, format)
107 #define TSTINFO_DEBUG 1 //jch
111 #define dtprintf(args...) tsaDebug(args)
113 #define dtprintf(args...)
116 #define kHTTPResponseCodeContinue 100
117 #define kHTTPResponseCodeOK 200
118 #define kHTTPResponseCodeNoContent 204
119 #define kHTTPResponseCodeBadRequest 400
120 #define kHTTPResponseCodeUnauthorized 401
121 #define kHTTPResponseCodeForbidden 403
122 #define kHTTPResponseCodeNotFound 404
123 #define kHTTPResponseCodeConflict 409
124 #define kHTTPResponseCodeExpectationFailed 417
125 #define kHTTPResponseCodeServFail 500
126 #define kHTTPResponseCodeServiceUnavailable 503
127 #define kHTTPResponseCodeInsufficientStorage 507
129 #pragma mark ----- Debug/Utilities -----
131 static OSStatus
remapHTTPErrorCodes(OSStatus status
)
135 case kHTTPResponseCodeOK
:
136 case kHTTPResponseCodeContinue
:
138 case kHTTPResponseCodeBadRequest
:
139 return errSecTimestampBadRequest
;
140 case kHTTPResponseCodeNoContent
:
141 case kHTTPResponseCodeUnauthorized
:
142 case kHTTPResponseCodeForbidden
:
143 case kHTTPResponseCodeNotFound
:
144 case kHTTPResponseCodeConflict
:
145 case kHTTPResponseCodeExpectationFailed
:
146 case kHTTPResponseCodeServFail
:
147 case kHTTPResponseCodeInsufficientStorage
:
148 case kHTTPResponseCodeServiceUnavailable
:
149 return errSecTimestampServiceNotAvailable
;
157 static void printDataAsHex(const char *title
, const CSSM_DATA
*d
, unsigned maxToPrint
) // 0 means print it all
162 uint32 len
= (uint32
)d
->Length
;
167 const int wrapwid
= 24; // large enough so SHA-1 hashes fit on one line...
169 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
)
184 sz
= sprintf(buffer
+ offset
, " %02x", (unsigned int)cp
[i
] & 0xff);
185 if ((i
% wrapwid
) == (wrapwid
-1))
187 dtprintf("%s", buffer
);
193 sz
=sprintf(buffer
+ offset
, more
?" ...\n":"\n");
197 // fprintf(stderr, "%s", buffer);
198 dtprintf("%s", buffer
);
205 int tsaWriteFileX(const char *fileName
, const unsigned char *bytes
, size_t numBytes
)
210 fd
= open(fileName
, O_RDWR
| O_CREAT
| O_TRUNC
, 0600);
214 rtn
= (int)write(fd
, bytes
, numBytes
);
215 if(rtn
!= (int)numBytes
)
218 fprintf(stderr
, "writeFile: short write\n");
229 char *cfStringToChar(CFStringRef inStr
)
233 const char *str
= NULL
;
236 return strdup(""); // return a null string
239 if ((str
= CFStringGetCStringPtr(inStr
, kCFStringEncodingUTF8
))) {
240 result
= strdup(str
);
242 // need to extract into buffer
243 CFIndex length
= CFStringGetLength(inStr
); // in 16-bit character units
244 CFIndex bytesToAllocate
= CFStringGetMaximumSizeForEncoding(length
, kCFStringEncodingUTF8
) + 1;
245 result
= malloc(bytesToAllocate
);
246 if (!CFStringGetCString(inStr
, result
, bytesToAllocate
, kCFStringEncodingUTF8
))
253 /* Oids longer than this are considered invalid. */
254 #define MAX_OID_SIZE 32
257 /* FIXME: There are other versions of this in SecCertifcate.c and SecCertificateP.c */
258 static CFStringRef
SecDERItemCopyOIDDecimalRepresentation(CFAllocatorRef allocator
, const CSSM_OID
*oid
)
260 if (oid
->Length
== 0)
261 return CFSTR("<NULL>");
263 if (oid
->Length
> MAX_OID_SIZE
)
264 return CFSTR("Oid too long");
266 CFMutableStringRef result
= CFStringCreateMutable(allocator
, 0);
268 // The first two levels are encoded into one byte, since the root levelq
269 // has only 3 nodes (40*x + y). However if x = joint-iso-itu-t(2) then
270 // y may be > 39, so we have to add special-case handling for this.
271 uint32_t x
= oid
->Data
[0] / 40;
272 uint32_t y
= oid
->Data
[0] % 40;
275 // Handle special case for large y if x = 2
279 CFStringAppendFormat(result
, NULL
, CFSTR("%u.%u"), x
, y
);
282 for (x
= 1; x
< oid
->Length
; ++x
)
284 value
= (value
<< 7) | (oid
->Data
[x
] & 0x7F);
285 /* @@@ value may not span more than 4 bytes. */
286 /* A max number of 20 values is allowed. */
287 if (!(oid
->Data
[x
] & 0x80))
289 CFStringAppendFormat(result
, NULL
, CFSTR(".%lu"), (unsigned long)value
);
297 static void debugSaveCertificates(CSSM_DATA
**outCerts
)
302 CSSM_DATA_PTR
*certp
;
304 const char *certNameBase
= "/tmp/tsa-resp-cert-";
305 char fname
[PATH_MAX
];
306 unsigned certCount
= SecCmsArrayCount((void **)outCerts
);
307 dtprintf("Found %d certs\n",certCount
);
309 for (certp
=outCerts
;*certp
;certp
++, ++jx
)
312 strncpy(fname
, certNameBase
, strlen(certNameBase
)+1);
313 sprintf(numstr
,"%u", jx
);
314 strcat(fname
,numstr
);
315 tsaWriteFileX(fname
, (*certp
)->Data
, (*certp
)->Length
);
317 break; //something wrong
323 static void debugShowSignerInfo(SecCmsSignedDataRef signedData
)
326 int numberOfSigners
= SecCmsSignedDataSignerInfoCount (signedData
);
327 dtprintf("numberOfSigners : %d\n", numberOfSigners
);
329 for (ix
=0;ix
< numberOfSigners
;ix
++)
331 SecCmsSignerInfoRef sigi
= SecCmsSignedDataGetSignerInfo(signedData
,ix
);
334 CFStringRef commonName
= SecCmsSignerInfoGetSignerCommonName(sigi
);
335 const char *signerhdr
= " signer : ";
338 char *cn
= cfStringToChar(commonName
);
339 dtprintf("%s%s\n", signerhdr
, cn
);
342 CFReleaseNull(commonName
);
345 dtprintf("%s<NULL>\n", signerhdr
);
351 static void debugShowContentTypeOID(SecCmsContentInfoRef contentInfo
)
355 CSSM_OID
*typeOID
= SecCmsContentInfoGetContentTypeOID(contentInfo
);
358 CFStringRef oidCFStr
= SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault
, typeOID
);
359 char *oidstr
= cfStringToChar(oidCFStr
);
360 printDataAsHex("oid:", typeOID
, (unsigned int)typeOID
->Length
);
361 dtprintf("\toid: %s\n", oidstr
);
370 uint64_t tsaDER_ToInt(const CSSM_DATA
*DER_Data
)
375 while(i
< DER_Data
->Length
) {
376 rtn
|= DER_Data
->Data
[i
];
377 if(++i
== DER_Data
->Length
) {
385 void displayTSTInfo(SecAsn1TSATSTInfo
*tstInfo
)
388 dtprintf("--- TSTInfo ---\n");
392 if (tstInfo
->version
.Data
)
394 uint64_t vers
= tsaDER_ToInt(&tstInfo
->version
);
395 dtprintf("Version:\t\t%u\n", (int)vers
);
398 if (tstInfo
->serialNumber
.Data
)
400 uint64_t sn
= tsaDER_ToInt(&tstInfo
->serialNumber
);
401 dtprintf("SerialNumber:\t%llu\n", sn
);
404 if (tstInfo
->ordering
.Data
)
406 uint64_t ord
= tsaDER_ToInt(&tstInfo
->ordering
);
407 dtprintf("Ordering:\t\t%s\n", ord
?"yes":"no");
410 if (tstInfo
->nonce
.Data
)
412 uint64_t nonce
= tsaDER_ToInt(&tstInfo
->nonce
);
413 dtprintf("Nonce:\t\t%llu\n", nonce
);
416 dtprintf("Nonce:\t\tnot specified\n");
418 if (tstInfo
->genTime
.Data
)
420 char buf
[tstInfo
->genTime
.Length
+1];
421 memcpy(buf
, (const char *)tstInfo
->genTime
.Data
, tstInfo
->genTime
.Length
);
422 buf
[tstInfo
->genTime
.Length
]=0;
423 dtprintf("GenTime:\t\t%s\n", buf
);
426 dtprintf("-- MessageImprint --\n");
427 if (true) // SecAsn1TSAMessageImprint
429 printDataAsHex(" Algorithm:",&tstInfo
->messageImprint
.hashAlgorithm
.algorithm
, 0);
430 printDataAsHex(" Message :", &tstInfo
->messageImprint
.hashedMessage
, 0);//tstInfo->messageImprint.hashedMessage.Length);
435 #pragma mark ----- TimeStamp Response using XPC -----
437 #include <xpc/private.h>
439 static OSStatus
checkForNonDERResponse(const unsigned char *resp
, size_t respLen
)
442 Good start is something like 30 82 0c 03 30 15 02 01 00 30 10 0c 0e 4f 70 65
444 URL: http://timestamp-int.corp.apple.com/signserver/process?TimeStampSigner
445 Resp: Http/1.1 Service Unavailable
447 URL: http://timestamp-int.corp.apple.com/ts01
450 URL: http://cutandtaste.com/404 (or other forced 404 site)
454 OSStatus status
= noErr
;
455 const char ader
[2] = { 0x30, 0x82 };
456 char *respStr
= NULL
;
458 size_t badResponseCount
;
460 const char *badResponses
[] =
463 "Http/1.1 Service Unavailable",
467 require_action(resp
&& respLen
, xit
, status
= errSecTimestampServiceNotAvailable
);
469 // This is usual case
470 if ((respLen
> 1) && (memcmp(resp
, ader
, 2)==0)) // might be good; pass on to DER decoder
473 badResponseCount
= sizeof(badResponses
)/sizeof(char *);
475 for (ix
= 0; ix
< badResponseCount
; ++ix
)
476 if (strlen(badResponses
[ix
]) > maxlen
)
477 maxlen
= strlen(badResponses
[ix
]);
479 // Prevent a large response from allocating a ton of memory
480 if (respLen
> maxlen
)
483 respStr
= (char *)malloc(respLen
+1);
484 strlcpy(respStr
, (const char *)resp
, respLen
);
486 for (ix
= 0; ix
< badResponseCount
; ++ix
)
487 if (strcmp(respStr
, badResponses
[ix
])==0)
488 return errSecTimestampServiceNotAvailable
;
492 free((void *)respStr
);
497 static OSStatus
sendTSARequestWithXPC(const unsigned char *tsaReq
, size_t tsaReqLength
, const unsigned char *tsaURL
, unsigned char **tsaResp
, size_t *tsaRespLength
)
499 __block OSStatus result
= noErr
;
500 int timeoutInSeconds
= 15;
501 extern xpc_object_t
xpc_create_with_format(const char * format
, ...);
503 dispatch_queue_t xpc_queue
= dispatch_queue_create("com.apple.security.XPCTimeStampingService", DISPATCH_QUEUE_SERIAL
);
504 __block dispatch_semaphore_t waitSemaphore
= dispatch_semaphore_create(0);
505 dispatch_time_t finishTime
= dispatch_time(DISPATCH_TIME_NOW
, timeoutInSeconds
* NSEC_PER_SEC
);
507 xpc_connection_t con
= xpc_connection_create("com.apple.security.XPCTimeStampingService", xpc_queue
);
509 xpc_connection_set_event_handler(con
, ^(xpc_object_t event
) {
510 xpc_type_t xtype
= xpc_get_type(event
);
511 if (XPC_TYPE_ERROR
== xtype
)
512 { tsaDebug("default: connection error: %s\n", xpc_dictionary_get_string(event
, XPC_ERROR_KEY_DESCRIPTION
)); }
514 { tsaDebug("default: unexpected connection event %p\n", event
); }
517 xpc_connection_resume(con
);
519 xpc_object_t tsaReqData
= xpc_data_create(tsaReq
, tsaReqLength
);
520 const char *urlstr
= (tsaURL
?(const char *)tsaURL
:"");
521 xpc_object_t url_as_xpc_string
= xpc_string_create(urlstr
);
523 xpc_object_t message
= xpc_create_with_format("{operation: TimeStampRequest, ServerURL: %value, TimeStampRequest: %value}", url_as_xpc_string
, tsaReqData
);
525 xpc_connection_send_message_with_reply(con
, message
, xpc_queue
, ^(xpc_object_t reply
)
527 tsaDebug("xpc_connection_send_message_with_reply handler called back\n");
528 dispatch_retain_safe(waitSemaphore
);
530 xpc_type_t xtype
= xpc_get_type(reply
);
531 if (XPC_TYPE_ERROR
== xtype
)
532 { tsaDebug("message error: %s\n", xpc_dictionary_get_string(reply
, XPC_ERROR_KEY_DESCRIPTION
)); }
533 else if (XPC_TYPE_CONNECTION
== xtype
)
534 { tsaDebug("received connection\n"); }
535 else if (XPC_TYPE_DICTIONARY
== xtype
)
539 // This is useful for debugging.
540 char *debug = xpc_copy_description(reply);
541 tsaDebug("DEBUG %s\n", debug);
546 xpc_object_t xpcTimeStampReply
= xpc_dictionary_get_value(reply
, "TimeStampReply");
547 size_t xpcTSRLength
= xpc_data_get_length(xpcTimeStampReply
);
548 tsaDebug("xpcTSRLength: %ld bytes of response\n", xpcTSRLength
);
550 xpc_object_t xpcTimeStampError
= xpc_dictionary_get_value(reply
, "TimeStampError");
551 xpc_object_t xpcTimeStampStatus
= xpc_dictionary_get_value(reply
, "TimeStampStatus");
553 if (xpcTimeStampError
|| xpcTimeStampStatus
)
556 if (xpcTimeStampError
)
558 size_t len
= xpc_string_get_length(xpcTimeStampError
);
559 char *buf
= (char *)malloc(len
);
560 strlcpy(buf
, xpc_string_get_string_ptr(xpcTimeStampError
), len
+1);
561 tsaDebug("xpcTimeStampError: %s\n", buf
);
566 if (xpcTimeStampStatus
)
568 result
= (OSStatus
)xpc_int64_get_value(xpcTimeStampStatus
);
569 tsaDebug("xpcTimeStampStatus: %d\n", (int)result
);
573 result
= remapHTTPErrorCodes(result
);
575 if ((result
== noErr
) && tsaResp
&& tsaRespLength
)
577 *tsaRespLength
= xpcTSRLength
;
578 *tsaResp
= (unsigned char *)malloc(xpcTSRLength
);
580 size_t bytesCopied
= xpc_data_get_bytes(xpcTimeStampReply
, *tsaResp
, 0, xpcTSRLength
);
581 if (bytesCopied
!= xpcTSRLength
)
582 { tsaDebug("length mismatch: copied: %ld, xpc: %ld\n", bytesCopied
, xpcTSRLength
); }
584 if ((result
= checkForNonDERResponse(*tsaResp
,bytesCopied
)))
586 tsaDebug("received non-DER response from timestamp server\n");
591 tsaDebug("copied: %ld bytes of response\n", bytesCopied
);
594 tsaDebug("releasing connection\n");
598 { tsaDebug("unexpected message reply type %p\n", xtype
); }
599 if (waitSemaphore
) { dispatch_semaphore_signal(waitSemaphore
); }
600 dispatch_release_null(waitSemaphore
);
602 { tsaDebug("waiting up to %d seconds for response from XPC\n", timeoutInSeconds
); }
603 if (waitSemaphore
) { dispatch_semaphore_wait(waitSemaphore
, finishTime
); }
605 dispatch_release_null(waitSemaphore
);
606 xpc_release(tsaReqData
);
607 xpc_release(message
);
609 { tsaDebug("sendTSARequestWithXPC exit\n"); }
614 #pragma mark ----- TimeStamp request -----
616 #include "tsaTemplates.h"
617 #include <security_asn1/SecAsn1Coder.h>
618 #include <Security/oidsalg.h>
619 #include <AssertMacros.h>
620 #include <libkern/OSByteOrder.h>
622 extern const SecAsn1Template kSecAsn1TSATimeStampReqTemplate
;
623 extern const SecAsn1Template kSecAsn1TSATimeStampRespTemplateDER
;
625 CFMutableDictionaryRef
SecCmsTSAGetDefaultContext(CFErrorRef
*error
)
627 // Caller responsible for retain/release
628 // <rdar://problem/11077440> Update SecCmsTSAGetDefaultContext with actual URL for Apple Timestamp server
629 // URL will be in TimeStampingPrefs.plist
631 CFBundleRef secFWbundle
= NULL
;
632 CFURLRef resourceURL
= NULL
;
633 CFDataRef resourceData
= NULL
;
634 CFPropertyListRef prefs
= NULL
;
635 CFMutableDictionaryRef contextDict
= NULL
;
636 SInt32 errorCode
= 0;
637 CFOptionFlags options
= 0;
638 CFPropertyListFormat format
= 0;
639 OSStatus status
= noErr
;
641 require_action(secFWbundle
= CFBundleGetBundleWithIdentifier(CFSTR("com.apple.security")), xit
, status
= errSecInternalError
);
642 CFRetain(secFWbundle
);
644 require_action(resourceURL
= CFBundleCopyResourceURL(secFWbundle
, CFSTR("TimeStampingPrefs"), CFSTR("plist"), NULL
),
645 xit
, status
= errSecInvalidPrefsDomain
);
647 require(CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault
, resourceURL
, &resourceData
,
648 NULL
, NULL
, &errorCode
), xit
);
649 require_action(resourceData
, xit
, status
= errSecDataNotAvailable
);
651 prefs
= CFPropertyListCreateWithData(kCFAllocatorDefault
, resourceData
, options
, &format
, error
);
652 require_action(prefs
&& (CFGetTypeID(prefs
)==CFDictionaryGetTypeID()), xit
, status
= errSecInvalidPrefsDomain
);
654 contextDict
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, 0, prefs
);
662 *error
= CFErrorCreate(kCFAllocatorDefault
, kCFErrorDomainOSStatus
, status
, NULL
);
664 CFRelease(secFWbundle
);
666 CFRelease(resourceURL
);
668 CFRelease(resourceData
);
675 static CFDataRef
_SecTSARequestCopyDEREncoding(SecAsn1TSAMessageImprint
*messageImprint
, bool noCerts
, uint64_t nonce
)
677 // Returns DER encoded TimeStampReq
678 // Modeled on _SecOCSPRequestCopyDEREncoding
679 // The Timestamp Authority supports 64 bit nonces (or more possibly)
681 SecAsn1CoderRef coder
= NULL
;
683 SecAsn1Item vers
= {1, &version
};
684 uint8_t creq
= noCerts
?0:1;
685 SecAsn1Item certReq
= {1, &creq
}; //jch - to request or not?
686 SecAsn1TSATimeStampReq tsreq
= {};
687 CFDataRef der
= NULL
;
688 uint64_t nonceVal
= OSSwapHostToBigConstInt64(nonce
);
689 SecAsn1Item nonceItem
= {sizeof(uint64_t), (unsigned char *)&nonceVal
};
691 uint8_t OID_FakePolicy_Data
[] = { 0x2A, 0x03, 0x04, 0x05, 0x06};
692 const CSSM_OID fakePolicyOID
= {sizeof(OID_FakePolicy_Data
),OID_FakePolicy_Data
};
694 tsreq
.version
= vers
;
696 tsreq
.messageImprint
= *messageImprint
;
697 tsreq
.certReq
= certReq
;
699 // skip reqPolicy, extensions for now - FAKES - jch
700 tsreq
.reqPolicy
= fakePolicyOID
; //policyID;
702 tsreq
.nonce
= nonceItem
;
704 // Encode the request
705 require_noerr(SecAsn1CoderCreate(&coder
), errOut
);
708 require_noerr(SecAsn1EncodeItem(coder
, &tsreq
,
709 &kSecAsn1TSATimeStampReqTemplate
, &encoded
), errOut
);
710 der
= CFDataCreate(kCFAllocatorDefault
, encoded
.Data
,
715 SecAsn1CoderRelease(coder
);
720 OSStatus
SecTSAResponseCopyDEREncoding(SecAsn1CoderRef coder
, const CSSM_DATA
*tsaResponse
, SecAsn1TimeStampRespDER
*respDER
)
722 // Partially decode the response
723 OSStatus status
= paramErr
;
725 require(tsaResponse
&& respDER
, errOut
);
726 require_noerr(SecAsn1DecodeData(coder
, tsaResponse
,
727 &kSecAsn1TSATimeStampRespTemplateDER
, respDER
), errOut
);
735 #pragma mark ----- TS Callback -----
737 OSStatus
SecCmsTSADefaultCallback(CFTypeRef context
, void *messageImprintV
, uint64_t nonce
, CSSM_DATA
*signedDERBlob
)
739 OSStatus result
= paramErr
;
740 const unsigned char *tsaReq
= NULL
;
741 size_t tsaReqLength
= 0;
742 CFDataRef cfreq
= NULL
;
743 unsigned char *tsaURL
= NULL
;
744 bool noCerts
= false;
746 if (!context
|| CFGetTypeID(context
)!=CFDictionaryGetTypeID())
749 SecAsn1TSAMessageImprint
*messageImprint
= (SecAsn1TSAMessageImprint
*)messageImprintV
;
750 if (!messageImprint
|| !signedDERBlob
)
753 CFBooleanRef cfnocerts
= (CFBooleanRef
)CFDictionaryGetValue((CFDictionaryRef
)context
, kTSAContextKeyNoCerts
);
756 tsaDebug("[TSA] Request noCerts\n");
757 noCerts
= CFBooleanGetValue(cfnocerts
);
760 // We must spoof the nonce here, before sending the request.
761 // If we tried to alter the reply, then the signature would break instead.
762 CFBooleanRef cfBadNonce
= (CFBooleanRef
)CFDictionaryGetValue((CFDictionaryRef
)context
, kTSADebugContextKeyBadNonce
);
763 if (cfBadNonce
&& CFBooleanGetValue(cfBadNonce
))
765 tsaDebug("[TSA] Forcing bad TS Request by changing nonce\n");
769 printDataAsHex("[TSA] hashToTimeStamp:", &messageImprint
->hashedMessage
,128);
770 cfreq
= _SecTSARequestCopyDEREncoding(messageImprint
, noCerts
, nonce
);
773 tsaReq
= CFDataGetBytePtr(cfreq
);
774 tsaReqLength
= CFDataGetLength(cfreq
);
778 tsaWriteFileX("/tmp/tsareq.req", tsaReq
, tsaReqLength
);
782 CFTypeRef url
= CFDictionaryGetValue((CFDictionaryRef
)context
, kTSAContextKeyURL
);
785 tsaDebug("[TSA] missing URL for TSA (key: %s)\n", "kTSAContextKeyURL");
789 CFStringRef urlStr
= NULL
;
790 if (CFURLGetTypeID() == CFGetTypeID(url
)) {
791 urlStr
= CFURLGetString(url
);
793 require_quiet(CFStringGetTypeID() == CFGetTypeID(url
), xit
);
796 require_quiet(urlStr
, xit
);
799 If debugging, look at special values in the context to mess things up
802 CFBooleanRef cfBadReq
= (CFBooleanRef
)CFDictionaryGetValue((CFDictionaryRef
)context
, kTSADebugContextKeyBadReq
);
803 if (cfBadReq
&& CFBooleanGetValue(cfBadReq
))
805 tsaDebug("[TSA] Forcing bad TS Request by truncating length from %ld to %ld\n", tsaReqLength
, (tsaReqLength
-4));
809 // need to extract into buffer
810 CFIndex length
= CFStringGetLength(urlStr
); // in 16-bit character units
811 tsaURL
= malloc(6 * length
+ 1); // pessimistic
812 if (!CFStringGetCString(urlStr
, (char *)tsaURL
, 6 * length
+ 1, kCFStringEncodingUTF8
))
815 tsaDebug("[TSA] URL for timestamp server: %s\n", tsaURL
);
817 unsigned char *tsaResp
= NULL
;
818 size_t tsaRespLength
= 0;
819 tsaDebug("calling sendTSARequestWithXPC with %ld bytes of request\n", tsaReqLength
);
821 require_noerr(result
= sendTSARequestWithXPC(tsaReq
, tsaReqLength
, tsaURL
, &tsaResp
, &tsaRespLength
), xit
);
823 tsaDebug("sendTSARequestWithXPC copied: %ld bytes of response\n", tsaRespLength
);
825 signedDERBlob
->Data
= tsaResp
;
826 signedDERBlob
->Length
= tsaRespLength
;
832 free((void *)tsaURL
);
839 #pragma mark ----- TimeStamp Verification -----
841 static OSStatus
convertGeneralizedTimeToCFAbsoluteTime(const char *timeStr
, CFAbsoluteTime
*ptime
)
844 See http://userguide.icu-project.org/formatparse/datetime for date/time format.
845 The "Z" signal a GMT time, but CFDateFormatterGetAbsoluteTimeFromString returns
846 values based on local time.
849 OSStatus result
= noErr
;
850 CFDateFormatterRef formatter
= NULL
;
851 CFStringRef time_string
= NULL
;
852 CFTimeZoneRef gmt
= NULL
;
853 CFLocaleRef locale
= NULL
;
854 CFRange
*rangep
= NULL
;
856 require(timeStr
&& timeStr
[0] && ptime
, xit
);
857 require(formatter
= CFDateFormatterCreate(kCFAllocatorDefault
, locale
, kCFDateFormatterNoStyle
, kCFDateFormatterNoStyle
), xit
);
858 // CFRetain(formatter);
859 CFDateFormatterSetFormat(formatter
, CFSTR("yyyyMMddHHmmss'Z'")); // GeneralizedTime
860 gmt
= CFTimeZoneCreateWithTimeIntervalFromGMT(NULL
, 0);
861 CFDateFormatterSetProperty(formatter
, kCFDateFormatterTimeZone
, gmt
);
863 time_string
= CFStringCreateWithCString(kCFAllocatorDefault
, timeStr
, kCFStringEncodingUTF8
);
864 if (!time_string
|| !CFDateFormatterGetAbsoluteTimeFromString(formatter
, time_string
, rangep
, ptime
))
866 dtprintf("%s is not a valid date\n", timeStr
);
872 CFRelease(formatter
);
874 CFRelease(time_string
);
881 static OSStatus
SecTSAValidateTimestamp(const SecAsn1TSATSTInfo
*tstInfo
, CSSM_DATA
**signingCerts
, CFAbsoluteTime
*timestampTime
)
883 // See <rdar://problem/11077708> Properly handle revocation information of timestamping certificate
884 OSStatus result
= paramErr
;
885 CFAbsoluteTime genTime
= 0;
886 char timeStr
[32] = {0,};
887 SecCertificateRef signingCertificate
= NULL
;
889 require(tstInfo
&& signingCerts
&& (tstInfo
->genTime
.Length
< 16), xit
);
891 // Find the leaf signingCert
892 require_noerr(result
= SecCertificateCreateFromData(*signingCerts
,
893 CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_DER
, &signingCertificate
), xit
);
895 memcpy(timeStr
, tstInfo
->genTime
.Data
, tstInfo
->genTime
.Length
);
896 timeStr
[tstInfo
->genTime
.Length
] = 0;
897 require_noerr(convertGeneralizedTimeToCFAbsoluteTime(timeStr
, &genTime
), xit
);
898 if (SecCertificateIsValidX(signingCertificate
, genTime
)) // iOS?
901 result
= errSecTimestampInvalid
;
903 *timestampTime
= genTime
;
905 if (signingCertificate
)
906 CFReleaseNull(signingCertificate
);
910 static OSStatus
verifyTSTInfo(const CSSM_DATA_PTR content
, CSSM_DATA
**signingCerts
, SecAsn1TSATSTInfo
*tstInfo
, CFAbsoluteTime
*timestampTime
, uint64_t expectedNonce
)
912 OSStatus status
= paramErr
;
913 SecAsn1CoderRef coder
= NULL
;
918 require_noerr(SecAsn1CoderCreate(&coder
), xit
);
919 require_noerr(SecAsn1Decode(coder
, content
->Data
, content
->Length
,
920 kSecAsn1TSATSTInfoTemplate
, tstInfo
), xit
);
921 displayTSTInfo(tstInfo
);
924 if (tstInfo
->nonce
.Data
&& expectedNonce
!=0)
926 uint64_t nonce
= tsaDER_ToInt(&tstInfo
->nonce
);
927 // if (expectedNonce!=nonce)
928 dtprintf("verifyTSTInfo nonce: actual: %lld, expected: %lld\n", nonce
, expectedNonce
);
929 require_action(expectedNonce
==nonce
, xit
, status
= errSecTimestampRejection
);
932 status
= SecTSAValidateTimestamp(tstInfo
, signingCerts
, timestampTime
);
933 dtprintf("SecTSAValidateTimestamp result: %ld\n", (long)status
);
937 SecAsn1CoderRelease(coder
);
941 static void debugShowExtendedTrustResult(int index
, CFDictionaryRef extendedResult
)
946 CFStringRef xresStr
= CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
,
947 CFSTR("Extended trust result for signer #%d : %@"), index
, extendedResult
);
958 extern const char *cssmErrorString(CSSM_RETURN error
);
960 static void statusBitTest(CSSM_TP_APPLE_CERT_STATUS certStatus
, uint32 bit
, const char *str
)
962 if (certStatus
& bit
)
963 dtprintf("%s ", str
);
967 static void debugShowCertEvidenceInfo(uint16_t certCount
, const CSSM_TP_APPLE_EVIDENCE_INFO
*info
)
970 CSSM_TP_APPLE_CERT_STATUS cs
;
971 // const CSSM_TP_APPLE_EVIDENCE_INFO *pinfo = info;
973 for (ix
=0; info
&& (ix
<certCount
); ix
++, ++info
)
975 cs
= info
->StatusBits
;
976 dtprintf(" cert %u:\n", ix
);
977 dtprintf(" StatusBits : 0x%x", (unsigned)cs
);
981 statusBitTest(cs
, CSSM_CERT_STATUS_EXPIRED
, "EXPIRED");
982 statusBitTest(cs
, CSSM_CERT_STATUS_NOT_VALID_YET
,
984 statusBitTest(cs
, CSSM_CERT_STATUS_IS_IN_INPUT_CERTS
,
985 "IS_IN_INPUT_CERTS");
986 statusBitTest(cs
, CSSM_CERT_STATUS_IS_IN_ANCHORS
,
988 statusBitTest(cs
, CSSM_CERT_STATUS_IS_ROOT
, "IS_ROOT");
989 statusBitTest(cs
, CSSM_CERT_STATUS_IS_FROM_NET
, "IS_FROM_NET");
995 dtprintf(" NumStatusCodes : %u ", info
->NumStatusCodes
);
996 CSSM_RETURN
*pstatuscode
= info
->StatusCodes
;
998 for (jx
=0; pstatuscode
&& (jx
<info
->NumStatusCodes
); jx
++, ++pstatuscode
)
999 dtprintf("%s ", cssmErrorString(*pstatuscode
));
1002 dtprintf(" Index: %u\n", info
->Index
);
1009 static const char *trustResultTypeString(SecTrustResultType trustResultType
)
1011 switch (trustResultType
)
1013 case kSecTrustResultProceed
: return "TrustResultProceed";
1014 case kSecTrustResultUnspecified
: return "TrustResultUnspecified";
1015 case kSecTrustResultDeny
: return "TrustResultDeny"; // user reject
1016 case kSecTrustResultInvalid
: return "TrustResultInvalid";
1017 case kSecTrustResultConfirm
: return "TrustResultConfirm";
1018 case kSecTrustResultRecoverableTrustFailure
: return "TrustResultRecoverableTrustFailure";
1019 case kSecTrustResultFatalTrustFailure
: return "TrustResultUnspecified";
1020 case kSecTrustResultOtherError
: return "TrustResultOtherError";
1021 default: return "TrustResultUnknown";
1027 static OSStatus
verifySigners(SecCmsSignedDataRef signedData
, int numberOfSigners
, CFTypeRef timeStampPolicy
)
1029 // See <rdar://problem/11077588> Bubble up SecTrustEvaluate of timestamp response to high level callers
1030 // Also <rdar://problem/11077708> Properly handle revocation information of timestamping certificate
1032 SecTrustRef trustRef
= NULL
;
1033 CFTypeRef policy
= CFRetainSafe(timeStampPolicy
);
1034 int result
=errSecInternalError
;
1038 require(policy
= SecPolicyCreateWithOID(kSecPolicyAppleTimeStamping
), xit
);
1042 for (jx
= 0; jx
< numberOfSigners
; ++jx
)
1044 SecTrustResultType trustResultType
;
1045 CFDictionaryRef extendedResult
= NULL
;
1046 CFArrayRef certChain
= NULL
;
1047 uint16_t certCount
= 0;
1049 CSSM_TP_APPLE_EVIDENCE_INFO
*statusChain
= NULL
;
1051 // SecCmsSignedDataVerifySignerInfo returns trustRef, which we can call SecTrustEvaluate on
1052 // usually (always?) if result is noErr, the SecTrust*Result calls will return errSecTrustNotAvailable
1053 result
= SecCmsSignedDataVerifySignerInfo (signedData
, jx
, NULL
, policy
, &trustRef
);
1054 dtprintf("[%s] SecCmsSignedDataVerifySignerInfo: result: %d, signer: %d\n",
1055 __FUNCTION__
, result
, jx
);
1056 require_noerr(result
, xit
);
1058 result
= SecTrustEvaluate (trustRef
, &trustResultType
);
1059 dtprintf("[%s] SecTrustEvaluate: result: %d, trustResult: %s (%d)\n",
1060 __FUNCTION__
, result
, trustResultTypeString(trustResultType
), trustResultType
);
1063 switch (trustResultType
)
1065 case kSecTrustResultProceed
:
1066 case kSecTrustResultUnspecified
:
1068 case kSecTrustResultDeny
: // user reject
1069 result
= errSecTimestampNotTrusted
; // SecCmsVSTimestampNotTrusted ?
1071 case kSecTrustResultInvalid
:
1072 assert(false); // should never happen
1073 result
= errSecTimestampNotTrusted
; // SecCmsVSTimestampNotTrusted ?
1075 case kSecTrustResultConfirm
:
1076 case kSecTrustResultRecoverableTrustFailure
:
1077 case kSecTrustResultFatalTrustFailure
:
1078 case kSecTrustResultOtherError
:
1082 There are two "errors" that need to be resolved externally:
1083 CSSMERR_TP_CERT_EXPIRED can be OK if the timestamp was made
1084 before the TSA chain expired; CSSMERR_TP_CERT_NOT_VALID_YET
1085 can happen in the case where the user's clock was set to 0.
1086 We don't want to prevent them using apps automatically, so
1087 return noErr and let codesign or whover decide.
1089 OSStatus resultCode
;
1090 require_action(SecTrustGetCssmResultCode(trustRef
, &resultCode
)==noErr
, xit
, result
= errSecTimestampNotTrusted
);
1091 result
= (resultCode
== CSSMERR_TP_CERT_EXPIRED
|| resultCode
== CSSMERR_TP_CERT_NOT_VALID_YET
)?noErr
:errSecTimestampNotTrusted
;
1096 rx
= SecTrustGetResult(trustRef
, &trustResultType
, &certChain
, &statusChain
);
1097 dtprintf("[%s] SecTrustGetResult: result: %d, type: %d\n", __FUNCTION__
,rx
, trustResultType
);
1098 certCount
= certChain
?CFArrayGetCount(certChain
):0;
1099 debugShowCertEvidenceInfo(certCount
, statusChain
);
1100 CFReleaseNull(certChain
);
1102 rx
= SecTrustCopyExtendedResult(trustRef
, &extendedResult
);
1103 dtprintf("[%s] SecTrustCopyExtendedResult: result: %d\n", __FUNCTION__
, rx
);
1106 debugShowExtendedTrustResult(jx
, extendedResult
);
1107 CFRelease(extendedResult
);
1111 CFReleaseNull(trustRef
);
1116 CFReleaseNull(trustRef
);
1122 static OSStatus
impExpImportCertUnCommon(
1123 const CSSM_DATA
*cdata
,
1124 SecKeychainRef importKeychain
, // optional
1125 CFMutableArrayRef outArray
) // optional, append here
1127 // The only difference between this and impExpImportCertCommon is that we append to outArray
1128 // before attempting to add to the keychain
1129 OSStatus status
= noErr
;
1130 SecCertificateRef certRef
= NULL
;
1132 require_action(cdata
, xit
, status
= errSecUnsupportedFormat
);
1134 /* Pass kCFAllocatorNull as bytesDeallocator to assure the bytes aren't freed */
1135 CFDataRef data
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, (const UInt8
*)cdata
->Data
, (CFIndex
)cdata
->Length
, kCFAllocatorNull
);
1136 require_action(data
, xit
, status
= errSecUnsupportedFormat
);
1138 certRef
= SecCertificateCreateWithData(kCFAllocatorDefault
, data
);
1139 CFRelease(data
); /* certRef has its own copy of the data now */
1141 dtprintf("impExpHandleCert error\n");
1142 return errSecUnsupportedFormat
;
1146 CFArrayAppendValue(outArray
, certRef
);
1150 status
= SecCertificateAddToKeychain(certRef
, importKeychain
);
1151 if (status
!=noErr
&& status
!=errSecDuplicateItem
)
1152 { dtprintf("SecCertificateAddToKeychain error: %ld\n", (long)status
); }
1161 static void saveTSACertificates(CSSM_DATA
**signingCerts
, CFMutableArrayRef outArray
)
1163 SecKeychainRef defaultKeychain
= NULL
;
1164 // Don't save certificates in keychain to avoid securityd issues
1165 // if (SecKeychainCopyDefault(&defaultKeychain))
1166 // defaultKeychain = NULL;
1168 unsigned certCount
= SecCmsArrayCount((void **)signingCerts
);
1170 for (dex
=0; dex
<certCount
; dex
++)
1172 OSStatus rx
= impExpImportCertUnCommon(signingCerts
[dex
], defaultKeychain
, outArray
);
1173 if (rx
!=noErr
&& rx
!=errSecDuplicateItem
)
1174 dtprintf("impExpImportCertCommon failed: %ld\n", (long)rx
);
1176 if (defaultKeychain
)
1177 CFRelease(defaultKeychain
);
1180 static const char *cfabsoluteTimeToString(CFAbsoluteTime abstime
)
1182 CFGregorianDate greg
= CFAbsoluteTimeGetGregorianDate(abstime
, NULL
);
1184 if (19 != snprintf(str
, 20, "%4.4d-%2.2d-%2.2d_%2.2d:%2.2d:%2.2d",
1185 (int)greg
.year
, greg
.month
, greg
.day
, greg
.hour
, greg
.minute
, (int)greg
.second
))
1187 char *data
= (char *)malloc(20);
1188 strncpy(data
, str
, 20);
1192 static OSStatus
setTSALeafValidityDates(SecCmsSignerInfoRef signerinfo
)
1194 OSStatus status
= noErr
;
1196 if (!signerinfo
->timestampCertList
|| (CFArrayGetCount(signerinfo
->timestampCertList
) == 0))
1197 return SecCmsVSSigningCertNotFound
;
1199 SecCertificateRef tsaLeaf
= (SecCertificateRef
)CFArrayGetValueAtIndex(signerinfo
->timestampCertList
, 0);
1200 require_action(tsaLeaf
, xit
, status
= errSecCertificateCannotOperate
);
1202 signerinfo
->tsaLeafNotBefore
= SecCertificateNotValidBefore(tsaLeaf
); /* Start date for Timestamp Authority leaf */
1203 signerinfo
->tsaLeafNotAfter
= SecCertificateNotValidAfter(tsaLeaf
); /* Expiration date for Timestamp Authority leaf */
1205 const char *nbefore
= cfabsoluteTimeToString(signerinfo
->tsaLeafNotBefore
);
1206 const char *nafter
= cfabsoluteTimeToString(signerinfo
->tsaLeafNotAfter
);
1207 if (nbefore
&& nafter
)
1209 dtprintf("Timestamp Authority leaf valid from %s to %s\n", nbefore
, nafter
);
1210 free((void *)nbefore
);free((void *)nafter
);
1215 status = errSecCertificateNotValidYet;
1217 status = errSecCertificateExpired;
1225 From RFC 3161: Time-Stamp Protocol (TSP),August 2001, APPENDIX B:
1227 B) The validity of the digital signature may then be verified in the
1230 1) The time-stamp token itself MUST be verified and it MUST be
1231 verified that it applies to the signature of the signer.
1233 2) The date/time indicated by the TSA in the TimeStampToken
1236 3) The certificate used by the signer MUST be identified and
1239 4) The date/time indicated by the TSA MUST be within the
1240 validity period of the signer's certificate.
1242 5) The revocation information about that certificate, at the
1243 date/time of the Time-Stamping operation, MUST be retrieved.
1245 6) Should the certificate be revoked, then the date/time of
1246 revocation shall be later than the date/time indicated by
1249 If all these conditions are successful, then the digital signature
1250 shall be declared as valid.
1254 OSStatus
decodeTimeStampToken(SecCmsSignerInfoRef signerinfo
, CSSM_DATA_PTR inData
, CSSM_DATA_PTR encDigest
, uint64_t expectedNonce
)
1256 return decodeTimeStampTokenWithPolicy(signerinfo
, NULL
, inData
, encDigest
, expectedNonce
);
1259 OSStatus
decodeTimeStampTokenWithPolicy(SecCmsSignerInfoRef signerinfo
, CFTypeRef timeStampPolicy
, CSSM_DATA_PTR inData
, CSSM_DATA_PTR encDigest
, uint64_t expectedNonce
)
1262 We update signerinfo with timestamp and tsa certificate chain.
1263 encDigest is the original signed blob, which we must hash and compare.
1264 inData comes from the unAuthAttr section of the CMS message
1266 These are set in signerinfo as side effects:
1271 SecCmsDecoderRef decoderContext
= NULL
;
1272 SecCmsMessageRef cmsMessage
= NULL
;
1273 SecCmsContentInfoRef contentInfo
;
1274 SecCmsSignedDataRef signedData
;
1275 SECOidTag contentTypeTag
;
1276 int contentLevelCount
;
1278 OSStatus result
= errSecUnknownFormat
;
1279 CSSM_DATA
**signingCerts
= NULL
;
1281 dtprintf("decodeTimeStampToken top: PORT_GetError() %d -----\n", PORT_GetError());
1284 /* decode the message */
1285 require_noerr(result
= SecCmsDecoderCreate (NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, &decoderContext
), xit
);
1286 result
= SecCmsDecoderUpdate(decoderContext
, inData
->Data
, inData
->Length
);
1289 result
= errSecTimestampInvalid
;
1290 SecCmsDecoderDestroy(decoderContext
);
1294 require_noerr(result
= SecCmsDecoderFinish(decoderContext
, &cmsMessage
), xit
);
1296 // process the results
1297 contentLevelCount
= SecCmsMessageContentLevelCount(cmsMessage
);
1300 printDataAsHex("encDigest",encDigest
, 0);
1302 for (ix
= 0; ix
< contentLevelCount
; ++ix
)
1304 dtprintf("\n----- Content Level %d -----\n", ix
);
1305 // get content information
1306 contentInfo
= SecCmsMessageContentLevel (cmsMessage
, ix
);
1307 contentTypeTag
= SecCmsContentInfoGetContentTypeTag (contentInfo
);
1309 // After 2nd round, contentInfo.content.data is the TSTInfo
1311 debugShowContentTypeOID(contentInfo
);
1313 switch (contentTypeTag
)
1315 case SEC_OID_PKCS7_SIGNED_DATA
:
1317 require((signedData
= (SecCmsSignedDataRef
)SecCmsContentInfoGetContent(contentInfo
)) != NULL
, xit
);
1319 debugShowSignerInfo(signedData
);
1321 SECAlgorithmID
**digestAlgorithms
= SecCmsSignedDataGetDigestAlgs(signedData
);
1322 unsigned digestAlgCount
= SecCmsArrayCount((void **)digestAlgorithms
);
1323 dtprintf("digestAlgCount: %d\n", digestAlgCount
);
1324 if (signedData
->digests
)
1328 for (jx
=0;jx
< digestAlgCount
;jx
++)
1330 sprintf(buffer
, " digest[%u]", jx
);
1331 printDataAsHex(buffer
,signedData
->digests
[jx
], 0);
1336 dtprintf("No digests\n");
1337 CSSM_DATA_PTR innerContent
= SecCmsContentInfoGetInnerContent(contentInfo
);
1340 dtprintf("inner content length: %ld\n", innerContent
->Length
);
1341 SecAsn1TSAMessageImprint fakeMessageImprint
= {{{0}},};
1342 OSStatus status
= createTSAMessageImprint(signedData
, innerContent
, &fakeMessageImprint
);
1344 { dtprintf("createTSAMessageImprint status: %d\n", (int)status
); }
1345 printDataAsHex("inner content hash",&fakeMessageImprint
.hashedMessage
, 0);
1346 CSSM_DATA_PTR digestdata
= &fakeMessageImprint
.hashedMessage
;
1347 CSSM_DATA_PTR digests
[2] = {digestdata
, NULL
};
1348 SecCmsSignedDataSetDigests(signedData
, digestAlgorithms
, (CSSM_DATA_PTR
*)&digests
);
1351 dtprintf("no inner content\n");
1355 Import the certificates. We leave this as a warning, since
1356 there are configurations where the certificates are not returned.
1358 signingCerts
= SecCmsSignedDataGetCertificateList(signedData
);
1359 if (signingCerts
== NULL
)
1360 { dtprintf("SecCmsSignedDataGetCertificateList returned NULL\n"); }
1363 if (!signerinfo
->timestampCertList
)
1364 signerinfo
->timestampCertList
= CFArrayCreateMutable(kCFAllocatorDefault
, 10, &kCFTypeArrayCallBacks
);
1365 saveTSACertificates(signingCerts
, signerinfo
->timestampCertList
);
1366 require_noerr(result
= setTSALeafValidityDates(signerinfo
), xit
);
1367 debugSaveCertificates(signingCerts
);
1370 int numberOfSigners
= SecCmsSignedDataSignerInfoCount (signedData
);
1372 result
= verifySigners(signedData
, numberOfSigners
, timeStampPolicy
);
1374 dtprintf("verifySigners failed: %ld\n", (long)result
); // warning
1377 if (result
) // remap to SecCmsVSTimestampNotTrusted ?
1382 case SEC_OID_PKCS9_SIGNING_CERTIFICATE
:
1384 dtprintf("SEC_OID_PKCS9_SIGNING_CERTIFICATE seen\n");
1388 case SEC_OID_PKCS9_ID_CT_TSTInfo
:
1390 SecAsn1TSATSTInfo tstInfo
= {{0},};
1391 result
= verifyTSTInfo(contentInfo
->rawContent
, signingCerts
, &tstInfo
, &signerinfo
->timestampTime
, expectedNonce
);
1392 if (signerinfo
->timestampTime
)
1394 const char *tstamp
= cfabsoluteTimeToString(signerinfo
->timestampTime
);
1397 dtprintf("Timestamp Authority timestamp: %s\n", tstamp
);
1398 free((void *)tstamp
);
1405 dtprintf("otherContent : %p\n", (char *)SecCmsContentInfoGetContent (contentInfo
));
1409 dtprintf("ContentTypeTag : %x\n", contentTypeTag
);
1415 SecCmsMessageDestroy(cmsMessage
);