]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_smime/lib/tsaSupport.c
Security-57740.1.18.tar.gz
[apple/security.git] / OSX / libsecurity_smime / lib / tsaSupport.c
1 /*
2 * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 *
23 * tsaSupport.c - ASN1 templates Time Stamping Authority requests and responses
24 */
25
26 /*
27 #include <Security/SecCmsDigestContext.h>
28 #include <Security/SecCmsMessage.h>
29 #include <security_asn1/secasn1.h>
30 #include <security_asn1/secerr.h>
31 */
32
33 #include <security_utilities/debugging.h>
34 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
35
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>
52
53 #include "tsaSupport.h"
54 #include "tsaSupportPriv.h"
55 #include "tsaTemplates.h"
56 #include "cmslocal.h"
57
58 #include "secoid.h"
59 #include "secitem.h"
60 #include <fcntl.h>
61
62 const CFStringRef kTSAContextKeyURL = CFSTR("ServerURL");
63 const CFStringRef kTSAContextKeyNoCerts = CFSTR("NoCerts");
64 const CFStringRef kTSADebugContextKeyBadReq = CFSTR("DebugBadReq");
65 const CFStringRef kTSADebugContextKeyBadNonce = CFSTR("DebugBadNonce");
66
67 extern const SecAsn1Template kSecAsn1TSATSTInfoTemplate[];
68
69 extern OSStatus impExpImportCertCommon(
70 const CSSM_DATA *cdata,
71 SecKeychainRef importKeychain, // optional
72 CFMutableArrayRef outArray); // optional, append here
73
74 #pragma mark ----- Debug Logs -----
75
76 #ifndef NDEBUG
77 #define TSA_USE_SYSLOG 1
78 #endif
79
80 #if TSA_USE_SYSLOG
81 #include <syslog.h>
82 #include <time.h>
83 #include <sys/time.h>
84 #define tsaDebug(fmt, ...) \
85 do { if (true) { \
86 char buf[64]; \
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__); \
93 } } while (0)
94 #define tsa_secinfo(scope, format...) \
95 { \
96 syslog(LOG_NOTICE, format); \
97 secinfo(scope, format); \
98 printf(format); \
99 }
100 #else
101 #define tsaDebug(args...) tsa_secinfo("tsa", ## args)
102 #define tsa_secinfo(scope, format...) \
103 secinfo(scope, format)
104 #endif
105
106 #ifndef NDEBUG
107 #define TSTINFO_DEBUG 1 //jch
108 #endif
109
110 #if TSTINFO_DEBUG
111 #define dtprintf(args...) tsaDebug(args)
112 #else
113 #define dtprintf(args...)
114 #endif
115
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
128
129 #pragma mark ----- Debug/Utilities -----
130
131 static OSStatus remapHTTPErrorCodes(OSStatus status)
132 {
133 switch (status)
134 {
135 case kHTTPResponseCodeOK:
136 case kHTTPResponseCodeContinue:
137 return noErr;
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;
150 default:
151 return status;
152 }
153 return status;
154
155 }
156
157 static void printDataAsHex(const char *title, const CSSM_DATA *d, unsigned maxToPrint) // 0 means print it all
158 {
159 #ifndef NDEBUG
160 unsigned i;
161 bool more = false;
162 uint32 len = (uint32)d->Length;
163 uint8 *cp = d->Data;
164 char *buffer = NULL;
165 size_t bufferSize;
166 int offset, sz = 0;
167 const int wrapwid = 24; // large enough so SHA-1 hashes fit on one line...
168
169 if ((maxToPrint != 0) && (len > maxToPrint))
170 {
171 len = maxToPrint;
172 more = true;
173 }
174
175 bufferSize = wrapwid+3*len;
176 buffer = (char *)malloc(bufferSize);
177
178 offset = sprintf(buffer, "%s [len = %u]\n", title, len);
179 dtprintf("%s", buffer);
180 offset = 0;
181
182 for (i=0; (i < len) && (offset+3 < bufferSize); i++, offset += sz)
183 {
184 sz = sprintf(buffer + offset, " %02x", (unsigned int)cp[i] & 0xff);
185 if ((i % wrapwid) == (wrapwid-1))
186 {
187 dtprintf("%s", buffer);
188 offset = 0;
189 sz = 0;
190 }
191 }
192
193 sz=sprintf(buffer + offset, more?" ...\n":"\n");
194 offset += sz;
195 buffer[offset+1]=0;
196
197 // fprintf(stderr, "%s", buffer);
198 dtprintf("%s", buffer);
199
200 free(buffer);
201 #endif
202 }
203
204 #ifndef NDEBUG
205 int tsaWriteFileX(const char *fileName, const unsigned char *bytes, size_t numBytes)
206 {
207 int rtn;
208 int fd;
209
210 fd = open(fileName, O_RDWR | O_CREAT | O_TRUNC, 0600);
211 if (fd <= 0)
212 return errno;
213
214 rtn = (int)write(fd, bytes, numBytes);
215 if(rtn != (int)numBytes)
216 {
217 if (rtn >= 0)
218 fprintf(stderr, "writeFile: short write\n");
219 rtn = EIO;
220 }
221 else
222 rtn = 0;
223
224 close(fd);
225 return rtn;
226 }
227 #endif
228
229 char *cfStringToChar(CFStringRef inStr)
230 {
231 // Caller must free
232 char *result = NULL;
233 const char *str = NULL;
234
235 if (!inStr)
236 return strdup(""); // return a null string
237
238 // quick path first
239 if ((str = CFStringGetCStringPtr(inStr, kCFStringEncodingUTF8))) {
240 result = strdup(str);
241 } else {
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))
247 result[0] = 0;
248 }
249
250 return result;
251 }
252
253 /* Oids longer than this are considered invalid. */
254 #define MAX_OID_SIZE 32
255
256 #ifndef NDEBUG
257 /* FIXME: There are other versions of this in SecCertifcate.c and SecCertificateP.c */
258 static CFStringRef SecDERItemCopyOIDDecimalRepresentation(CFAllocatorRef allocator, const CSSM_OID *oid)
259 {
260 if (oid->Length == 0)
261 return CFSTR("<NULL>");
262
263 if (oid->Length > MAX_OID_SIZE)
264 return CFSTR("Oid too long");
265
266 CFMutableStringRef result = CFStringCreateMutable(allocator, 0);
267
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;
273 if (x > 2)
274 {
275 // Handle special case for large y if x = 2
276 y += (x - 2) * 40;
277 x = 2;
278 }
279 CFStringAppendFormat(result, NULL, CFSTR("%u.%u"), x, y);
280
281 uint32_t value = 0;
282 for (x = 1; x < oid->Length; ++x)
283 {
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))
288 {
289 CFStringAppendFormat(result, NULL, CFSTR(".%lu"), (unsigned long)value);
290 value = 0;
291 }
292 }
293 return result;
294 }
295 #endif
296
297 static void debugSaveCertificates(CSSM_DATA **outCerts)
298 {
299 #ifndef NDEBUG
300 if (outCerts)
301 {
302 CSSM_DATA_PTR *certp;
303 unsigned jx = 0;
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);
308
309 for (certp=outCerts;*certp;certp++, ++jx)
310 {
311 char numstr[32];
312 strncpy(fname, certNameBase, strlen(certNameBase)+1);
313 sprintf(numstr,"%u", jx);
314 strcat(fname,numstr);
315 tsaWriteFileX(fname, (*certp)->Data, (*certp)->Length);
316 if (jx > 5)
317 break; //something wrong
318 }
319 }
320 #endif
321 }
322
323 static void debugShowSignerInfo(SecCmsSignedDataRef signedData)
324 {
325 #ifndef NDEBUG
326 int numberOfSigners = SecCmsSignedDataSignerInfoCount (signedData);
327 dtprintf("numberOfSigners : %d\n", numberOfSigners);
328 int ix;
329 for (ix=0;ix < numberOfSigners;ix++)
330 {
331 SecCmsSignerInfoRef sigi = SecCmsSignedDataGetSignerInfo(signedData,ix);
332 if (sigi)
333 {
334 CFStringRef commonName = SecCmsSignerInfoGetSignerCommonName(sigi);
335 const char *signerhdr = " signer : ";
336 if (commonName)
337 {
338 char *cn = cfStringToChar(commonName);
339 dtprintf("%s%s\n", signerhdr, cn);
340 if (cn)
341 free(cn);
342 CFReleaseNull(commonName);
343 }
344 else
345 dtprintf("%s<NULL>\n", signerhdr);
346 }
347 }
348 #endif
349 }
350
351 static void debugShowContentTypeOID(SecCmsContentInfoRef contentInfo)
352 {
353 #ifndef NDEBUG
354
355 CSSM_OID *typeOID = SecCmsContentInfoGetContentTypeOID(contentInfo);
356 if (typeOID)
357 {
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);
362 if (oidCFStr)
363 CFRelease(oidCFStr);
364 if (oidstr)
365 free(oidstr);
366 }
367 #endif
368 }
369
370 uint64_t tsaDER_ToInt(const CSSM_DATA *DER_Data)
371 {
372 uint64_t rtn = 0;
373 unsigned i = 0;
374
375 while(i < DER_Data->Length) {
376 rtn |= DER_Data->Data[i];
377 if(++i == DER_Data->Length) {
378 break;
379 }
380 rtn <<= 8;
381 }
382 return rtn;
383 }
384
385 void displayTSTInfo(SecAsn1TSATSTInfo *tstInfo)
386 {
387 #ifndef NDEBUG
388 dtprintf("--- TSTInfo ---\n");
389 if (!tstInfo)
390 return;
391
392 if (tstInfo->version.Data)
393 {
394 uint64_t vers = tsaDER_ToInt(&tstInfo->version);
395 dtprintf("Version:\t\t%u\n", (int)vers);
396 }
397
398 if (tstInfo->serialNumber.Data)
399 {
400 uint64_t sn = tsaDER_ToInt(&tstInfo->serialNumber);
401 dtprintf("SerialNumber:\t%llu\n", sn);
402 }
403
404 if (tstInfo->ordering.Data)
405 {
406 uint64_t ord = tsaDER_ToInt(&tstInfo->ordering);
407 dtprintf("Ordering:\t\t%s\n", ord?"yes":"no");
408 }
409
410 if (tstInfo->nonce.Data)
411 {
412 uint64_t nonce = tsaDER_ToInt(&tstInfo->nonce);
413 dtprintf("Nonce:\t\t%llu\n", nonce);
414 }
415 else
416 dtprintf("Nonce:\t\tnot specified\n");
417
418 if (tstInfo->genTime.Data)
419 {
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);
424 }
425
426 dtprintf("-- MessageImprint --\n");
427 if (true) // SecAsn1TSAMessageImprint
428 {
429 printDataAsHex(" Algorithm:",&tstInfo->messageImprint.hashAlgorithm.algorithm, 0);
430 printDataAsHex(" Message :", &tstInfo->messageImprint.hashedMessage, 0);//tstInfo->messageImprint.hashedMessage.Length);
431 }
432 #endif
433 }
434
435 #pragma mark ----- TimeStamp Response using XPC -----
436
437 #include <xpc/private.h>
438
439 static OSStatus checkForNonDERResponse(const unsigned char *resp, size_t respLen)
440 {
441 /*
442 Good start is something like 30 82 0c 03 30 15 02 01 00 30 10 0c 0e 4f 70 65
443
444 URL: http://timestamp-int.corp.apple.com/signserver/process?TimeStampSigner
445 Resp: Http/1.1 Service Unavailable
446
447 URL: http://timestamp-int.corp.apple.com/ts01
448 Resp: blank
449
450 URL: http://cutandtaste.com/404 (or other forced 404 site)
451 Resp: 404
452 */
453
454 OSStatus status = noErr;
455 const char ader[2] = { 0x30, 0x82 };
456 char *respStr = NULL;
457 size_t maxlen = 0;
458 size_t badResponseCount;
459
460 const char *badResponses[] =
461 {
462 "<!DOCTYPE html>",
463 "Http/1.1 Service Unavailable",
464 "blank"
465 };
466
467 require_action(resp && respLen, xit, status = errSecTimestampServiceNotAvailable);
468
469 // This is usual case
470 if ((respLen > 1) && (memcmp(resp, ader, 2)==0)) // might be good; pass on to DER decoder
471 return noErr;
472
473 badResponseCount = sizeof(badResponses)/sizeof(char *);
474 int ix;
475 for (ix = 0; ix < badResponseCount; ++ix)
476 if (strlen(badResponses[ix]) > maxlen)
477 maxlen = strlen(badResponses[ix]);
478
479 // Prevent a large response from allocating a ton of memory
480 if (respLen > maxlen)
481 respLen = maxlen;
482
483 respStr = (char *)malloc(respLen+1);
484 strlcpy(respStr, (const char *)resp, respLen);
485
486 for (ix = 0; ix < badResponseCount; ++ix)
487 if (strcmp(respStr, badResponses[ix])==0)
488 return errSecTimestampServiceNotAvailable;
489
490 xit:
491 if (respStr)
492 free((void *)respStr);
493
494 return status;
495 }
496
497 static OSStatus sendTSARequestWithXPC(const unsigned char *tsaReq, size_t tsaReqLength, const unsigned char *tsaURL, unsigned char **tsaResp, size_t *tsaRespLength)
498 {
499 __block OSStatus result = noErr;
500 int timeoutInSeconds = 15;
501 extern xpc_object_t xpc_create_with_format(const char * format, ...);
502
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);
506
507 xpc_connection_t con = xpc_connection_create("com.apple.security.XPCTimeStampingService", xpc_queue);
508
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)); }
513 else
514 { tsaDebug("default: unexpected connection event %p\n", event); }
515 });
516
517 xpc_connection_resume(con);
518
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);
522
523 xpc_object_t message = xpc_create_with_format("{operation: TimeStampRequest, ServerURL: %value, TimeStampRequest: %value}", url_as_xpc_string, tsaReqData);
524
525 xpc_connection_send_message_with_reply(con, message, xpc_queue, ^(xpc_object_t reply)
526 {
527 tsaDebug("xpc_connection_send_message_with_reply handler called back\n");
528 dispatch_retain_safe(waitSemaphore);
529
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)
536 {
537 #ifndef NDEBUG
538 /*
539 // This is useful for debugging.
540 char *debug = xpc_copy_description(reply);
541 tsaDebug("DEBUG %s\n", debug);
542 free(debug);
543 */
544 #endif
545
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);
549
550 xpc_object_t xpcTimeStampError = xpc_dictionary_get_value(reply, "TimeStampError");
551 xpc_object_t xpcTimeStampStatus = xpc_dictionary_get_value(reply, "TimeStampStatus");
552
553 if (xpcTimeStampError || xpcTimeStampStatus)
554 {
555 #ifndef NDEBUG
556 if (xpcTimeStampError)
557 {
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);
562 if (buf)
563 free(buf);
564 }
565 #endif
566 if (xpcTimeStampStatus)
567 {
568 result = (OSStatus)xpc_int64_get_value(xpcTimeStampStatus);
569 tsaDebug("xpcTimeStampStatus: %d\n", (int)result);
570 }
571 }
572
573 result = remapHTTPErrorCodes(result);
574
575 if ((result == noErr) && tsaResp && tsaRespLength)
576 {
577 *tsaRespLength = xpcTSRLength;
578 *tsaResp = (unsigned char *)malloc(xpcTSRLength);
579
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); }
583 else
584 if ((result = checkForNonDERResponse(*tsaResp,bytesCopied)))
585 {
586 tsaDebug("received non-DER response from timestamp server\n");
587 }
588 else
589 {
590 result = noErr;
591 tsaDebug("copied: %ld bytes of response\n", bytesCopied);
592 }
593 }
594 tsaDebug("releasing connection\n");
595 xpc_release(con);
596 }
597 else
598 { tsaDebug("unexpected message reply type %p\n", xtype); }
599 if (waitSemaphore) { dispatch_semaphore_signal(waitSemaphore); }
600 dispatch_release_null(waitSemaphore);
601 });
602 { tsaDebug("waiting up to %d seconds for response from XPC\n", timeoutInSeconds); }
603 if (waitSemaphore) { dispatch_semaphore_wait(waitSemaphore, finishTime); }
604
605 dispatch_release_null(waitSemaphore);
606 xpc_release(tsaReqData);
607 xpc_release(message);
608
609 { tsaDebug("sendTSARequestWithXPC exit\n"); }
610
611 return result;
612 }
613
614 #pragma mark ----- TimeStamp request -----
615
616 #include "tsaTemplates.h"
617 #include <security_asn1/SecAsn1Coder.h>
618 #include <Security/oidsalg.h>
619 #include <AssertMacros.h>
620 #include <libkern/OSByteOrder.h>
621
622 extern const SecAsn1Template kSecAsn1TSATimeStampReqTemplate;
623 extern const SecAsn1Template kSecAsn1TSATimeStampRespTemplateDER;
624
625 CFMutableDictionaryRef SecCmsTSAGetDefaultContext(CFErrorRef *error)
626 {
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
630
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;
640
641 require_action(secFWbundle = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.security")), xit, status = errSecInternalError);
642 CFRetain(secFWbundle);
643
644 require_action(resourceURL = CFBundleCopyResourceURL(secFWbundle, CFSTR("TimeStampingPrefs"), CFSTR("plist"), NULL),
645 xit, status = errSecInvalidPrefsDomain);
646
647 require(CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, resourceURL, &resourceData,
648 NULL, NULL, &errorCode), xit);
649 require_action(resourceData, xit, status = errSecDataNotAvailable);
650
651 prefs = CFPropertyListCreateWithData(kCFAllocatorDefault, resourceData, options, &format, error);
652 require_action(prefs && (CFGetTypeID(prefs)==CFDictionaryGetTypeID()), xit, status = errSecInvalidPrefsDomain);
653
654 contextDict = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, prefs);
655
656 if (error)
657 *error = NULL;
658 xit:
659 if (errorCode)
660 status = errorCode;
661 if (error && status)
662 *error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainOSStatus, status, NULL);
663 if (secFWbundle)
664 CFRelease(secFWbundle);
665 if (resourceURL)
666 CFRelease(resourceURL);
667 if (resourceData)
668 CFRelease(resourceData);
669 if (prefs)
670 CFRelease(prefs);
671
672 return contextDict;
673 }
674
675 static CFDataRef _SecTSARequestCopyDEREncoding(SecAsn1TSAMessageImprint *messageImprint, bool noCerts, uint64_t nonce)
676 {
677 // Returns DER encoded TimeStampReq
678 // Modeled on _SecOCSPRequestCopyDEREncoding
679 // The Timestamp Authority supports 64 bit nonces (or more possibly)
680
681 SecAsn1CoderRef coder = NULL;
682 uint8_t version = 1;
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};
690
691 uint8_t OID_FakePolicy_Data[] = { 0x2A, 0x03, 0x04, 0x05, 0x06};
692 const CSSM_OID fakePolicyOID = {sizeof(OID_FakePolicy_Data),OID_FakePolicy_Data};
693
694 tsreq.version = vers;
695
696 tsreq.messageImprint = *messageImprint;
697 tsreq.certReq = certReq;
698
699 // skip reqPolicy, extensions for now - FAKES - jch
700 tsreq.reqPolicy = fakePolicyOID; //policyID;
701
702 tsreq.nonce = nonceItem;
703
704 // Encode the request
705 require_noerr(SecAsn1CoderCreate(&coder), errOut);
706
707 SecAsn1Item encoded;
708 require_noerr(SecAsn1EncodeItem(coder, &tsreq,
709 &kSecAsn1TSATimeStampReqTemplate, &encoded), errOut);
710 der = CFDataCreate(kCFAllocatorDefault, encoded.Data,
711 encoded.Length);
712
713 errOut:
714 if (coder)
715 SecAsn1CoderRelease(coder);
716
717 return der;
718 }
719
720 OSStatus SecTSAResponseCopyDEREncoding(SecAsn1CoderRef coder, const CSSM_DATA *tsaResponse, SecAsn1TimeStampRespDER *respDER)
721 {
722 // Partially decode the response
723 OSStatus status = paramErr;
724
725 require(tsaResponse && respDER, errOut);
726 require_noerr(SecAsn1DecodeData(coder, tsaResponse,
727 &kSecAsn1TSATimeStampRespTemplateDER, respDER), errOut);
728 status = noErr;
729
730 errOut:
731
732 return status;
733 }
734
735 #pragma mark ----- TS Callback -----
736
737 OSStatus SecCmsTSADefaultCallback(CFTypeRef context, void *messageImprintV, uint64_t nonce, CSSM_DATA *signedDERBlob)
738 {
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;
745
746 if (!context || CFGetTypeID(context)!=CFDictionaryGetTypeID())
747 return paramErr;
748
749 SecAsn1TSAMessageImprint *messageImprint = (SecAsn1TSAMessageImprint *)messageImprintV;
750 if (!messageImprint || !signedDERBlob)
751 return paramErr;
752
753 CFBooleanRef cfnocerts = (CFBooleanRef)CFDictionaryGetValue((CFDictionaryRef)context, kTSAContextKeyNoCerts);
754 if (cfnocerts)
755 {
756 tsaDebug("[TSA] Request noCerts\n");
757 noCerts = CFBooleanGetValue(cfnocerts);
758 }
759
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))
764 {
765 tsaDebug("[TSA] Forcing bad TS Request by changing nonce\n");
766 nonce++;
767 }
768
769 printDataAsHex("[TSA] hashToTimeStamp:", &messageImprint->hashedMessage,128);
770 cfreq = _SecTSARequestCopyDEREncoding(messageImprint, noCerts, nonce);
771 if (cfreq)
772 {
773 tsaReq = CFDataGetBytePtr(cfreq);
774 tsaReqLength = CFDataGetLength(cfreq);
775
776 #ifndef NDEBUG
777 CFShow(cfreq);
778 tsaWriteFileX("/tmp/tsareq.req", tsaReq, tsaReqLength);
779 #endif
780 }
781
782 CFTypeRef url = CFDictionaryGetValue((CFDictionaryRef)context, kTSAContextKeyURL);
783 if (!url)
784 {
785 tsaDebug("[TSA] missing URL for TSA (key: %s)\n", "kTSAContextKeyURL");
786 goto xit;
787 }
788
789 CFStringRef urlStr = NULL;
790 if (CFURLGetTypeID() == CFGetTypeID(url)) {
791 urlStr = CFURLGetString(url);
792 } else {
793 require_quiet(CFStringGetTypeID() == CFGetTypeID(url), xit);
794 urlStr = url;
795 }
796 require_quiet(urlStr, xit);
797
798 /*
799 If debugging, look at special values in the context to mess things up
800 */
801
802 CFBooleanRef cfBadReq = (CFBooleanRef)CFDictionaryGetValue((CFDictionaryRef)context, kTSADebugContextKeyBadReq);
803 if (cfBadReq && CFBooleanGetValue(cfBadReq))
804 {
805 tsaDebug("[TSA] Forcing bad TS Request by truncating length from %ld to %ld\n", tsaReqLength, (tsaReqLength-4));
806 tsaReqLength -= 4;
807 }
808
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))
813 goto xit;
814
815 tsaDebug("[TSA] URL for timestamp server: %s\n", tsaURL);
816
817 unsigned char *tsaResp = NULL;
818 size_t tsaRespLength = 0;
819 tsaDebug("calling sendTSARequestWithXPC with %ld bytes of request\n", tsaReqLength);
820
821 require_noerr(result = sendTSARequestWithXPC(tsaReq, tsaReqLength, tsaURL, &tsaResp, &tsaRespLength), xit);
822
823 tsaDebug("sendTSARequestWithXPC copied: %ld bytes of response\n", tsaRespLength);
824
825 signedDERBlob->Data = tsaResp;
826 signedDERBlob->Length = tsaRespLength;
827
828 result = noErr;
829
830 xit:
831 if (tsaURL)
832 free((void *)tsaURL);
833 if (cfreq)
834 CFRelease(cfreq);
835
836 return result;
837 }
838
839 #pragma mark ----- TimeStamp Verification -----
840
841 static OSStatus convertGeneralizedTimeToCFAbsoluteTime(const char *timeStr, CFAbsoluteTime *ptime)
842 {
843 /*
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.
847 */
848
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;
855
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);
862
863 time_string = CFStringCreateWithCString(kCFAllocatorDefault, timeStr, kCFStringEncodingUTF8);
864 if (!time_string || !CFDateFormatterGetAbsoluteTimeFromString(formatter, time_string, rangep, ptime))
865 {
866 dtprintf("%s is not a valid date\n", timeStr);
867 result = 1;
868 }
869
870 xit:
871 if (formatter)
872 CFRelease(formatter);
873 if (time_string)
874 CFRelease(time_string);
875 if (gmt)
876 CFRelease(gmt);
877
878 return result;
879 }
880
881 static OSStatus SecTSAValidateTimestamp(const SecAsn1TSATSTInfo *tstInfo, CSSM_DATA **signingCerts, CFAbsoluteTime *timestampTime)
882 {
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;
888
889 require(tstInfo && signingCerts && (tstInfo->genTime.Length < 16), xit);
890
891 // Find the leaf signingCert
892 require_noerr(result = SecCertificateCreateFromData(*signingCerts,
893 CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, &signingCertificate), xit);
894
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?
899 result = noErr;
900 else
901 result = errSecTimestampInvalid;
902 if (timestampTime)
903 *timestampTime = genTime;
904 xit:
905 if (signingCertificate)
906 CFReleaseNull(signingCertificate);
907 return result;
908 }
909
910 static OSStatus verifyTSTInfo(const CSSM_DATA_PTR content, CSSM_DATA **signingCerts, SecAsn1TSATSTInfo *tstInfo, CFAbsoluteTime *timestampTime, uint64_t expectedNonce)
911 {
912 OSStatus status = paramErr;
913 SecAsn1CoderRef coder = NULL;
914
915 if (!tstInfo)
916 return SECFailure;
917
918 require_noerr(SecAsn1CoderCreate(&coder), xit);
919 require_noerr(SecAsn1Decode(coder, content->Data, content->Length,
920 kSecAsn1TSATSTInfoTemplate, tstInfo), xit);
921 displayTSTInfo(tstInfo);
922
923 // Check the nonce
924 if (tstInfo->nonce.Data && expectedNonce!=0)
925 {
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);
930 }
931
932 status = SecTSAValidateTimestamp(tstInfo, signingCerts, timestampTime);
933 dtprintf("SecTSAValidateTimestamp result: %ld\n", (long)status);
934
935 xit:
936 if (coder)
937 SecAsn1CoderRelease(coder);
938 return status;
939 }
940
941 static void debugShowExtendedTrustResult(int index, CFDictionaryRef extendedResult)
942 {
943 #ifndef NDEBUG
944 if (extendedResult)
945 {
946 CFStringRef xresStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
947 CFSTR("Extended trust result for signer #%d : %@"), index, extendedResult);
948 if (xresStr)
949 {
950 CFShow(xresStr);
951 CFRelease(xresStr);
952 }
953 }
954 #endif
955 }
956
957 #ifndef NDEBUG
958 extern const char *cssmErrorString(CSSM_RETURN error);
959
960 static void statusBitTest(CSSM_TP_APPLE_CERT_STATUS certStatus, uint32 bit, const char *str)
961 {
962 if (certStatus & bit)
963 dtprintf("%s ", str);
964 }
965 #endif
966
967 static void debugShowCertEvidenceInfo(uint16_t certCount, const CSSM_TP_APPLE_EVIDENCE_INFO *info)
968 {
969 #ifndef NDEBUG
970 CSSM_TP_APPLE_CERT_STATUS cs;
971 // const CSSM_TP_APPLE_EVIDENCE_INFO *pinfo = info;
972 uint16_t ix;
973 for (ix=0; info && (ix<certCount); ix++, ++info)
974 {
975 cs = info->StatusBits;
976 dtprintf(" cert %u:\n", ix);
977 dtprintf(" StatusBits : 0x%x", (unsigned)cs);
978 if (cs)
979 {
980 dtprintf(" ( ");
981 statusBitTest(cs, CSSM_CERT_STATUS_EXPIRED, "EXPIRED");
982 statusBitTest(cs, CSSM_CERT_STATUS_NOT_VALID_YET,
983 "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,
987 "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");
990 dtprintf(")\n");
991 }
992 else
993 dtprintf("\n");
994
995 dtprintf(" NumStatusCodes : %u ", info->NumStatusCodes);
996 CSSM_RETURN *pstatuscode = info->StatusCodes;
997 uint16_t jx;
998 for (jx=0; pstatuscode && (jx<info->NumStatusCodes); jx++, ++pstatuscode)
999 dtprintf("%s ", cssmErrorString(*pstatuscode));
1000
1001 dtprintf("\n");
1002 dtprintf(" Index: %u\n", info->Index);
1003 }
1004
1005 #endif
1006 }
1007
1008 #ifndef NDEBUG
1009 static const char *trustResultTypeString(SecTrustResultType trustResultType)
1010 {
1011 switch (trustResultType)
1012 {
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";
1022 }
1023 return "";
1024 }
1025 #endif
1026
1027 static OSStatus verifySigners(SecCmsSignedDataRef signedData, int numberOfSigners, CFTypeRef timeStampPolicy)
1028 {
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
1031
1032 SecTrustRef trustRef = NULL;
1033 CFTypeRef policy = CFRetainSafe(timeStampPolicy);
1034 int result=errSecInternalError;
1035 int rx;
1036
1037 if (!policy) {
1038 require(policy = SecPolicyCreateWithOID(kSecPolicyAppleTimeStamping), xit);
1039 }
1040
1041 int jx;
1042 for (jx = 0; jx < numberOfSigners; ++jx)
1043 {
1044 SecTrustResultType trustResultType;
1045 CFDictionaryRef extendedResult = NULL;
1046 CFArrayRef certChain = NULL;
1047 uint16_t certCount = 0;
1048
1049 CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL;
1050
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);
1057
1058 result = SecTrustEvaluate (trustRef, &trustResultType);
1059 dtprintf("[%s] SecTrustEvaluate: result: %d, trustResult: %s (%d)\n",
1060 __FUNCTION__, result, trustResultTypeString(trustResultType), trustResultType);
1061 if (result)
1062 goto xit;
1063 switch (trustResultType)
1064 {
1065 case kSecTrustResultProceed:
1066 case kSecTrustResultUnspecified:
1067 break; // success
1068 case kSecTrustResultDeny: // user reject
1069 result = errSecTimestampNotTrusted; // SecCmsVSTimestampNotTrusted ?
1070 break;
1071 case kSecTrustResultInvalid:
1072 assert(false); // should never happen
1073 result = errSecTimestampNotTrusted; // SecCmsVSTimestampNotTrusted ?
1074 break;
1075 case kSecTrustResultConfirm:
1076 case kSecTrustResultRecoverableTrustFailure:
1077 case kSecTrustResultFatalTrustFailure:
1078 case kSecTrustResultOtherError:
1079 default:
1080 {
1081 /*
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.
1088 */
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;
1092 }
1093 break;
1094 }
1095
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);
1101
1102 rx = SecTrustCopyExtendedResult(trustRef, &extendedResult);
1103 dtprintf("[%s] SecTrustCopyExtendedResult: result: %d\n", __FUNCTION__, rx);
1104 if (extendedResult)
1105 {
1106 debugShowExtendedTrustResult(jx, extendedResult);
1107 CFRelease(extendedResult);
1108 }
1109
1110 if (trustRef)
1111 CFReleaseNull(trustRef);
1112 }
1113
1114 xit:
1115 if (trustRef)
1116 CFReleaseNull(trustRef);
1117 if (policy)
1118 CFRelease(policy);
1119 return result;
1120 }
1121
1122 static OSStatus impExpImportCertUnCommon(
1123 const CSSM_DATA *cdata,
1124 SecKeychainRef importKeychain, // optional
1125 CFMutableArrayRef outArray) // optional, append here
1126 {
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;
1131
1132 require_action(cdata, xit, status = errSecUnsupportedFormat);
1133
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);
1137
1138 certRef = SecCertificateCreateWithData(kCFAllocatorDefault, data);
1139 CFRelease(data); /* certRef has its own copy of the data now */
1140 if(!certRef) {
1141 dtprintf("impExpHandleCert error\n");
1142 return errSecUnsupportedFormat;
1143 }
1144
1145 if (outArray)
1146 CFArrayAppendValue(outArray, certRef);
1147
1148 if (importKeychain)
1149 {
1150 status = SecCertificateAddToKeychain(certRef, importKeychain);
1151 if (status!=noErr && status!=errSecDuplicateItem)
1152 { dtprintf("SecCertificateAddToKeychain error: %ld\n", (long)status); }
1153 }
1154
1155 xit:
1156 if (certRef)
1157 CFRelease(certRef);
1158 return status;
1159 }
1160
1161 static void saveTSACertificates(CSSM_DATA **signingCerts, CFMutableArrayRef outArray)
1162 {
1163 SecKeychainRef defaultKeychain = NULL;
1164 // Don't save certificates in keychain to avoid securityd issues
1165 // if (SecKeychainCopyDefault(&defaultKeychain))
1166 // defaultKeychain = NULL;
1167
1168 unsigned certCount = SecCmsArrayCount((void **)signingCerts);
1169 unsigned dex;
1170 for (dex=0; dex<certCount; dex++)
1171 {
1172 OSStatus rx = impExpImportCertUnCommon(signingCerts[dex], defaultKeychain, outArray);
1173 if (rx!=noErr && rx!=errSecDuplicateItem)
1174 dtprintf("impExpImportCertCommon failed: %ld\n", (long)rx);
1175 }
1176 if (defaultKeychain)
1177 CFRelease(defaultKeychain);
1178 }
1179
1180 static const char *cfabsoluteTimeToString(CFAbsoluteTime abstime)
1181 {
1182 CFGregorianDate greg = CFAbsoluteTimeGetGregorianDate(abstime, NULL);
1183 char str[20];
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))
1186 str[0]=0;
1187 char *data = (char *)malloc(20);
1188 strncpy(data, str, 20);
1189 return data;
1190 }
1191
1192 static OSStatus setTSALeafValidityDates(SecCmsSignerInfoRef signerinfo)
1193 {
1194 OSStatus status = noErr;
1195
1196 if (!signerinfo->timestampCertList || (CFArrayGetCount(signerinfo->timestampCertList) == 0))
1197 return SecCmsVSSigningCertNotFound;
1198
1199 SecCertificateRef tsaLeaf = (SecCertificateRef)CFArrayGetValueAtIndex(signerinfo->timestampCertList, 0);
1200 require_action(tsaLeaf, xit, status = errSecCertificateCannotOperate);
1201
1202 signerinfo->tsaLeafNotBefore = SecCertificateNotValidBefore(tsaLeaf); /* Start date for Timestamp Authority leaf */
1203 signerinfo->tsaLeafNotAfter = SecCertificateNotValidAfter(tsaLeaf); /* Expiration date for Timestamp Authority leaf */
1204
1205 const char *nbefore = cfabsoluteTimeToString(signerinfo->tsaLeafNotBefore);
1206 const char *nafter = cfabsoluteTimeToString(signerinfo->tsaLeafNotAfter);
1207 if (nbefore && nafter)
1208 {
1209 dtprintf("Timestamp Authority leaf valid from %s to %s\n", nbefore, nafter);
1210 free((void *)nbefore);free((void *)nafter);
1211 }
1212
1213 /*
1214 if(at < nb)
1215 status = errSecCertificateNotValidYet;
1216 else if (at > na)
1217 status = errSecCertificateExpired;
1218 */
1219
1220 xit:
1221 return status;
1222 }
1223
1224 /*
1225 From RFC 3161: Time-Stamp Protocol (TSP),August 2001, APPENDIX B:
1226
1227 B) The validity of the digital signature may then be verified in the
1228 following way:
1229
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.
1232
1233 2) The date/time indicated by the TSA in the TimeStampToken
1234 MUST be retrieved.
1235
1236 3) The certificate used by the signer MUST be identified and
1237 retrieved.
1238
1239 4) The date/time indicated by the TSA MUST be within the
1240 validity period of the signer's certificate.
1241
1242 5) The revocation information about that certificate, at the
1243 date/time of the Time-Stamping operation, MUST be retrieved.
1244
1245 6) Should the certificate be revoked, then the date/time of
1246 revocation shall be later than the date/time indicated by
1247 the TSA.
1248
1249 If all these conditions are successful, then the digital signature
1250 shall be declared as valid.
1251
1252 */
1253
1254 OSStatus decodeTimeStampToken(SecCmsSignerInfoRef signerinfo, CSSM_DATA_PTR inData, CSSM_DATA_PTR encDigest, uint64_t expectedNonce)
1255 {
1256 return decodeTimeStampTokenWithPolicy(signerinfo, NULL, inData, encDigest, expectedNonce);
1257 }
1258
1259 OSStatus decodeTimeStampTokenWithPolicy(SecCmsSignerInfoRef signerinfo, CFTypeRef timeStampPolicy, CSSM_DATA_PTR inData, CSSM_DATA_PTR encDigest, uint64_t expectedNonce)
1260 {
1261 /*
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
1265
1266 These are set in signerinfo as side effects:
1267 timestampTime -
1268 timestampCertList
1269 */
1270
1271 SecCmsDecoderRef decoderContext = NULL;
1272 SecCmsMessageRef cmsMessage = NULL;
1273 SecCmsContentInfoRef contentInfo;
1274 SecCmsSignedDataRef signedData;
1275 SECOidTag contentTypeTag;
1276 int contentLevelCount;
1277 int ix;
1278 OSStatus result = errSecUnknownFormat;
1279 CSSM_DATA **signingCerts = NULL;
1280
1281 dtprintf("decodeTimeStampToken top: PORT_GetError() %d -----\n", PORT_GetError());
1282 PORT_SetError(0);
1283
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);
1287 if (result)
1288 {
1289 result = errSecTimestampInvalid;
1290 SecCmsDecoderDestroy(decoderContext);
1291 goto xit;
1292 }
1293
1294 require_noerr(result = SecCmsDecoderFinish(decoderContext, &cmsMessage), xit);
1295
1296 // process the results
1297 contentLevelCount = SecCmsMessageContentLevelCount(cmsMessage);
1298
1299 if (encDigest)
1300 printDataAsHex("encDigest",encDigest, 0);
1301
1302 for (ix = 0; ix < contentLevelCount; ++ix)
1303 {
1304 dtprintf("\n----- Content Level %d -----\n", ix);
1305 // get content information
1306 contentInfo = SecCmsMessageContentLevel (cmsMessage, ix);
1307 contentTypeTag = SecCmsContentInfoGetContentTypeTag (contentInfo);
1308
1309 // After 2nd round, contentInfo.content.data is the TSTInfo
1310
1311 debugShowContentTypeOID(contentInfo);
1312
1313 switch (contentTypeTag)
1314 {
1315 case SEC_OID_PKCS7_SIGNED_DATA:
1316 {
1317 require((signedData = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(contentInfo)) != NULL, xit);
1318
1319 debugShowSignerInfo(signedData);
1320
1321 SECAlgorithmID **digestAlgorithms = SecCmsSignedDataGetDigestAlgs(signedData);
1322 unsigned digestAlgCount = SecCmsArrayCount((void **)digestAlgorithms);
1323 dtprintf("digestAlgCount: %d\n", digestAlgCount);
1324 if (signedData->digests)
1325 {
1326 int jx;
1327 char buffer[128];
1328 for (jx=0;jx < digestAlgCount;jx++)
1329 {
1330 sprintf(buffer, " digest[%u]", jx);
1331 printDataAsHex(buffer,signedData->digests[jx], 0);
1332 }
1333 }
1334 else
1335 {
1336 dtprintf("No digests\n");
1337 CSSM_DATA_PTR innerContent = SecCmsContentInfoGetInnerContent(contentInfo);
1338 if (innerContent)
1339 {
1340 dtprintf("inner content length: %ld\n", innerContent->Length);
1341 SecAsn1TSAMessageImprint fakeMessageImprint = {{{0}},};
1342 OSStatus status = createTSAMessageImprint(signedData, innerContent, &fakeMessageImprint);
1343 if (status)
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);
1349 }
1350 else
1351 dtprintf("no inner content\n");
1352 }
1353
1354 /*
1355 Import the certificates. We leave this as a warning, since
1356 there are configurations where the certificates are not returned.
1357 */
1358 signingCerts = SecCmsSignedDataGetCertificateList(signedData);
1359 if (signingCerts == NULL)
1360 { dtprintf("SecCmsSignedDataGetCertificateList returned NULL\n"); }
1361 else
1362 {
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);
1368 }
1369
1370 int numberOfSigners = SecCmsSignedDataSignerInfoCount (signedData);
1371
1372 result = verifySigners(signedData, numberOfSigners, timeStampPolicy);
1373 if (result)
1374 dtprintf("verifySigners failed: %ld\n", (long)result); // warning
1375
1376
1377 if (result) // remap to SecCmsVSTimestampNotTrusted ?
1378 goto xit;
1379
1380 break;
1381 }
1382 case SEC_OID_PKCS9_SIGNING_CERTIFICATE:
1383 {
1384 dtprintf("SEC_OID_PKCS9_SIGNING_CERTIFICATE seen\n");
1385 break;
1386 }
1387
1388 case SEC_OID_PKCS9_ID_CT_TSTInfo:
1389 {
1390 SecAsn1TSATSTInfo tstInfo = {{0},};
1391 result = verifyTSTInfo(contentInfo->rawContent, signingCerts, &tstInfo, &signerinfo->timestampTime, expectedNonce);
1392 if (signerinfo->timestampTime)
1393 {
1394 const char *tstamp = cfabsoluteTimeToString(signerinfo->timestampTime);
1395 if (tstamp)
1396 {
1397 dtprintf("Timestamp Authority timestamp: %s\n", tstamp);
1398 free((void *)tstamp);
1399 }
1400 }
1401 break;
1402 }
1403 case SEC_OID_OTHER:
1404 {
1405 dtprintf("otherContent : %p\n", (char *)SecCmsContentInfoGetContent (contentInfo));
1406 break;
1407 }
1408 default:
1409 dtprintf("ContentTypeTag : %x\n", contentTypeTag);
1410 break;
1411 }
1412 }
1413 xit:
1414 if (cmsMessage)
1415 SecCmsMessageDestroy(cmsMessage);
1416
1417 return result;
1418 }
1419
1420