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