/*
 * Copyright (c) 2018 Apple Inc. All Rights Reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 *
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this
 * file.
 *
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 *
 * @APPLE_LICENSE_HEADER_END@
 *
 */

#include <AssertMacros.h>
#import <XCTest/XCTest.h>
#include "OSX/utilities/SecCFWrappers.h"
#include <Security/SecCertificatePriv.h>
#include <Security/SecPolicy.h>
#include <Security/SecTrust.h>
#include <Security/SecTrustSettings.h>

#import "TrustEvaluationTestCase.h"
#include "../TestMacroConversions.h"
#include "VerifyDateTests_data.h"

@interface VerifyDateTests : TrustEvaluationTestCase
@end

@implementation VerifyDateTests
/* Test long-lived cert chain that expires in 9999 */

static SecTrustRef trust = nil;

+ (void)setUp {
    [super setUp];
    SecCertificateRef leaf = SecCertificateCreateWithBytes(NULL, longleaf, sizeof(longleaf));
    SecCertificateRef root = SecCertificateCreateWithBytes(NULL, longroot, sizeof(longroot));
    NSArray *anchors = @[(__bridge id)root];

    SecTrustCreateWithCertificates(leaf, NULL, &trust);
    SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors);
    CFReleaseNull(leaf);
    CFReleaseNull(root);
}

+ (void)tearDown {
    CFReleaseNull(trust);
}

- (void)testPriorToNotBefore {
    CFDateRef date = NULL;
    /* September 4, 2013 (prior to "notBefore" date of 2 April 2014, should fail) */
    isnt(date = CFDateCreate(NULL, 400000000), NULL, "failed to create date");
    ok_status(SecTrustSetVerifyDate(trust, date), "set trust date to 23 Sep 2013");
    XCTAssertFalse(SecTrustEvaluateWithError(trust, NULL), "evaluate trust on 23 Sep 2013 and expect failure");
    CFReleaseNull(date);
}

- (void)testRecentWithinValidity {
    CFDateRef date = NULL;
    /* January 17, 2016 (recent date within validity period, should succeed) */
    isnt(date = CFDateCreate(NULL, 474747474), NULL, "failed to create date");
    ok_status(SecTrustSetVerifyDate(trust, date), "set trust date to 17 Jan 2016");
    XCTAssert(SecTrustEvaluateWithError(trust, NULL), "evaluate trust on 17 Jan 2016 and expect success");
    CFReleaseNull(date);
}

- (void)testFarFutureWithinValidity {
    CFDateRef date = NULL;
    /* December 20, 9999 (far-future date within validity period, should succeed) */
    isnt(date = CFDateCreate(NULL, 252423000000), NULL, "failed to create date");
    ok_status(SecTrustSetVerifyDate(trust, date), "set trust date to 20 Dec 9999");
    XCTAssert(SecTrustEvaluateWithError(trust, NULL), "evaluate trust on 20 Dec 9999 and expect success");
    CFReleaseNull(date);
}

- (void)testAfterNotAfter {
    CFDateRef date = NULL;
    /* January 12, 10000 (after the "notAfter" date of 31 Dec 9999, should fail) */
    isnt(date = CFDateCreate(NULL, 252425000000), NULL, "failed to create date");
    ok_status(SecTrustSetVerifyDate(trust, date), "set trust date to 12 Jan 10000");
    XCTAssertFalse(SecTrustEvaluateWithError(trust, NULL), "evaluate trust on 12 Jan 10000 and expect failure");
    CFReleaseNull(date);
}

@end

@interface ValidityPeriodRestrictionTests : TrustEvaluationTestCase
@end

@implementation ValidityPeriodRestrictionTests
// Note that the dates described in the test names are the issuance date not the VerifyDate

