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