/*
 * 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.X509Certificate;
import java.io.File;

/*
 * Test for ensuring an OCSPResponse is fresh.
 *
 * According to RFC 5019, clients must be able to determine OCSPResponse
 * freshness based on an accurate source of time. OCSP clock skew can be set via
 * com.sun.security.ocsp.clockSkew system property.
 *
 * Test scenario: - a certificate is good - an application tries to check
 * revocation status of certificate via OCSP - time difference between OCSP
 * client and OCSP responder is less than OCSP clock skew
 *
 * Expected result: successful validation
 *
 */

/*
 * @test
 * @author Shivangi Gupta
 * @library ../../common ../../common/bcpkix-jdk15on.jar ../../common/bcprov-jdk15on.jar
 * @run main/othervm/policy=freshOCSPpolicy -Djava.security.manager
 * FreshOCSPResponseTest
 */
public class FreshOCSPResponseTest {

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

    private final int ocspResponderTimeSkew = 900000; // 15 minutes

    private final int ocspClockSkew = 1200; // 20 minutes

    public static void main(String[] args) throws Exception {
        FreshOCSPResponseTest test = new FreshOCSPResponseTest();
        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 (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");
        }
    }

    /*
     * @param args Command line parameters
     */
    private void runTest(String[] args) throws Exception {
        parseArgs(args);
        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();
        simpleOcspResponder.setTimeSkew(ocspResponderTimeSkew);
        Utils.sleep(5);
        // 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"));
        System.out.println(
                "Testing with OCSP skew value that is greater than time difference between client and OCSP responder");
        System.out.println("Expected result: successful validation");
        Utils.doOcspValidation(cert, trustedCert, simpleOcspResponderPort);
        System.out.println("Test passed");
    }
}