- (BOOL)runTrustEvaluation:(NSArray *)certs anchors:(NSArray *)anchors error:(NSError **)error
{
    SecPolicyRef policy = SecPolicyCreateSSL(true, CFSTR("example.com"));
    NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:590000000.0]; // September 12, 2019 at 9:53:20 AM PDT
    SecTrustRef trustRef = NULL;
    BOOL result = NO;
    CFErrorRef cferror = NULL;

    require_noerr(SecTrustCreateWithCertificates((__bridge CFArrayRef)certs, policy, &trustRef), errOut);
    require_noerr(SecTrustSetVerifyDate(trustRef, (__bridge CFDateRef)date), errOut);

    if (anchors) {
        require_noerr(SecTrustSetAnchorCertificates(trustRef, (__bridge CFArrayRef)anchors), errOut);
    }

    result = SecTrustEvaluateWithError(trustRef, &cferror);
    if (error && cferror) {
        *error = (__bridge NSError*)cferror;
    }

errOut:
    CFReleaseNull(policy);
    CFReleaseNull(trustRef);
    CFReleaseNull(cferror);
    return result;
}

- (void)testSystemTrust_MoreThan5Years
{
    [self setTestRootAsSystem:_testValidityPeriodsRootHash];
    SecCertificateRef root = SecCertificateCreateWithBytes(NULL, _testValidityPeriodsRoot, sizeof(_testValidityPeriodsRoot));
    SecCertificateRef leaf = SecCertificateCreateWithBytes(NULL, _testLeaf_66Months, sizeof(_testLeaf_66Months));

    NSError *error = nil;
    XCTAssertFalse([self runTrustEvaluation:@[(__bridge id)leaf] anchors:@[(__bridge id)root] error:&error],
                   "system-trusted 66 month cert succeeded");

    [self removeTestRootAsSystem];
    CFReleaseNull(root);
    CFReleaseNull(leaf);
}

- (void)testSystemTrust_LessThan5Years_BeforeJul2016
{
    [self setTestRootAsSystem:_testValidityPeriodsRootHash];
    SecCertificateRef root = SecCertificateCreateWithBytes(NULL, _testValidityPeriodsRoot, sizeof(_testValidityPeriodsRoot));
    SecCertificateRef leaf = SecCertificateCreateWithBytes(NULL, _testLeaf_5Years, sizeof(_testLeaf_5Years));

    NSError *error = nil;
    XCTAssertTrue([self runTrustEvaluation:@[(__bridge id)leaf] anchors:@[(__bridge id)root] error:&error],
                  "system-trusted 5 year cert issued before 1 July 2016 failed: %@", error);

    [self removeTestRootAsSystem];
    CFReleaseNull(root);
    CFReleaseNull(leaf);
}

- (void)testSystemTrust_MoreThan39Months_AfterJul2016
{
    [self setTestRootAsSystem:_testValidityPeriodsRootHash];
    SecCertificateRef root = SecCertificateCreateWithBytes(NULL, _testValidityPeriodsRoot, sizeof(_testValidityPeriodsRoot));
    SecCertificateRef leaf = SecCertificateCreateWithBytes(NULL, _testLeaf_4Years, sizeof(_testLeaf_4Years));

    NSError *error = nil;
    XCTAssertFalse([self runTrustEvaluation:@[(__bridge id)leaf] anchors:@[(__bridge id)root] error:&error],
                   "system-trusted 4 year cert issued after 1 July 2016 succeeded");

    [self removeTestRootAsSystem];
    CFReleaseNull(root);
    CFReleaseNull(leaf);
}

- (void)testSystemTrust_LessThan39Months_BeforeMar2018
{
    // This cert should be valid
    [self setTestRootAsSystem:_testValidityPeriodsRootHash];
    SecCertificateRef root = SecCertificateCreateWithBytes(NULL, _testValidityPeriodsRoot, sizeof(_testValidityPeriodsRoot));
    SecCertificateRef leaf = SecCertificateCreateWithBytes(NULL, _testLeaf_39Months, sizeof(_testLeaf_39Months));

    NSError *error = nil;
    XCTAssertTrue([self runTrustEvaluation:@[(__bridge id)leaf] anchors:@[(__bridge id)root] error:&error],
                  "system-trusted 39 month cert issued before 1 Mar 2018 failed: %@", error);

    [self removeTestRootAsSystem];
    CFReleaseNull(root);
    CFReleaseNull(leaf);
}

