/*
 * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
import java.security.PrivateKey;
import java.security.cert.CertPathValidatorException;
import java.security.cert.X509Certificate;
import java.io.File;

/**
 * Test for incorrect value of com.sun.security.ocsp.clockSkew system property.
 * The test checks that incorrect values are processed correctly: OCSP clock
 * skew should be set to default value.
 *
 * Test scenario: - a certificate is good - an application tries to check
 * revocation status of certificate via OCSP - com.sun.security.ocsp.clockSkew
 * system property is set to incorrect value - first, the test runs validation
 * if time on client and server sides is the same, successful validation is
 * expected - next, the test runs validation if time on client and server sides
 * is different, validation failure is expected
 *
 */

/*
 * @test
 * @author Shivangi Gupta
 * @library ../../common ../../common/bcpkix-jdk15on.jar ../../common/bcprov-jdk15on.jar
 * @clean *
 * @run main/othervm/policy=freshOCSPpolicy -Djava.security.manager
 * OCSPClockSkewTest 0
 * @run main/othervm/policy=freshOCSPpolicy -Djava.security.manager
 * OCSPClockSkewTest string
 * @run main/othervm/policy=freshOCSPpolicy -Djava.security.manager
 * OCSPClockSkewTest -1
 * @run main/othervm/policy=freshOCSPpolicy -Djava.security.manager
 * OCSPClockSkewTest 2147483648
 * @run main/othervm/policy=freshOCSPpolicy -Djava.security.manager
 * OCSPClockSkewTest
 */
public class OCSPClockSkewTest {

    private static final String WORK_DIR = System.getProperty("test.src", ".");
    private X509Certificate cert;
    private X509Certificate trustedCert;
    private PrivateKey ocspResponderKey;
    private String ocspClockSkew;

    private final int ocspResponderTimeSkew = 3600000; // 1 hour

    public static void main(String[] args) throws Exception {
        OCSPClockSkewTest test = new OCSPClockSkewTest();
        test.runTest(args);
    }

    private void parseArgs(String[] args) throws Exception {
        String BASE = WORK_DIR.substring(0, WORK_DIR.indexOf("RevocationChecking") + "RevocationChecking".length());
        String certFile = BASE + File.separator + "common" + File.separator + "data" + File.separator + "ca"
                + File.separator + "valid.pem";
        String trustedCertFile = BASE + File.separator + "common" + File.separator + "data" + File.separator + "ca"
                + File.separator + "root.pem";
        String ocspResponderKeyFile = BASE + File.separator + "common" + File.separator + "data" + File.separator + "ca"
                + File.separator + "ocsp_responder_key";
        cert = Utils.getCertFromFile(certFile);
        trustedCert = Utils.getCertFromFile(trustedCertFile);
        ocspResponderKey = Utils.loadRsaPrivateKey(ocspResponderKeyFile);

        if (args.length >= 1) {
            ocspClockSkew = args[0];
        }

        if (cert == null) {
            throw new IllegalArgumentException("Certificate is not set");
        }

        if (trustedCert == null) {
            throw new IllegalArgumentException("Trusted certificate is not set");
        }

        if (ocspResponderKey == null) {
            throw new IllegalArgumentException("OCSP responder key is not set");
        }
    }

    private void runTest(String[] args) throws Exception {
        parseArgs(args);

        // Set maximum allowable clock skew to be used for the OCSP check
        System.setProperty("com.sun.security.ocsp.clockSkew", String.valueOf(ocspClockSkew));
        System.out.println("com.sun.security.ocsp.clockSkew" + System.getProperty("com.sun.security.ocsp.clockSkew"));

        // Start OCSP responder
        SimpleOCSPResponderDataBase ocspResponderDatabase = new SimpleOCSPResponderDataBase();
        ocspResponderDatabase.addGood(cert.getSerialNumber());
        int simpleOcspResponderPort = Utils.getFreePort();
        SimpleOCSPResponder simpleOcspResponder = new SimpleOCSPResponder(simpleOcspResponderPort,
                ocspResponderDatabase, "SHA1withRSA", ocspResponderKey);
        simpleOcspResponder.setDaemon(true);
        simpleOcspResponder.start();

        Utils.sleep(5);

        System.out.println(
                "Run validation if time on client and server sides is the same. Successful validation is expected");
        Utils.doOcspValidation(cert, trustedCert, simpleOcspResponderPort);

        System.out.println(
                "Run validation if time on client and server sides is different. Validation failure is expected");
        simpleOcspResponder.setTimeSkew(ocspResponderTimeSkew);
        try {
            Utils.doOcspValidation(cert, trustedCert, simpleOcspResponderPort);
            throw new Exception("Test failed: CertPathValidatorException was expected");
        } catch (CertPathValidatorException e) {
            System.out.println("Got CertPathValidatorException" + e.getMessage());
            System.out.println("Expected CertPathValidatorException was thrown");
        }
        System.out.println("Test passed");
    }
}
