1/* 2 * Copyright (c) 2012 Apple Computer, 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 51#include "tsaSupport.h" 52#include "tsaSupportPriv.h" 53#include "tsaTemplates.h" 54#include "cmslocal.h" 55 56#include "secoid.h" 57#include "secitem.h" 58#include <fcntl.h> 59 60const CFStringRef kTSAContextKeyURL = CFSTR("ServerURL"); 61const CFStringRef kTSAContextKeyNoCerts = CFSTR("NoCerts"); 62const CFStringRef kTSADebugContextKeyBadReq = CFSTR("DebugBadReq"); 63const CFStringRef kTSADebugContextKeyBadNonce = CFSTR("DebugBadNonce"); 64 65extern const SecAsn1Template kSecAsn1TSATSTInfoTemplate[]; 66 67extern OSStatus impExpImportCertCommon( 68 const CSSM_DATA *cdata, 69 SecKeychainRef importKeychain, // optional 70 CFMutableArrayRef outArray); // optional, append here 71 72#pragma mark ----- Debug Logs ----- 73 74#ifndef NDEBUG 75#define TSA_USE_SYSLOG 1 76#endif 77 78#if TSA_USE_SYSLOG 79#include <syslog.h> 80 #include <time.h> 81 #include <sys/time.h> 82 #define tsaDebug(fmt, ...) \ 83 do { if (true) { \ 84 char buf[64]; \ 85 struct timeval time_now; \ 86 gettimeofday(&time_now, NULL); \ 87 struct tm* time_info = localtime(&time_now.tv_sec); \ 88 strftime(buf, sizeof(buf), "[%Y-%m-%d %H:%M:%S]", time_info); \ 89 fprintf(stderr, "%s " fmt, buf, ## __VA_ARGS__); \ 90 syslog(LOG_ERR, " " fmt, ## __VA_ARGS__); \ 91 } } while (0) 92 #define tsa_secdebug(scope, format...) \ 93 { \ 94 syslog(LOG_NOTICE, format); \ 95 secdebug(scope, format); \ 96 printf(format); \ 97 } 98#else 99 #define tsaDebug(args...) tsa_secdebug("tsa", ## args) 100#define tsa_secdebug(scope, format...) \ 101 secdebug(scope, format) 102#endif 103 104#ifndef NDEBUG 105#define TSTINFO_DEBUG 1 //jch 106#endif 107 108#if TSTINFO_DEBUG 109#define dtprintf(args...) tsaDebug(args) 110#else 111#define dtprintf(args...) 112#endif 113 114#define kHTTPResponseCodeContinue 100 115#define kHTTPResponseCodeOK 200 116#define kHTTPResponseCodeNoContent 204 117#define kHTTPResponseCodeBadRequest 400 118#define kHTTPResponseCodeUnauthorized 401 119#define kHTTPResponseCodeForbidden 403 120#define kHTTPResponseCodeNotFound 404 121#define kHTTPResponseCodeConflict 409 122#define kHTTPResponseCodeExpectationFailed 417 123#define kHTTPResponseCodeServFail 500 124#define kHTTPResponseCodeServiceUnavailable 503 125#define kHTTPResponseCodeInsufficientStorage 507 126 127#pragma mark ----- Debug/Utilities ----- 128 129static OSStatus remapHTTPErrorCodes(OSStatus status) 130{ 131 switch (status) 132 { 133 case kHTTPResponseCodeOK: 134 case kHTTPResponseCodeContinue: 135 return noErr; 136 case kHTTPResponseCodeBadRequest: 137 return errSecTimestampBadRequest; 138 case kHTTPResponseCodeNoContent: 139 case kHTTPResponseCodeUnauthorized: 140 case kHTTPResponseCodeForbidden: 141 case kHTTPResponseCodeNotFound: 142 case kHTTPResponseCodeConflict: 143 case kHTTPResponseCodeExpectationFailed: 144 case kHTTPResponseCodeServFail: 145 case kHTTPResponseCodeInsufficientStorage: 146 case kHTTPResponseCodeServiceUnavailable: 147 return errSecTimestampServiceNotAvailable; 148 default: 149 return status; 150 } 151 return status; 152 153} 154 155static void printDataAsHex(const char *title, const CSSM_DATA *d, unsigned maxToPrint) // 0 means print it all 156{ 157#ifndef NDEBUG 158 unsigned i; 159 bool more = false; 160 uint32 len = (uint32)d->Length; 161 uint8 *cp = d->Data; 162 char *buffer = NULL; 163 size_t bufferSize; 164 int offset, sz = 0; 165 const int wrapwid = 24; // large enough so SHA-1 hashes fit on one line... 166 167 if ((maxToPrint != 0) && (len > maxToPrint)) 168 { 169 len = maxToPrint; 170 more = true; 171 } 172 173 bufferSize = wrapwid+3*len; 174 buffer = (char *)malloc(bufferSize); 175 176 offset = sprintf(buffer, "%s [len = %u]\n", title, len); 177 dtprintf("%s", buffer); 178 offset = 0; 179 180 for (i=0; (i < len) && (offset+3 < bufferSize); i++, offset += sz) 181 { 182 sz = sprintf(buffer + offset, " %02x", (unsigned int)cp[i] & 0xff); 183 if ((i % wrapwid) == (wrapwid-1)) 184 { 185 dtprintf("%s", buffer); 186 offset = 0; 187 sz = 0; 188 } 189 } 190 191 sz=sprintf(buffer + offset, more?" ...\n":"\n"); 192 offset += sz; 193 buffer[offset+1]=0; 194 195// fprintf(stderr, "%s", buffer); 196 dtprintf("%s", buffer); 197#endif 198} 199 200#ifndef NDEBUG 201int tsaWriteFileX(const char *fileName, const unsigned char *bytes, size_t numBytes) 202{ 203 int rtn; 204 int fd; 205 206 fd = open(fileName, O_RDWR | O_CREAT | O_TRUNC, 0600); 207 if (fd <= 0) 208 return errno; 209 210 rtn = (int)write(fd, bytes, numBytes); 211 if(rtn != (int)numBytes) 212 { 213 if (rtn >= 0) 214 fprintf(stderr, "writeFile: short write\n"); 215 rtn = EIO; 216 } 217 else 218 rtn = 0; 219 220 close(fd); 221 return rtn; 222} 223#endif 224 225char *cfStringToChar(CFStringRef inStr) 226{ 227 // Caller must free 228 char *result = NULL; 229 const char *str = NULL; 230 231 if (!inStr) 232 return strdup(""); // return a null string 233 234 // quick path first 235 if ((str = CFStringGetCStringPtr(inStr, kCFStringEncodingUTF8))) { 236 result = strdup(str); 237 } else { 238 // need to extract into buffer 239 CFIndex length = CFStringGetLength(inStr); // in 16-bit character units 240 CFIndex bytesToAllocate = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1; 241 result = malloc(bytesToAllocate); 242 if (!CFStringGetCString(inStr, result, bytesToAllocate, kCFStringEncodingUTF8)) 243 result[0] = 0; 244 } 245 246 return result; 247} 248 249/* Oids longer than this are considered invalid. */ 250#define MAX_OID_SIZE 32 251 252#ifndef NDEBUG 253/* FIXME: There are other versions of this in SecCertifcate.c and SecCertificateP.c */ 254static CFStringRef SecDERItemCopyOIDDecimalRepresentation(CFAllocatorRef allocator, const CSSM_OID *oid) 255{ 256 if (oid->Length == 0) 257 return CFSTR("<NULL>"); 258 259 if (oid->Length > MAX_OID_SIZE) 260 return CFSTR("Oid too long"); 261 262 CFMutableStringRef result = CFStringCreateMutable(allocator, 0); 263 264 // The first two levels are encoded into one byte, since the root levelq 265 // has only 3 nodes (40*x + y). However if x = joint-iso-itu-t(2) then 266 // y may be > 39, so we have to add special-case handling for this. 267 uint32_t x = oid->Data[0] / 40; 268 uint32_t y = oid->Data[0] % 40; 269 if (x > 2) 270 { 271 // Handle special case for large y if x = 2 272 y += (x - 2) * 40; 273 x = 2; 274 } 275 CFStringAppendFormat(result, NULL, CFSTR("%u.%u"), x, y); 276 277 uint32_t value = 0; 278 for (x = 1; x < oid->Length; ++x) 279 { 280 value = (value << 7) | (oid->Data[x] & 0x7F); 281 /* @@@ value may not span more than 4 bytes. */ 282 /* A max number of 20 values is allowed. */ 283 if (!(oid->Data[x] & 0x80)) 284 { 285 CFStringAppendFormat(result, NULL, CFSTR(".%lu"), (unsigned long)value); 286 value = 0; 287 } 288 } 289 return result; 290} 291#endif 292 293static void debugSaveCertificates(CSSM_DATA **outCerts) 294{ 295#ifndef NDEBUG 296 if (outCerts) 297 { 298 CSSM_DATA_PTR *certp; 299 unsigned jx = 0; 300 const char *certNameBase = "/tmp/tsa-resp-cert-"; 301 char fname[PATH_MAX]; 302 unsigned certCount = SecCmsArrayCount((void **)outCerts); 303 dtprintf("Found %d certs\n",certCount); 304 305 for (certp=outCerts;*certp;certp++, ++jx) 306 { 307 char numstr[32]; 308 strncpy(fname, certNameBase, strlen(certNameBase)+1); 309 sprintf(numstr,"%u", jx); 310 strcat(fname,numstr); 311 tsaWriteFileX(fname, (*certp)->Data, (*certp)->Length); 312 if (jx > 5) 313 break; //something wrong 314 } 315 } 316#endif 317} 318 319static void debugShowSignerInfo(SecCmsSignedDataRef signedData) 320{ 321#ifndef NDEBUG 322 int numberOfSigners = SecCmsSignedDataSignerInfoCount (signedData); 323 dtprintf("numberOfSigners : %d\n", numberOfSigners); 324 int ix; 325 for (ix=0;ix < numberOfSigners;ix++) 326 { 327 SecCmsSignerInfoRef sigi = SecCmsSignedDataGetSignerInfo(signedData,ix); 328 if (sigi) 329 { 330 CFStringRef commonName = SecCmsSignerInfoGetSignerCommonName(sigi); 331 const char *signerhdr = " signer : "; 332 if (commonName) 333 { 334 char *cn = cfStringToChar(commonName); 335 dtprintf("%s%s\n", signerhdr, cn); 336 if (cn) 337 free(cn); 338 } 339 else 340 dtprintf("%s<NULL>\n", signerhdr); 341 } 342 } 343#endif 344} 345 346static void debugShowContentTypeOID(SecCmsContentInfoRef contentInfo) 347{ 348#ifndef NDEBUG 349 350 CSSM_OID *typeOID = SecCmsContentInfoGetContentTypeOID(contentInfo); 351 if (typeOID) 352 { 353 CFStringRef oidCFStr = SecDERItemCopyOIDDecimalRepresentation(kCFAllocatorDefault, typeOID); 354 char *oidstr = cfStringToChar(oidCFStr); 355 printDataAsHex("oid:", typeOID, (unsigned int)typeOID->Length); 356 dtprintf("\toid: %s\n", oidstr); 357 if (oidCFStr) 358 CFRelease(oidCFStr); 359 if (oidstr) 360 free(oidstr); 361 } 362#endif 363} 364 365uint64_t tsaDER_ToInt(const CSSM_DATA *DER_Data) 366{ 367 uint64_t rtn = 0; 368 unsigned i = 0; 369 370 while(i < DER_Data->Length) { 371 rtn |= DER_Data->Data[i]; 372 if(++i == DER_Data->Length) { 373 break; 374 } 375 rtn <<= 8; 376 } 377 return rtn; 378} 379 380void displayTSTInfo(SecAsn1TSATSTInfo *tstInfo) 381{ 382#ifndef NDEBUG 383 dtprintf("--- TSTInfo ---\n"); 384 if (!tstInfo) 385 return; 386 387 if (tstInfo->version.Data) 388 { 389 uint64_t vers = tsaDER_ToInt(&tstInfo->version); 390 dtprintf("Version:\t\t%u\n", (int)vers); 391 } 392 393 if (tstInfo->serialNumber.Data) 394 { 395 uint64_t sn = tsaDER_ToInt(&tstInfo->serialNumber); 396 dtprintf("SerialNumber:\t%llu\n", sn); 397 } 398 399 if (tstInfo->ordering.Data) 400 { 401 uint64_t ord = tsaDER_ToInt(&tstInfo->ordering); 402 dtprintf("Ordering:\t\t%s\n", ord?"yes":"no"); 403 } 404 405 if (tstInfo->nonce.Data) 406 { 407 uint64_t nonce = tsaDER_ToInt(&tstInfo->nonce); 408 dtprintf("Nonce:\t\t%llu\n", nonce); 409 } 410 else 411 dtprintf("Nonce:\t\tnot specified\n"); 412 413 if (tstInfo->genTime.Data) 414 { 415 char buf[tstInfo->genTime.Length+1]; 416 memcpy(buf, (const char *)tstInfo->genTime.Data, tstInfo->genTime.Length); 417 buf[tstInfo->genTime.Length]=0; 418 dtprintf("GenTime:\t\t%s\n", buf); 419 } 420 421 dtprintf("-- MessageImprint --\n"); 422 if (true) // SecAsn1TSAMessageImprint 423 { 424 printDataAsHex(" Algorithm:",&tstInfo->messageImprint.hashAlgorithm.algorithm, 0); 425 printDataAsHex(" Message :", &tstInfo->messageImprint.hashedMessage, 0);//tstInfo->messageImprint.hashedMessage.Length); 426 } 427#endif 428} 429 430#pragma mark ----- TimeStamp Response using XPC ----- 431 432#include <xpc/private.h> 433 434static OSStatus checkForNonDERResponse(const unsigned char *resp, size_t respLen) 435{ 436 /* 437 Good start is something like 30 82 0c 03 30 15 02 01 00 30 10 0c 0e 4f 70 65 438 439 URL: http://timestamp-int.corp.apple.com/signserver/process?TimeStampSigner 440 Resp: Http/1.1 Service Unavailable 441 442 URL: http://timestamp-int.corp.apple.com/ts01 443 Resp: blank 444 445 URL: http://cutandtaste.com/404 (or other forced 404 site) 446 Resp: 404 447 */ 448 449 OSStatus status = noErr; 450 const char ader[2] = { 0x30, 0x82 }; 451 char *respStr = NULL; 452 size_t maxlen = 0; 453 size_t badResponseCount; 454 455 const char *badResponses[] = 456 { 457 "<!DOCTYPE html>", 458 "Http/1.1 Service Unavailable", 459 "blank" 460 }; 461 462 require_action(resp && respLen, xit, status = errSecTimestampServiceNotAvailable); 463 464 // This is usual case 465 if ((respLen > 1) && (memcmp(resp, ader, 2)==0)) // might be good; pass on to DER decoder 466 return noErr; 467 468 badResponseCount = sizeof(badResponses)/sizeof(char *); 469 int ix; 470 for (ix = 0; ix < badResponseCount; ++ix) 471 if (strlen(badResponses[ix]) > maxlen) 472 maxlen = strlen(badResponses[ix]); 473 474 // Prevent a large response from allocating a ton of memory 475 if (respLen > maxlen) 476 respLen = maxlen; 477 478 respStr = (char *)malloc(respLen+1); 479 strlcpy(respStr, (const char *)resp, respLen); 480 481 for (ix = 0; ix < badResponseCount; ++ix) 482 if (strcmp(respStr, badResponses[ix])==0) 483 return errSecTimestampServiceNotAvailable; 484 485xit: 486 if (respStr) 487 free((void *)respStr); 488 489 return status; 490} 491 492static OSStatus sendTSARequestWithXPC(const unsigned char *tsaReq, size_t tsaReqLength, const unsigned char *tsaURL, unsigned char **tsaResp, size_t *tsaRespLength) 493{ 494 __block OSStatus result = noErr; 495 int timeoutInSeconds = 15; 496 extern xpc_object_t xpc_create_with_format(const char * format, ...); 497 498 dispatch_queue_t xpc_queue = dispatch_queue_create("com.apple.security.XPCTimeStampingService", DISPATCH_QUEUE_SERIAL); 499 __block dispatch_semaphore_t waitSemaphore = dispatch_semaphore_create(0); 500 dispatch_time_t finishTime = dispatch_time(DISPATCH_TIME_NOW, timeoutInSeconds * NSEC_PER_SEC); 501 502 xpc_connection_t con = xpc_connection_create("com.apple.security.XPCTimeStampingService", xpc_queue); 503 504 xpc_connection_set_event_handler(con, ^(xpc_object_t event) { 505 xpc_type_t xtype = xpc_get_type(event); 506 if (XPC_TYPE_ERROR == xtype) 507 { tsaDebug("default: connection error: %s\n", xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION)); } 508 else 509 { tsaDebug("default: unexpected connection event %p\n", event); } 510 }); 511 512 xpc_connection_resume(con); 513 514 xpc_object_t tsaReqData = xpc_data_create(tsaReq, tsaReqLength); 515 const char *urlstr = (tsaURL?(const char *)tsaURL:""); 516 xpc_object_t url_as_xpc_string = xpc_string_create(urlstr); 517 518 xpc_object_t message = xpc_create_with_format("{operation: TimeStampRequest, ServerURL: %value, TimeStampRequest: %value}", url_as_xpc_string, tsaReqData); 519 520 xpc_connection_send_message_with_reply(con, message, xpc_queue, ^(xpc_object_t reply) 521 { 522 tsaDebug("xpc_connection_send_message_with_reply handler called back\n"); 523 dispatch_retain(waitSemaphore); 524 525 xpc_type_t xtype = xpc_get_type(reply); 526 if (XPC_TYPE_ERROR == xtype) 527 { tsaDebug("message error: %s\n", xpc_dictionary_get_string(reply, XPC_ERROR_KEY_DESCRIPTION)); } 528 else if (XPC_TYPE_CONNECTION == xtype) 529 { tsaDebug("received connection\n"); } 530 else if (XPC_TYPE_DICTIONARY == xtype) 531 { 532#ifndef NDEBUG 533 /* 534 // This is useful for debugging. 535 char *debug = xpc_copy_description(reply); 536 tsaDebug("DEBUG %s\n", debug); 537 free(debug); 538 */ 539#endif 540 541 xpc_object_t xpcTimeStampReply = xpc_dictionary_get_value(reply, "TimeStampReply"); 542 size_t xpcTSRLength = xpc_data_get_length(xpcTimeStampReply); 543 tsaDebug("xpcTSRLength: %ld bytes of response\n", xpcTSRLength); 544 545 xpc_object_t xpcTimeStampError = xpc_dictionary_get_value(reply, "TimeStampError"); 546 xpc_object_t xpcTimeStampStatus = xpc_dictionary_get_value(reply, "TimeStampStatus"); 547 548 if (xpcTimeStampError || xpcTimeStampStatus) 549 { 550#ifndef NDEBUG 551 if (xpcTimeStampError) 552 { 553 size_t len = xpc_string_get_length(xpcTimeStampError); 554 char *buf = (char *)malloc(len); 555 strlcpy(buf, xpc_string_get_string_ptr(xpcTimeStampError), len+1); 556 tsaDebug("xpcTimeStampError: %s\n", buf); 557 if (buf) 558 free(buf); 559 } 560#endif 561 if (xpcTimeStampStatus) 562 { 563 result = (OSStatus)xpc_int64_get_value(xpcTimeStampStatus); 564 tsaDebug("xpcTimeStampStatus: %d\n", (int)result); 565 } 566 } 567 568 result = remapHTTPErrorCodes(result); 569 570 if ((result == noErr) && tsaResp && tsaRespLength) 571 { 572 *tsaRespLength = xpcTSRLength; 573 *tsaResp = (unsigned char *)malloc(xpcTSRLength); 574 575 size_t bytesCopied = xpc_data_get_bytes(xpcTimeStampReply, *tsaResp, 0, xpcTSRLength); 576 if (bytesCopied != xpcTSRLength) 577 { tsaDebug("length mismatch: copied: %ld, xpc: %ld\n", bytesCopied, xpcTSRLength); } 578 else 579 if ((result = checkForNonDERResponse(*tsaResp,bytesCopied))) 580 { 581 tsaDebug("received non-DER response from timestamp server\n"); 582 } 583 else 584 { 585 result = noErr; 586 tsaDebug("copied: %ld bytes of response\n", bytesCopied); 587 } 588 } 589 tsaDebug("releasing connection\n"); 590 xpc_release(con); 591 } 592 else 593 { tsaDebug("unexpected message reply type %p\n", xtype); } 594 595 dispatch_semaphore_signal(waitSemaphore); 596 dispatch_release(waitSemaphore); 597 }); 598 599 { tsaDebug("waiting up to %d seconds for response from XPC\n", timeoutInSeconds); } 600 dispatch_semaphore_wait(waitSemaphore, finishTime); 601 602 dispatch_release(waitSemaphore); 603 xpc_release(tsaReqData); 604 xpc_release(message); 605 606 { tsaDebug("sendTSARequestWithXPC exit\n"); } 607 608 return result; 609} 610 611#pragma mark ----- TimeStamp request ----- 612 613#include "tsaTemplates.h" 614#include <security_asn1/SecAsn1Coder.h> 615#include <Security/oidsalg.h> 616#include <AssertMacros.h> 617#include <libkern/OSByteOrder.h> 618 619extern const SecAsn1Template kSecAsn1TSATimeStampReqTemplate; 620extern const SecAsn1Template kSecAsn1TSATimeStampRespTemplateDER; 621 622CFMutableDictionaryRef SecCmsTSAGetDefaultContext(CFErrorRef *error) 623{ 624 // Caller responsible for retain/release 625 // <rdar://problem/11077440> Update SecCmsTSAGetDefaultContext with actual URL for Apple Timestamp server 626 // URL will be in TimeStampingPrefs.plist 627 628 CFBundleRef secFWbundle = NULL; 629 CFURLRef resourceURL = NULL; 630 CFDataRef resourceData = NULL; 631 CFPropertyListRef prefs = NULL; 632 CFMutableDictionaryRef contextDict = NULL; 633 SInt32 errorCode = 0; 634 CFOptionFlags options = 0; 635 CFPropertyListFormat format = 0; 636 OSStatus status = noErr; 637 638 require_action(secFWbundle = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.security")), xit, status = errSecInternalError); 639 require_action(resourceURL = CFBundleCopyResourceURL(secFWbundle, CFSTR("TimeStampingPrefs"), CFSTR("plist"), NULL), 640 xit, status = errSecInvalidPrefsDomain); 641 642 require(CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, resourceURL, &resourceData, 643 NULL, NULL, &errorCode), xit); 644 require_action(resourceData, xit, status = errSecDataNotAvailable); 645 646 prefs = CFPropertyListCreateWithData(kCFAllocatorDefault, resourceData, options, &format, error); 647 require_action(prefs && (CFGetTypeID(prefs)==CFDictionaryGetTypeID()), xit, status = errSecInvalidPrefsDomain); 648 649 contextDict = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, prefs); 650 651 if (error) 652 *error = NULL; 653xit: 654 if (errorCode) 655 status = errorCode; 656 if (error && status) 657 *error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainOSStatus, status, NULL); 658 if (secFWbundle) 659 CFRelease(secFWbundle); 660 if (resourceURL) 661 CFRelease(resourceURL); 662 if (resourceData) 663 CFRelease(resourceData); 664 if (prefs) 665 CFRelease(prefs); 666 667 return contextDict; 668} 669 670static CFDataRef _SecTSARequestCopyDEREncoding(SecAsn1TSAMessageImprint *messageImprint, bool noCerts, uint64_t nonce) 671{ 672 // Returns DER encoded TimeStampReq 673 // Modeled on _SecOCSPRequestCopyDEREncoding 674 // The Timestamp Authority supports 64 bit nonces (or more possibly) 675 676 SecAsn1CoderRef coder = NULL; 677 uint8_t version = 1; 678 SecAsn1Item vers = {1, &version}; 679 uint8_t creq = noCerts?0:1; 680 SecAsn1Item certReq = {1, &creq}; //jch - to request or not? 681 SecAsn1TSATimeStampReq tsreq = {}; 682 CFDataRef der = NULL; 683 uint64_t nonceVal = OSSwapHostToBigConstInt64(nonce); 684 SecAsn1Item nonceItem = {sizeof(uint64_t), (unsigned char *)&nonceVal}; 685 686 uint8_t OID_FakePolicy_Data[] = { 0x2A, 0x03, 0x04, 0x05, 0x06}; 687 const CSSM_OID fakePolicyOID = {sizeof(OID_FakePolicy_Data),OID_FakePolicy_Data}; 688 689 tsreq.version = vers; 690 691 tsreq.messageImprint = *messageImprint; 692 tsreq.certReq = certReq; 693 694 // skip reqPolicy, extensions for now - FAKES - jch 695 tsreq.reqPolicy = fakePolicyOID; //policyID; 696 697 tsreq.nonce = nonceItem; 698 699 // Encode the request 700 require_noerr(SecAsn1CoderCreate(&coder), errOut); 701 702 SecAsn1Item encoded; 703 require_noerr(SecAsn1EncodeItem(coder, &tsreq, 704 &kSecAsn1TSATimeStampReqTemplate, &encoded), errOut); 705 der = CFDataCreate(kCFAllocatorDefault, encoded.Data, 706 encoded.Length); 707 708errOut: 709 if (coder) 710 SecAsn1CoderRelease(coder); 711 712 return der; 713} 714 715OSStatus SecTSAResponseCopyDEREncoding(SecAsn1CoderRef coder, const CSSM_DATA *tsaResponse, SecAsn1TimeStampRespDER *respDER) 716{ 717 // Partially decode the response 718 OSStatus status = paramErr; 719 720 require(tsaResponse && respDER, errOut); 721 require_noerr(SecAsn1DecodeData(coder, tsaResponse, 722 &kSecAsn1TSATimeStampRespTemplateDER, respDER), errOut); 723 status = noErr; 724 725errOut: 726 727 return status; 728} 729 730#pragma mark ----- TS Callback ----- 731 732OSStatus SecCmsTSADefaultCallback(CFTypeRef context, void *messageImprintV, uint64_t nonce, CSSM_DATA *signedDERBlob) 733{ 734 OSStatus result = paramErr; 735 const unsigned char *tsaReq = NULL; 736 size_t tsaReqLength = 0; 737 CFDataRef cfreq = NULL; 738 unsigned char *tsaURL = NULL; 739 bool noCerts = false; 740 741 if (!context || CFGetTypeID(context)!=CFDictionaryGetTypeID()) 742 return paramErr; 743 744 SecAsn1TSAMessageImprint *messageImprint = (SecAsn1TSAMessageImprint *)messageImprintV; 745 if (!messageImprint || !signedDERBlob) 746 return paramErr; 747 748 CFBooleanRef cfnocerts = (CFBooleanRef)CFDictionaryGetValue((CFDictionaryRef)context, kTSAContextKeyNoCerts); 749 if (cfnocerts) 750 { 751 tsaDebug("[TSA] Request noCerts\n"); 752 noCerts = CFBooleanGetValue(cfnocerts); 753 } 754 755 // We must spoof the nonce here, before sending the request. 756 // If we tried to alter the reply, then the signature would break instead. 757 CFBooleanRef cfBadNonce = (CFBooleanRef)CFDictionaryGetValue((CFDictionaryRef)context, kTSADebugContextKeyBadNonce); 758 if (cfBadNonce && CFBooleanGetValue(cfBadNonce)) 759 { 760 tsaDebug("[TSA] Forcing bad TS Request by changing nonce\n"); 761 nonce++; 762 } 763 764 printDataAsHex("[TSA] hashToTimeStamp:", &messageImprint->hashedMessage,128); 765 cfreq = _SecTSARequestCopyDEREncoding(messageImprint, noCerts, nonce); 766 if (cfreq) 767 { 768 tsaReq = CFDataGetBytePtr(cfreq); 769 tsaReqLength = CFDataGetLength(cfreq); 770 771#ifndef NDEBUG 772 CFShow(cfreq); 773 tsaWriteFileX("/tmp/tsareq.req", tsaReq, tsaReqLength); 774#endif 775 } 776 777 CFStringRef url = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)context, kTSAContextKeyURL); 778 if (!url) 779 { 780 tsaDebug("[TSA] missing URL for TSA (key: %s)\n", "kTSAContextKeyURL"); 781 goto xit; 782 } 783 784 /* 785 If debugging, look at special values in the context to mess things up 786 */ 787 788 CFBooleanRef cfBadReq = (CFBooleanRef)CFDictionaryGetValue((CFDictionaryRef)context, kTSADebugContextKeyBadReq); 789 if (cfBadReq && CFBooleanGetValue(cfBadReq)) 790 { 791 tsaDebug("[TSA] Forcing bad TS Request by truncating length from %ld to %ld\n", tsaReqLength, (tsaReqLength-4)); 792 tsaReqLength -= 4; 793 } 794 795 // need to extract into buffer 796 CFIndex length = CFStringGetLength(url); // in 16-bit character units 797 tsaURL = malloc(6 * length + 1); // pessimistic 798 if (!CFStringGetCString(url, (char *)tsaURL, 6 * length + 1, kCFStringEncodingUTF8)) 799 goto xit; 800 801 tsaDebug("[TSA] URL for timestamp server: %s\n", tsaURL); 802 803 unsigned char *tsaResp = NULL; 804 size_t tsaRespLength = 0; 805 tsaDebug("calling sendTSARequestWithXPC with %ld bytes of request\n", tsaReqLength); 806 807 require_noerr(result = sendTSARequestWithXPC(tsaReq, tsaReqLength, tsaURL, &tsaResp, &tsaRespLength), xit); 808 809 tsaDebug("sendTSARequestWithXPC copied: %ld bytes of response\n", tsaRespLength); 810 811 signedDERBlob->Data = tsaResp; 812 signedDERBlob->Length = tsaRespLength; 813 814 result = noErr; 815 816xit: 817 if (tsaURL) 818 free((void *)tsaURL); 819 if (cfreq) 820 CFRelease(cfreq); 821 822 return result; 823} 824 825#pragma mark ----- TimeStamp Verification ----- 826 827static OSStatus convertGeneralizedTimeToCFAbsoluteTime(const char *timeStr, CFAbsoluteTime *ptime) 828{ 829 /* 830 See http://userguide.icu-project.org/formatparse/datetime for date/time format. 831 The "Z" signal a GMT time, but CFDateFormatterGetAbsoluteTimeFromString returns 832 values based on local time. 833 */ 834 835 OSStatus result = noErr; 836 CFDateFormatterRef formatter = NULL; 837 CFStringRef time_string = NULL; 838 CFTimeZoneRef gmt = NULL; 839 CFLocaleRef locale = NULL; 840 CFRange *rangep = NULL; 841 842 require(timeStr && timeStr[0] && ptime, xit); 843 require(formatter = CFDateFormatterCreate(kCFAllocatorDefault, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle), xit); 844// CFRetain(formatter); 845 CFDateFormatterSetFormat(formatter, CFSTR("yyyyMMddHHmmss'Z'")); // GeneralizedTime 846 gmt = CFTimeZoneCreateWithTimeIntervalFromGMT(NULL, 0); 847 CFDateFormatterSetProperty(formatter, kCFDateFormatterTimeZone, gmt); 848 849 time_string = CFStringCreateWithCString(kCFAllocatorDefault, timeStr, kCFStringEncodingUTF8); 850 if (!time_string || !CFDateFormatterGetAbsoluteTimeFromString(formatter, time_string, rangep, ptime)) 851 { 852 dtprintf("%s is not a valid date\n", timeStr); 853 result = 1; 854 } 855 856xit: 857 if (formatter) 858 CFRelease(formatter); 859 if (time_string) 860 CFRelease(time_string); 861 if (gmt) 862 CFRelease(gmt); 863 864 return result; 865} 866 867static OSStatus SecTSAValidateTimestamp(const SecAsn1TSATSTInfo *tstInfo, CSSM_DATA **signingCerts, CFAbsoluteTime *timestampTime) 868{ 869 // See <rdar://problem/11077708> Properly handle revocation information of timestamping certificate 870 OSStatus result = paramErr; 871 CFAbsoluteTime genTime = 0; 872 char timeStr[32] = {0,}; 873 SecCertificateRef signingCertificate = NULL; 874 875 require(tstInfo && signingCerts && (tstInfo->genTime.Length < 16), xit); 876 877 // Find the leaf signingCert 878 require_noerr(result = SecCertificateCreateFromData(*signingCerts, 879 CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, &signingCertificate), xit); 880 881 memcpy(timeStr, tstInfo->genTime.Data, tstInfo->genTime.Length); 882 timeStr[tstInfo->genTime.Length] = 0; 883 require_noerr(convertGeneralizedTimeToCFAbsoluteTime(timeStr, &genTime), xit); 884 if (SecCertificateIsValidX(signingCertificate, genTime)) // iOS? 885 result = noErr; 886 else 887 result = errSecTimestampInvalid; 888 if (timestampTime) 889 *timestampTime = genTime; 890xit: 891 return result; 892} 893 894static OSStatus verifyTSTInfo(const CSSM_DATA_PTR content, CSSM_DATA **signingCerts, SecAsn1TSATSTInfo *tstInfo, CFAbsoluteTime *timestampTime, uint64_t expectedNonce) 895{ 896 OSStatus status = paramErr; 897 SecAsn1CoderRef coder = NULL; 898 899 if (!tstInfo) 900 return SECFailure; 901 902 require_noerr(SecAsn1CoderCreate(&coder), xit); 903 require_noerr(SecAsn1Decode(coder, content->Data, content->Length, 904 kSecAsn1TSATSTInfoTemplate, tstInfo), xit); 905 displayTSTInfo(tstInfo); 906 907 // Check the nonce 908 if (tstInfo->nonce.Data && expectedNonce!=0) 909 { 910 uint64_t nonce = tsaDER_ToInt(&tstInfo->nonce); 911 // if (expectedNonce!=nonce) 912 dtprintf("verifyTSTInfo nonce: actual: %lld, expected: %lld\n", nonce, expectedNonce); 913 require_action(expectedNonce==nonce, xit, status = errSecTimestampRejection); 914 } 915 916 status = SecTSAValidateTimestamp(tstInfo, signingCerts, timestampTime); 917 dtprintf("SecTSAValidateTimestamp result: %ld\n", (long)status); 918 919xit: 920 if (coder) 921 SecAsn1CoderRelease(coder); 922 return status; 923} 924 925static void debugShowExtendedTrustResult(int index, CFDictionaryRef extendedResult) 926{ 927#ifndef NDEBUG 928 if (extendedResult) 929 { 930 CFStringRef xresStr = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, 931 CFSTR("Extended trust result for signer #%d : %@"), index, extendedResult); 932 if (xresStr) 933 { 934 CFShow(xresStr); 935 CFRelease(xresStr); 936 } 937 } 938#endif 939} 940 941#ifndef NDEBUG 942extern const char *cssmErrorString(CSSM_RETURN error); 943 944static void statusBitTest(CSSM_TP_APPLE_CERT_STATUS certStatus, uint32 bit, const char *str) 945{ 946 if (certStatus & bit) 947 dtprintf("%s ", str); 948} 949#endif 950 951static void debugShowCertEvidenceInfo(uint16_t certCount, const CSSM_TP_APPLE_EVIDENCE_INFO *info) 952{ 953#ifndef NDEBUG 954 CSSM_TP_APPLE_CERT_STATUS cs; 955// const CSSM_TP_APPLE_EVIDENCE_INFO *pinfo = info; 956 uint16_t ix; 957 for (ix=0; info && (ix<certCount); ix++, ++info) 958 { 959 cs = info->StatusBits; 960 dtprintf(" cert %u:\n", ix); 961 dtprintf(" StatusBits : 0x%x", (unsigned)cs); 962 if (cs) 963 { 964 dtprintf(" ( "); 965 statusBitTest(cs, CSSM_CERT_STATUS_EXPIRED, "EXPIRED"); 966 statusBitTest(cs, CSSM_CERT_STATUS_NOT_VALID_YET, 967 "NOT_VALID_YET"); 968 statusBitTest(cs, CSSM_CERT_STATUS_IS_IN_INPUT_CERTS, 969 "IS_IN_INPUT_CERTS"); 970 statusBitTest(cs, CSSM_CERT_STATUS_IS_IN_ANCHORS, 971 "IS_IN_ANCHORS"); 972 statusBitTest(cs, CSSM_CERT_STATUS_IS_ROOT, "IS_ROOT"); 973 statusBitTest(cs, CSSM_CERT_STATUS_IS_FROM_NET, "IS_FROM_NET"); 974 dtprintf(")\n"); 975 } 976 else 977 dtprintf("\n"); 978 979 dtprintf(" NumStatusCodes : %u ", info->NumStatusCodes); 980 CSSM_RETURN *pstatuscode = info->StatusCodes; 981 uint16_t jx; 982 for (jx=0; pstatuscode && (jx<info->NumStatusCodes); jx++, ++pstatuscode) 983 dtprintf("%s ", cssmErrorString(*pstatuscode)); 984 985 dtprintf("\n"); 986 dtprintf(" Index: %u\n", info->Index); 987 } 988 989#endif 990} 991 992#ifndef NDEBUG 993static const char *trustResultTypeString(SecTrustResultType trustResultType) 994{ 995 switch (trustResultType) 996 { 997 case kSecTrustResultProceed: return "TrustResultProceed"; 998 case kSecTrustResultUnspecified: return "TrustResultUnspecified"; 999 case kSecTrustResultDeny: return "TrustResultDeny"; // user reject 1000 case kSecTrustResultInvalid: return "TrustResultInvalid"; 1001 case kSecTrustResultConfirm: return "TrustResultConfirm"; 1002 case kSecTrustResultRecoverableTrustFailure: return "TrustResultRecoverableTrustFailure"; 1003 case kSecTrustResultFatalTrustFailure: return "TrustResultUnspecified"; 1004 case kSecTrustResultOtherError: return "TrustResultOtherError"; 1005 default: return "TrustResultUnknown"; 1006 } 1007 return ""; 1008} 1009#endif 1010 1011static OSStatus verifySigners(SecCmsSignedDataRef signedData, int numberOfSigners) 1012{ 1013 // See <rdar://problem/11077588> Bubble up SecTrustEvaluate of timestamp response to high level callers 1014 // Also <rdar://problem/11077708> Properly handle revocation information of timestamping certificate 1015 1016 SecPolicyRef policy = NULL; 1017 int result=errSecInternalError; 1018 int rx; 1019 1020 require(policy = SecPolicyCreateWithOID(kSecPolicyAppleTimeStamping), xit); 1021 int jx; 1022 for (jx = 0; jx < numberOfSigners; ++jx) 1023 { 1024 SecTrustResultType trustResultType; 1025 SecTrustRef trustRef = NULL; 1026 CFDictionaryRef extendedResult = NULL; 1027 CFArrayRef certChain = NULL; 1028 uint16_t certCount = 0; 1029 1030 CSSM_TP_APPLE_EVIDENCE_INFO *statusChain = NULL; 1031 1032 // SecCmsSignedDataVerifySignerInfo returns trustRef, which we can call SecTrustEvaluate on 1033 // usually (always?) if result is noErr, the SecTrust*Result calls will return errSecTrustNotAvailable 1034 result = SecCmsSignedDataVerifySignerInfo (signedData, jx, NULL, policy, &trustRef); 1035 dtprintf("[%s] SecCmsSignedDataVerifySignerInfo: result: %d, signer: %d\n", 1036 __FUNCTION__, result, jx); 1037 require_noerr(result, xit); 1038 1039 result = SecTrustEvaluate (trustRef, &trustResultType); 1040 dtprintf("[%s] SecTrustEvaluate: result: %d, trustResult: %s (%d)\n", 1041 __FUNCTION__, result, trustResultTypeString(trustResultType), trustResultType); 1042 if (result) 1043 goto xit; 1044 switch (trustResultType) 1045 { 1046 case kSecTrustResultProceed: 1047 case kSecTrustResultUnspecified: 1048 break; // success 1049 case kSecTrustResultDeny: // user reject 1050 result = errSecTimestampNotTrusted; // SecCmsVSTimestampNotTrusted ? 1051 break; 1052 case kSecTrustResultInvalid: 1053 assert(false); // should never happen 1054 result = errSecTimestampNotTrusted; // SecCmsVSTimestampNotTrusted ? 1055 break; 1056 case kSecTrustResultConfirm: 1057 case kSecTrustResultRecoverableTrustFailure: 1058 case kSecTrustResultFatalTrustFailure: 1059 case kSecTrustResultOtherError: 1060 default: 1061 { 1062 /* 1063 There are two "errors" that need to be resolved externally: 1064 CSSMERR_TP_CERT_EXPIRED can be OK if the timestamp was made 1065 before the TSA chain expired; CSSMERR_TP_CERT_NOT_VALID_YET 1066 can happen in the case where the user's clock was set to 0. 1067 We don't want to prevent them using apps automatically, so 1068 return noErr and let codesign or whover decide. 1069 */ 1070 OSStatus resultCode; 1071 require_action(SecTrustGetCssmResultCode(trustRef, &resultCode)==noErr, xit, result = errSecTimestampNotTrusted); 1072 result = (resultCode == CSSMERR_TP_CERT_EXPIRED || resultCode == CSSMERR_TP_CERT_NOT_VALID_YET)?noErr:errSecTimestampNotTrusted; 1073 } 1074 break; 1075 } 1076 1077 rx = SecTrustGetResult(trustRef, &trustResultType, &certChain, &statusChain); 1078 dtprintf("[%s] SecTrustGetResult: result: %d, type: %d\n", __FUNCTION__,rx, trustResultType); 1079 certCount = certChain?CFArrayGetCount(certChain):0; 1080 debugShowCertEvidenceInfo(certCount, statusChain); 1081 1082 rx = SecTrustCopyExtendedResult(trustRef, &extendedResult); 1083 dtprintf("[%s] SecTrustCopyExtendedResult: result: %d\n", __FUNCTION__, rx); 1084 if (extendedResult) 1085 { 1086 debugShowExtendedTrustResult(jx, extendedResult); 1087 CFRelease(extendedResult); 1088 } 1089 1090 if (trustRef) 1091 CFRelease (trustRef); 1092 } 1093 1094xit: 1095 if (policy) 1096 CFRelease (policy); 1097 return result; 1098} 1099 1100static OSStatus impExpImportCertUnCommon( 1101 const CSSM_DATA *cdata, 1102 SecKeychainRef importKeychain, // optional 1103 CFMutableArrayRef outArray) // optional, append here 1104{ 1105 // The only difference between this and impExpImportCertCommon is that we append to outArray 1106 // before attempting to add to the keychain 1107 OSStatus status = noErr; 1108 SecCertificateRef certRef = NULL; 1109 1110 require_action(cdata, xit, status = errSecUnsupportedFormat); 1111 1112 /* Pass kCFAllocatorNull as bytesDeallocator to assure the bytes aren't freed */ 1113 CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)cdata->Data, (CFIndex)cdata->Length, kCFAllocatorNull); 1114 require_action(data, xit, status = errSecUnsupportedFormat); 1115 1116 certRef = SecCertificateCreateWithData(kCFAllocatorDefault, data); 1117 CFRelease(data); /* certRef has its own copy of the data now */ 1118 if(!certRef) { 1119 dtprintf("impExpHandleCert error\n"); 1120 return errSecUnsupportedFormat; 1121 } 1122 1123 if (outArray) 1124 CFArrayAppendValue(outArray, certRef); 1125 1126 if (importKeychain) 1127 { 1128 status = SecCertificateAddToKeychain(certRef, importKeychain); 1129 if (status!=noErr && status!=errSecDuplicateItem) 1130 { dtprintf("SecCertificateAddToKeychain error: %ld\n", (long)status); } 1131 } 1132 1133xit: 1134 if (certRef) 1135 CFRelease(certRef); 1136 return status; 1137} 1138 1139static void saveTSACertificates(CSSM_DATA **signingCerts, CFMutableArrayRef outArray) 1140{ 1141 SecKeychainRef defaultKeychain = NULL; 1142 // Don't save certificates in keychain to avoid securityd issues 1143// if (SecKeychainCopyDefault(&defaultKeychain)) 1144// defaultKeychain = NULL; 1145 1146 unsigned certCount = SecCmsArrayCount((void **)signingCerts); 1147 unsigned dex; 1148 for (dex=0; dex<certCount; dex++) 1149 { 1150 OSStatus rx = impExpImportCertUnCommon(signingCerts[dex], defaultKeychain, outArray); 1151 if (rx!=noErr && rx!=errSecDuplicateItem) 1152 dtprintf("impExpImportCertCommon failed: %ld\n", (long)rx); 1153 } 1154 if (defaultKeychain) 1155 CFRelease(defaultKeychain); 1156} 1157 1158static const char *cfabsoluteTimeToString(CFAbsoluteTime abstime) 1159{ 1160 CFGregorianDate greg = CFAbsoluteTimeGetGregorianDate(abstime, NULL); 1161 char str[20]; 1162 if (19 != snprintf(str, 20, "%4.4d-%2.2d-%2.2d_%2.2d:%2.2d:%2.2d", 1163 (int)greg.year, greg.month, greg.day, greg.hour, greg.minute, (int)greg.second)) 1164 str[0]=0; 1165 char *data = (char *)malloc(20); 1166 strncpy(data, str, 20); 1167 return data; 1168} 1169 1170static OSStatus setTSALeafValidityDates(SecCmsSignerInfoRef signerinfo) 1171{ 1172 OSStatus status = noErr; 1173 1174 if (!signerinfo->timestampCertList || (CFArrayGetCount(signerinfo->timestampCertList) == 0)) 1175 return SecCmsVSSigningCertNotFound; 1176 1177 SecCertificateRef tsaLeaf = (SecCertificateRef)CFArrayGetValueAtIndex(signerinfo->timestampCertList, 0); 1178 require_action(tsaLeaf, xit, status = errSecCertificateCannotOperate); 1179 1180 signerinfo->tsaLeafNotBefore = SecCertificateNotValidBefore(tsaLeaf); /* Start date for Timestamp Authority leaf */ 1181 signerinfo->tsaLeafNotAfter = SecCertificateNotValidAfter(tsaLeaf); /* Expiration date for Timestamp Authority leaf */ 1182 1183 const char *nbefore = cfabsoluteTimeToString(signerinfo->tsaLeafNotBefore); 1184 const char *nafter = cfabsoluteTimeToString(signerinfo->tsaLeafNotAfter); 1185 if (nbefore && nafter) 1186 { 1187 dtprintf("Timestamp Authority leaf valid from %s to %s\n", nbefore, nafter); 1188 free((void *)nbefore);free((void *)nafter); 1189 } 1190 1191/* 1192 if(at < nb) 1193 status = errSecCertificateNotValidYet; 1194 else if (at > na) 1195 status = errSecCertificateExpired; 1196*/ 1197 1198xit: 1199 return status; 1200} 1201 1202/* 1203 From RFC 3161: Time-Stamp Protocol (TSP),August 2001, APPENDIX B: 1204 1205 B) The validity of the digital signature may then be verified in the 1206 following way: 1207 1208 1) The time-stamp token itself MUST be verified and it MUST be 1209 verified that it applies to the signature of the signer. 1210 1211 2) The date/time indicated by the TSA in the TimeStampToken 1212 MUST be retrieved. 1213 1214 3) The certificate used by the signer MUST be identified and 1215 retrieved. 1216 1217 4) The date/time indicated by the TSA MUST be within the 1218 validity period of the signer's certificate. 1219 1220 5) The revocation information about that certificate, at the 1221 date/time of the Time-Stamping operation, MUST be retrieved. 1222 1223 6) Should the certificate be revoked, then the date/time of 1224 revocation shall be later than the date/time indicated by 1225 the TSA. 1226 1227 If all these conditions are successful, then the digital signature 1228 shall be declared as valid. 1229 1230*/ 1231 1232OSStatus decodeTimeStampToken(SecCmsSignerInfoRef signerinfo, CSSM_DATA_PTR inData, CSSM_DATA_PTR encDigest, uint64_t expectedNonce) 1233{ 1234 /* 1235 We update signerinfo with timestamp and tsa certificate chain. 1236 encDigest is the original signed blob, which we must hash and compare. 1237 inData comes from the unAuthAttr section of the CMS message 1238 1239 These are set in signerinfo as side effects: 1240 timestampTime - 1241 timestampCertList 1242 */ 1243 1244 SecCmsDecoderRef decoderContext = NULL; 1245 SecCmsMessageRef cmsMessage = NULL; 1246 SecCmsContentInfoRef contentInfo; 1247 SecCmsSignedDataRef signedData; 1248 SECOidTag contentTypeTag; 1249 int contentLevelCount; 1250 int ix; 1251 OSStatus result = errSecUnknownFormat; 1252 CSSM_DATA **signingCerts = NULL; 1253 1254 dtprintf("decodeTimeStampToken top: PORT_GetError() %d -----\n", PORT_GetError()); 1255 PORT_SetError(0); 1256 1257 /* decode the message */ 1258 require_noerr(result = SecCmsDecoderCreate (NULL, NULL, NULL, NULL, NULL, NULL, NULL, &decoderContext), xit); 1259 result = SecCmsDecoderUpdate(decoderContext, inData->Data, inData->Length); 1260 if (result) 1261 { 1262 result = errSecTimestampInvalid; 1263 SecCmsDecoderDestroy(decoderContext); 1264 goto xit; 1265 } 1266 1267 require_noerr(result = SecCmsDecoderFinish(decoderContext, &cmsMessage), xit); 1268 1269 // process the results 1270 contentLevelCount = SecCmsMessageContentLevelCount(cmsMessage); 1271 1272 if (encDigest) 1273 printDataAsHex("encDigest",encDigest, 0); 1274 1275 for (ix = 0; ix < contentLevelCount; ++ix) 1276 { 1277 dtprintf("\n----- Content Level %d -----\n", ix); 1278 // get content information 1279 contentInfo = SecCmsMessageContentLevel (cmsMessage, ix); 1280 contentTypeTag = SecCmsContentInfoGetContentTypeTag (contentInfo); 1281 1282 // After 2nd round, contentInfo.content.data is the TSTInfo 1283 1284 debugShowContentTypeOID(contentInfo); 1285 1286 switch (contentTypeTag) 1287 { 1288 case SEC_OID_PKCS7_SIGNED_DATA: 1289 { 1290 require((signedData = (SecCmsSignedDataRef)SecCmsContentInfoGetContent(contentInfo)) != NULL, xit); 1291 1292 debugShowSignerInfo(signedData); 1293 1294 SECAlgorithmID **digestAlgorithms = SecCmsSignedDataGetDigestAlgs(signedData); 1295 unsigned digestAlgCount = SecCmsArrayCount((void **)digestAlgorithms); 1296 dtprintf("digestAlgCount: %d\n", digestAlgCount); 1297 if (signedData->digests) 1298 { 1299 int jx; 1300 char buffer[128]; 1301 for (jx=0;jx < digestAlgCount;jx++) 1302 { 1303 sprintf(buffer, " digest[%u]", jx); 1304 printDataAsHex(buffer,signedData->digests[jx], 0); 1305 } 1306 } 1307 else 1308 { 1309 dtprintf("No digests\n"); 1310 CSSM_DATA_PTR innerContent = SecCmsContentInfoGetInnerContent(contentInfo); 1311 if (innerContent) 1312 { 1313 dtprintf("inner content length: %ld\n", innerContent->Length); 1314 SecAsn1TSAMessageImprint fakeMessageImprint = {{{0}},}; 1315 OSStatus status = createTSAMessageImprint(signedData, innerContent, &fakeMessageImprint); 1316 if (status) 1317 { dtprintf("createTSAMessageImprint status: %d\n", (int)status); } 1318 printDataAsHex("inner content hash",&fakeMessageImprint.hashedMessage, 0); 1319 CSSM_DATA_PTR digestdata = &fakeMessageImprint.hashedMessage; 1320 CSSM_DATA_PTR digests[2] = {digestdata, NULL}; 1321 SecCmsSignedDataSetDigests(signedData, digestAlgorithms, (CSSM_DATA_PTR *)&digests); 1322 } 1323 else 1324 dtprintf("no inner content\n"); 1325 } 1326 1327 /* 1328 Import the certificates. We leave this as a warning, since 1329 there are configurations where the certificates are not returned. 1330 */ 1331 signingCerts = SecCmsSignedDataGetCertificateList(signedData); 1332 if (signingCerts == NULL) 1333 { dtprintf("SecCmsSignedDataGetCertificateList returned NULL\n"); } 1334 else 1335 { 1336 if (!signerinfo->timestampCertList) 1337 signerinfo->timestampCertList = CFArrayCreateMutable(kCFAllocatorDefault, 10, &kCFTypeArrayCallBacks); 1338 saveTSACertificates(signingCerts, signerinfo->timestampCertList); 1339 require_noerr(result = setTSALeafValidityDates(signerinfo), xit); 1340 debugSaveCertificates(signingCerts); 1341 } 1342 1343 int numberOfSigners = SecCmsSignedDataSignerInfoCount (signedData); 1344 1345 result = verifySigners(signedData, numberOfSigners); 1346 if (result) 1347 dtprintf("verifySigners failed: %ld\n", (long)result); // warning 1348 1349 1350 if (result) // remap to SecCmsVSTimestampNotTrusted ? 1351 goto xit; 1352 1353 break; 1354 } 1355 case SEC_OID_PKCS9_SIGNING_CERTIFICATE: 1356 { 1357 dtprintf("SEC_OID_PKCS9_SIGNING_CERTIFICATE seen\n"); 1358 break; 1359 } 1360 1361 case SEC_OID_PKCS9_ID_CT_TSTInfo: 1362 { 1363 SecAsn1TSATSTInfo tstInfo = {{0},}; 1364 result = verifyTSTInfo(contentInfo->rawContent, signingCerts, &tstInfo, &signerinfo->timestampTime, expectedNonce); 1365 if (signerinfo->timestampTime) 1366 { 1367 const char *tstamp = cfabsoluteTimeToString(signerinfo->timestampTime); 1368 if (tstamp) 1369 { 1370 dtprintf("Timestamp Authority timestamp: %s\n", tstamp); 1371 free((void *)tstamp); 1372 } 1373 } 1374 break; 1375 } 1376 case SEC_OID_OTHER: 1377 { 1378 dtprintf("otherContent : %p\n", (char *)SecCmsContentInfoGetContent (contentInfo)); 1379 break; 1380 } 1381 default: 1382 dtprintf("ContentTypeTag : %x\n", contentTypeTag); 1383 break; 1384 } 1385 } 1386xit: 1387 if (cmsMessage) 1388 SecCmsMessageDestroy(cmsMessage); 1389 1390 return result; 1391} 1392 1393 1394