- (void)testSystemTrust_MoreThan825Days_AfterMar2018
{
    [self setTestRootAsSystem:_testValidityPeriodsRootHash];
    SecCertificateRef root = SecCertificateCreateWithBytes(NULL, _testValidityPeriodsRoot, sizeof(_testValidityPeriodsRoot));
    SecCertificateRef leaf = SecCertificateCreateWithBytes(NULL, _testLeaf_3Years, sizeof(_testLeaf_3Years));

    NSError *error = nil;
    XCTAssertFalse([self runTrustEvaluation:@[(__bridge id)leaf] anchors:@[(__bridge id)root] error:&error],
                   "system-trusted 3 year cert issued after 1 Mar 2018 succeeded");

    [self removeTestRootAsSystem];
    CFReleaseNull(root);
    CFReleaseNull(leaf);
}

- (void)testSystemTrust_LessThan825Days_AfterMar2018
{
    [self setTestRootAsSystem:_testValidityPeriodsRootHash];
    SecCertificateRef root = SecCertificateCreateWithBytes(NULL, _testValidityPeriodsRoot, sizeof(_testValidityPeriodsRoot));
    SecCertificateRef leaf = SecCertificateCreateWithBytes(NULL, _testLeaf_825Days, sizeof(_testLeaf_825Days));

    NSError *error = nil;
    XCTAssertTrue([self runTrustEvaluation:@[(__bridge id)leaf] anchors:@[(__bridge id)root] error:&error],
                  "system-trusted 825 day cert issued after 1 Mar 2018 failed: %@", error);

    [self removeTestRootAsSystem];
    CFReleaseNull(root);
    CFReleaseNull(leaf);
}

- (void)testAppTrustRoot_MoreThan825Days_AfterJul2019
{
    SecCertificateRef root = SecCertificateCreateWithBytes(NULL, _testValidityPeriodsRoot, sizeof(_testValidityPeriodsRoot));
    SecCertificateRef leaf = SecCertificateCreateWithBytes(NULL, _testLeaf_3Years, sizeof(_testLeaf_3Years));

    NSError *error = nil;
    XCTAssertFalse([self runTrustEvaluation:@[(__bridge id)leaf] anchors:@[(__bridge id)root] error:&error],
                   "app-trusted (root) 3 year cert issued after 1 Jul 2019 succeeded");

    CFReleaseNull(root);
    CFReleaseNull(leaf);
}

- (void)testAppTrustRoot_MoreThan825Days_BeforeJul2019
{
    SecCertificateRef root = SecCertificateCreateWithBytes(NULL, _testValidityPeriodsRoot, sizeof(_testValidityPeriodsRoot));
    SecCertificateRef leaf = SecCertificateCreateWithBytes(NULL, _testLeaf_66Months, sizeof(_testLeaf_66Months));

    NSError *error = nil;
    XCTAssertTrue([self runTrustEvaluation:@[(__bridge id)leaf] anchors:@[(__bridge id)root] error:&error],
                  "app-trusted (root) 66 month cert issued before 1 Jul 2019 failed: %@", error);

    CFReleaseNull(root);
    CFReleaseNull(leaf);
}

- (void)testAppTrustRoot_LessThan825Days_AfterJul2019
{
    SecCertificateRef root = SecCertificateCreateWithBytes(NULL, _testValidityPeriodsRoot, sizeof(_testValidityPeriodsRoot));
    SecCertificateRef leaf = SecCertificateCreateWithBytes(NULL, _testLeaf_825Days, sizeof(_testLeaf_825Days));

    NSError *error = nil;
    XCTAssertTrue([self runTrustEvaluation:@[(__bridge id)leaf] anchors:@[(__bridge id)root] error:&error],
                  "app-trusted (root) 825 day cert issued after 1 Jul 2019 failed: %@", error);

    CFReleaseNull(root);
    CFReleaseNull(leaf);
}

- (void)testAppTrustLeaf_MoreThan825Days_AfterJul2019
{
    SecCertificateRef leaf = SecCertificateCreateWithBytes(NULL, _testLeaf_3Years, sizeof(_testLeaf_3Years));

    NSError *error = nil;
    XCTAssertFalse([self runTrustEvaluation:@[(__bridge id)leaf] anchors:@[(__bridge id)leaf] error:&error],
                   "app-trusted 3 year cert issued after 1 Jul 2019 succeeded");

    CFReleaseNull(leaf);
}

- (void)testAppTrustLeaf_MoreThan825Days_BeforeJul2019
{
    SecCertificateRef leaf = SecCertificateCreateWithBytes(NULL, _testLeaf_66Months, sizeof(_testLeaf_66Months));

    NSError *error = nil;
    XCTAssertTrue([self runTrustEvaluation:@[(__bridge id)leaf] anchors:@[(__bridge id)leaf] error:&error],
                  "app-trusted 66 month cert issued before 1 Jul 2019 failed: %@", error);

    CFReleaseNull(leaf);
}

- (void)testAppTrustLeaf_LessThan825Days_AfterJul2019
{
    SecCertificateRef leaf = SecCertificateCreateWithBytes(NULL, _testLeaf_825Days, sizeof(_testLeaf_825Days));

    NSError *error = nil;
    XCTAssertTrue([self runTrustEvaluation:@[(__bridge id)leaf] anchors:@[(__bridge id)leaf] error:&error],
                  "app-trusted 825 day cert issued after 1 Jul 2019 failed: %@", error);

    CFReleaseNull(leaf);
}

#if !TARGET_OS_BRIDGE // bridgeOS doesn't have trust settings
- (void)testUserTrustRoot_MoreThan825Days_AfterJul2019
{
    SecCertificateRef root = SecCertificateCreateWithBytes(NULL, _testValidityPeriodsRoot, sizeof(_testValidityPeriodsRoot));
    SecCertificateRef leaf = SecCertificateCreateWithBytes(NULL, _testLeaf_3Years, sizeof(_testLeaf_3Years));
    id persistentRef = [self addTrustSettingsForCert:root];
    NSArray *certs = @[(__bridge id)leaf, (__bridge id)root];

    NSError *error = nil;
    XCTAssertFalse([self runTrustEvaluation:certs anchors:nil error:&error],
                  "user-trusted (root) 3 year cert issued after 1 Jul 2019 succeeded");

    [self removeTrustSettingsForCert:root persistentRef:persistentRef];
    CFReleaseNull(root);
    CFReleaseNull(leaf);
}

- (void)testUserTrustRoot_MoreThan825Days_BeforeJul2019
{
    SecCertificateRef root = SecCertificateCreateWithBytes(NULL, _testValidityPeriodsRoot, sizeof(_testValidityPeriodsRoot));
    SecCertificateRef leaf = SecCertificateCreateWithBytes(NULL, _testLeaf_66Months, sizeof(_testLeaf_66Months));
    id persistentRef = [self addTrustSettingsForCert:root];
    NSArray *certs = @[(__bridge id)leaf, (__bridge id)root];

    NSError *error = nil;
    XCTAssertTrue([self runTrustEvaluation:certs anchors:nil error:&error],
                  "user-trusted (root) 66 month cert issued before 1 Jul 2019 failed: %@", error);

    [self removeTrustSettingsForCert:root persistentRef:persistentRef];
    CFReleaseNull(root);
    CFReleaseNull(leaf);
}

- (void)testUserTrustRoot_LessThan825Days_AfterJul2019
{
    SecCertificateRef root = SecCertificateCreateWithBytes(NULL, _testValidityPeriodsRoot, sizeof(_testValidityPeriodsRoot));
    SecCertificateRef leaf = SecCertificateCreateWithBytes(NULL, _testLeaf_825Days, sizeof(_testLeaf_825Days));
    id persistentRef = [self addTrustSettingsForCert:root];
    NSArray *certs = @[(__bridge id)leaf, (__bridge id)root];

    NSError *error = nil;
    XCTAssertTrue([self runTrustEvaluation:certs anchors:nil error:&error],
                  "app-trusted (root) 825 day cert issued after 1 Jul 2019 failed: %@", error);

    [self removeTrustSettingsForCert:root persistentRef:persistentRef];
    CFReleaseNull(root);
    CFReleaseNull(leaf);
}

- (void)testUserTrustLeaf_MoreThan825Days_AfterJul2019
{
    SecCertificateRef leaf = SecCertificateCreateWithBytes(NULL, _testLeaf_3Years, sizeof(_testLeaf_3Years));
    id persistentRef = [self addTrustSettingsForCert:leaf];

    NSError *error = nil;
    XCTAssertTrue([self runTrustEvaluation:@[(__bridge id)leaf] anchors:nil error:&error],
                  "user-trusted leaf 3 year cert issued after 1 Jul 2019 failed: %@", error);

    [self removeTrustSettingsForCert:leaf persistentRef:persistentRef];
    CFReleaseNull(leaf);
}

- (void)testUserTrustLeaf_MoreThan825Days_BeforeJul2019
{
    SecCertificateRef leaf = SecCertificateCreateWithBytes(NULL, _testLeaf_66Months, sizeof(_testLeaf_66Months));
    id persistentRef = [self addTrustSettingsForCert:leaf];

    NSError *error = nil;
    XCTAssertTrue([self runTrustEvaluation:@[(__bridge id)leaf] anchors:nil error:&error],
                  "user-trusted leaf 66 month cert issued before 1 Jul 2019 failed: %@", error);

    [self removeTrustSettingsForCert:leaf persistentRef:persistentRef];
    CFReleaseNull(leaf);
}

- (void)testUserTrustLeaf_LessThan825Days_AfterJul2019
{
    SecCertificateRef leaf = SecCertificateCreateWithBytes(NULL, _testLeaf_825Days, sizeof(_testLeaf_825Days));
    id persistentRef = [self addTrustSettingsForCert:leaf];

    NSError *error = nil;
    XCTAssertTrue([self runTrustEvaluation:@[(__bridge id)leaf] anchors:nil error:&error],
                  "user-trusted leaf 825 day cert issued after 1 Jul 2019 failed: %@", error);

    [self removeTrustSettingsForCert:leaf persistentRef:persistentRef];
    CFReleaseNull(leaf);
}

- (void)testUserDistrustLeaf_MoreThan825Days_AfterJul2019
{
    SecCertificateRef leaf = SecCertificateCreateWithBytes(NULL, _testLeaf_3Years, sizeof(_testLeaf_3Years));
    id persistentRef = [self addTrustSettingsForCert:leaf trustSettings: @{ (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultDeny)}];

    NSError *error = nil;
    XCTAssertFalse([self runTrustEvaluation:@[(__bridge id)leaf] anchors:nil error:&error],
                  "user-denied leaf 3 year cert issued after 1 Jul 2019 suceeded");

    [self removeTrustSettingsForCert:leaf persistentRef:persistentRef];
    CFReleaseNull(leaf);
}

- (void)testUserUnspecifiedLeaf_MoreThan825Days_AfterJul2019
{
    SecCertificateRef root = SecCertificateCreateWithBytes(NULL, _testValidityPeriodsRoot, sizeof(_testValidityPeriodsRoot));
    SecCertificateRef leaf = SecCertificateCreateWithBytes(NULL, _testLeaf_3Years, sizeof(_testLeaf_3Years));
    id persistentRef = [self addTrustSettingsForCert:leaf trustSettings: @{ (__bridge NSString*)kSecTrustSettingsResult: @(kSecTrustSettingsResultUnspecified)}];

    NSError *error = nil;
    XCTAssertFalse([self runTrustEvaluation:@[(__bridge id)leaf] anchors:@[(__bridge id)root] error:&error],
                  "user-unspecified trust leaf 3 year cert issued after 1 Jul 2019 succeeded");

    [self removeTrustSettingsForCert:leaf persistentRef:persistentRef];
    CFReleaseNull(leaf);
    CFReleaseNull(root);
}
#endif // !TARGET_OS_BRIDGE

@end
