Add PolicyImplTest for Certificate Transparency

A new FakeX509Certificate class is added, based on MockX509Certificate
from AOSP SslCertificateTest.

Bug: 319829948
Test: atest CtsLibcoreTestCases:com.android.org.conscrypt.ct.PolicyImplTest
Change-Id: Ib9ae572bb873eea39b7f394d4e558f7acc78eb48
diff --git a/platform/src/test/java/org/conscrypt/ct/PolicyImplTest.java b/platform/src/test/java/org/conscrypt/ct/PolicyImplTest.java
new file mode 100644
index 0000000..7322999
--- /dev/null
+++ b/platform/src/test/java/org/conscrypt/ct/PolicyImplTest.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.conscrypt.ct;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.conscrypt.java.security.cert.FakeX509Certificate;
+import org.junit.Assume;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.security.PublicKey;
+import java.security.cert.X509Certificate;
+
+@RunWith(JUnit4.class)
+public class PolicyImplTest {
+    private static LogInfo usableOp1Log1;
+    private static LogInfo usableOp1Log2;
+    private static LogInfo retiredOp1Log;
+    private static LogInfo usableOp2Log;
+    private static LogInfo retiredOp2Log;
+    private static SignedCertificateTimestamp embeddedSCT;
+
+    private static class FakePublicKey implements PublicKey {
+        static final long serialVersionUID = 1;
+        final byte[] key;
+
+        FakePublicKey(byte[] key) {
+            this.key = key;
+        }
+
+        @Override
+        public byte[] getEncoded() {
+            return this.key;
+        }
+
+        @Override
+        public String getAlgorithm() {
+            return "";
+        }
+
+        @Override
+        public String getFormat() {
+            return "";
+        }
+    }
+
+    @BeforeClass
+    public static void setUp() {
+        /* Defines LogInfo for the tests. Only a subset of the attributes are
+         * expected to be used, namely the LogID (based on the public key), the
+         * operator name and the log state.
+         */
+        usableOp1Log1 = new LogInfo.Builder()
+                                .setPublicKey(new FakePublicKey(new byte[] {0x01}))
+                                .setUrl("")
+                                .setOperator("operator 1")
+                                .setState(LogInfo.STATE_USABLE)
+                                .build();
+        usableOp1Log2 = new LogInfo.Builder()
+                                .setPublicKey(new FakePublicKey(new byte[] {0x02}))
+                                .setUrl("")
+                                .setOperator("operator 1")
+                                .setState(LogInfo.STATE_USABLE)
+                                .build();
+        retiredOp1Log = new LogInfo.Builder()
+                                .setPublicKey(new FakePublicKey(new byte[] {0x03}))
+                                .setUrl("")
+                                .setOperator("operator 1")
+                                .setState(LogInfo.STATE_RETIRED)
+                                .build();
+        usableOp2Log = new LogInfo.Builder()
+                               .setPublicKey(new FakePublicKey(new byte[] {0x04}))
+                               .setUrl("")
+                               .setOperator("operator 2")
+                               .setState(LogInfo.STATE_USABLE)
+                               .build();
+        retiredOp2Log = new LogInfo.Builder()
+                                .setPublicKey(new FakePublicKey(new byte[] {0x05}))
+                                .setUrl("")
+                                .setOperator("operator 2")
+                                .setState(LogInfo.STATE_RETIRED)
+                                .build();
+        /* Only the origin of the SCT is used during the evaluation for policy
+         * compliance. The signature is validated at the previous step (see
+         * the Verifier class).
+         */
+        embeddedSCT = new SignedCertificateTimestamp(SignedCertificateTimestamp.Version.V1, null, 0,
+                null, null, SignedCertificateTimestamp.Origin.EMBEDDED);
+    }
+
+    @Test
+    public void emptyVerificationResult() throws Exception {
+        Policy p = new PolicyImpl();
+        VerificationResult result = new VerificationResult();
+
+        X509Certificate leaf = new FakeX509Certificate();
+        assertFalse("An empty VerificationResult", p.doesResultConformToPolicy(result, leaf));
+    }
+
+    @Test
+    public void validVerificationResult() throws Exception {
+        Policy p = new PolicyImpl();
+
+        VerifiedSCT vsct1 = new VerifiedSCT.Builder(embeddedSCT)
+                                    .setStatus(VerifiedSCT.Status.VALID)
+                                    .setLogInfo(usableOp1Log1)
+                                    .build();
+
+        VerifiedSCT vsct2 = new VerifiedSCT.Builder(embeddedSCT)
+                                    .setStatus(VerifiedSCT.Status.VALID)
+                                    .setLogInfo(usableOp2Log)
+                                    .build();
+
+        VerificationResult result = new VerificationResult();
+        result.add(vsct1);
+        result.add(vsct2);
+
+        X509Certificate leaf = new FakeX509Certificate();
+        assertTrue("Two valid SCTs from different operators",
+                p.doesResultConformToPolicy(result, leaf));
+    }
+
+    @Test
+    public void validWithRetiredVerificationResult() throws Exception {
+        Policy p = new PolicyImpl();
+
+        VerifiedSCT vsct1 = new VerifiedSCT.Builder(embeddedSCT)
+                                    .setStatus(VerifiedSCT.Status.VALID)
+                                    .setLogInfo(retiredOp1Log)
+                                    .build();
+
+        VerifiedSCT vsct2 = new VerifiedSCT.Builder(embeddedSCT)
+                                    .setStatus(VerifiedSCT.Status.VALID)
+                                    .setLogInfo(usableOp2Log)
+                                    .build();
+
+        VerificationResult result = new VerificationResult();
+        result.add(vsct1);
+        result.add(vsct2);
+
+        X509Certificate leaf = new FakeX509Certificate();
+        assertTrue("One valid, one retired SCTs from different operators",
+                p.doesResultConformToPolicy(result, leaf));
+    }
+
+    @Test
+    public void invalidOneSctVerificationResult() throws Exception {
+        Policy p = new PolicyImpl();
+
+        VerifiedSCT vsct1 = new VerifiedSCT.Builder(embeddedSCT)
+                                    .setStatus(VerifiedSCT.Status.VALID)
+                                    .setLogInfo(usableOp1Log1)
+                                    .build();
+
+        VerificationResult result = new VerificationResult();
+        result.add(vsct1);
+
+        X509Certificate leaf = new FakeX509Certificate();
+        assertFalse("One valid SCT", p.doesResultConformToPolicy(result, leaf));
+    }
+
+    @Test
+    public void invalidTwoSctsVerificationResult() throws Exception {
+        Policy p = new PolicyImpl();
+
+        VerifiedSCT vsct1 = new VerifiedSCT.Builder(embeddedSCT)
+                                    .setStatus(VerifiedSCT.Status.VALID)
+                                    .setLogInfo(retiredOp1Log)
+                                    .build();
+
+        VerifiedSCT vsct2 = new VerifiedSCT.Builder(embeddedSCT)
+                                    .setStatus(VerifiedSCT.Status.VALID)
+                                    .setLogInfo(retiredOp2Log)
+                                    .build();
+
+        VerificationResult result = new VerificationResult();
+        result.add(vsct1);
+        result.add(vsct2);
+
+        X509Certificate leaf = new FakeX509Certificate();
+        assertFalse("Two retired SCTs from different operators",
+                p.doesResultConformToPolicy(result, leaf));
+    }
+}
diff --git a/repackaged/platform/src/test/java/com/android/org/conscrypt/ct/PolicyImplTest.java b/repackaged/platform/src/test/java/com/android/org/conscrypt/ct/PolicyImplTest.java
new file mode 100644
index 0000000..030f670
--- /dev/null
+++ b/repackaged/platform/src/test/java/com/android/org/conscrypt/ct/PolicyImplTest.java
@@ -0,0 +1,205 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.org.conscrypt.ct;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.android.org.conscrypt.java.security.cert.FakeX509Certificate;
+import java.security.PublicKey;
+import java.security.cert.X509Certificate;
+import org.junit.Assume;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+@RunWith(JUnit4.class)
+public class PolicyImplTest {
+    private static LogInfo usableOp1Log1;
+    private static LogInfo usableOp1Log2;
+    private static LogInfo retiredOp1Log;
+    private static LogInfo usableOp2Log;
+    private static LogInfo retiredOp2Log;
+    private static SignedCertificateTimestamp embeddedSCT;
+
+    private static class FakePublicKey implements PublicKey {
+        static final long serialVersionUID = 1;
+        final byte[] key;
+
+        FakePublicKey(byte[] key) {
+            this.key = key;
+        }
+
+        @Override
+        public byte[] getEncoded() {
+            return this.key;
+        }
+
+        @Override
+        public String getAlgorithm() {
+            return "";
+        }
+
+        @Override
+        public String getFormat() {
+            return "";
+        }
+    }
+
+    @BeforeClass
+    public static void setUp() {
+        /* Defines LogInfo for the tests. Only a subset of the attributes are
+         * expected to be used, namely the LogID (based on the public key), the
+         * operator name and the log state.
+         */
+        usableOp1Log1 = new LogInfo.Builder()
+                                .setPublicKey(new FakePublicKey(new byte[] {0x01}))
+                                .setUrl("")
+                                .setOperator("operator 1")
+                                .setState(LogInfo.STATE_USABLE)
+                                .build();
+        usableOp1Log2 = new LogInfo.Builder()
+                                .setPublicKey(new FakePublicKey(new byte[] {0x02}))
+                                .setUrl("")
+                                .setOperator("operator 1")
+                                .setState(LogInfo.STATE_USABLE)
+                                .build();
+        retiredOp1Log = new LogInfo.Builder()
+                                .setPublicKey(new FakePublicKey(new byte[] {0x03}))
+                                .setUrl("")
+                                .setOperator("operator 1")
+                                .setState(LogInfo.STATE_RETIRED)
+                                .build();
+        usableOp2Log = new LogInfo.Builder()
+                               .setPublicKey(new FakePublicKey(new byte[] {0x04}))
+                               .setUrl("")
+                               .setOperator("operator 2")
+                               .setState(LogInfo.STATE_USABLE)
+                               .build();
+        retiredOp2Log = new LogInfo.Builder()
+                                .setPublicKey(new FakePublicKey(new byte[] {0x05}))
+                                .setUrl("")
+                                .setOperator("operator 2")
+                                .setState(LogInfo.STATE_RETIRED)
+                                .build();
+        /* Only the origin of the SCT is used during the evaluation for policy
+         * compliance. The signature is validated at the previous step (see
+         * the Verifier class).
+         */
+        embeddedSCT = new SignedCertificateTimestamp(SignedCertificateTimestamp.Version.V1, null, 0,
+                null, null, SignedCertificateTimestamp.Origin.EMBEDDED);
+    }
+
+    @Test
+    public void emptyVerificationResult() throws Exception {
+        Policy p = new PolicyImpl();
+        VerificationResult result = new VerificationResult();
+
+        X509Certificate leaf = new FakeX509Certificate();
+        assertFalse("An empty VerificationResult", p.doesResultConformToPolicy(result, leaf));
+    }
+
+    @Test
+    public void validVerificationResult() throws Exception {
+        Policy p = new PolicyImpl();
+
+        VerifiedSCT vsct1 = new VerifiedSCT.Builder(embeddedSCT)
+                                    .setStatus(VerifiedSCT.Status.VALID)
+                                    .setLogInfo(usableOp1Log1)
+                                    .build();
+
+        VerifiedSCT vsct2 = new VerifiedSCT.Builder(embeddedSCT)
+                                    .setStatus(VerifiedSCT.Status.VALID)
+                                    .setLogInfo(usableOp2Log)
+                                    .build();
+
+        VerificationResult result = new VerificationResult();
+        result.add(vsct1);
+        result.add(vsct2);
+
+        X509Certificate leaf = new FakeX509Certificate();
+        assertTrue("Two valid SCTs from different operators",
+                p.doesResultConformToPolicy(result, leaf));
+    }
+
+    @Test
+    public void validWithRetiredVerificationResult() throws Exception {
+        Policy p = new PolicyImpl();
+
+        VerifiedSCT vsct1 = new VerifiedSCT.Builder(embeddedSCT)
+                                    .setStatus(VerifiedSCT.Status.VALID)
+                                    .setLogInfo(retiredOp1Log)
+                                    .build();
+
+        VerifiedSCT vsct2 = new VerifiedSCT.Builder(embeddedSCT)
+                                    .setStatus(VerifiedSCT.Status.VALID)
+                                    .setLogInfo(usableOp2Log)
+                                    .build();
+
+        VerificationResult result = new VerificationResult();
+        result.add(vsct1);
+        result.add(vsct2);
+
+        X509Certificate leaf = new FakeX509Certificate();
+        assertTrue("One valid, one retired SCTs from different operators",
+                p.doesResultConformToPolicy(result, leaf));
+    }
+
+    @Test
+    public void invalidOneSctVerificationResult() throws Exception {
+        Policy p = new PolicyImpl();
+
+        VerifiedSCT vsct1 = new VerifiedSCT.Builder(embeddedSCT)
+                                    .setStatus(VerifiedSCT.Status.VALID)
+                                    .setLogInfo(usableOp1Log1)
+                                    .build();
+
+        VerificationResult result = new VerificationResult();
+        result.add(vsct1);
+
+        X509Certificate leaf = new FakeX509Certificate();
+        assertFalse("One valid SCT", p.doesResultConformToPolicy(result, leaf));
+    }
+
+    @Test
+    public void invalidTwoSctsVerificationResult() throws Exception {
+        Policy p = new PolicyImpl();
+
+        VerifiedSCT vsct1 = new VerifiedSCT.Builder(embeddedSCT)
+                                    .setStatus(VerifiedSCT.Status.VALID)
+                                    .setLogInfo(retiredOp1Log)
+                                    .build();
+
+        VerifiedSCT vsct2 = new VerifiedSCT.Builder(embeddedSCT)
+                                    .setStatus(VerifiedSCT.Status.VALID)
+                                    .setLogInfo(retiredOp2Log)
+                                    .build();
+
+        VerificationResult result = new VerificationResult();
+        result.add(vsct1);
+        result.add(vsct2);
+
+        X509Certificate leaf = new FakeX509Certificate();
+        assertFalse("Two retired SCTs from different operators",
+                p.doesResultConformToPolicy(result, leaf));
+    }
+}
diff --git a/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/cert/FakeX509Certificate.java b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/cert/FakeX509Certificate.java
new file mode 100644
index 0000000..f4b55f3
--- /dev/null
+++ b/repackaged/testing/src/main/java/com/android/org/conscrypt/java/security/cert/FakeX509Certificate.java
@@ -0,0 +1,171 @@
+/* GENERATED SOURCE. DO NOT MODIFY. */
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.org.conscrypt.java.security.cert;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Set;
+
+/**
+ * @hide This class is not part of the Android public SDK API
+ */
+public class FakeX509Certificate extends X509Certificate {
+    @Override
+    public void checkValidity()
+            throws CertificateExpiredException, CertificateNotYetValidException {}
+
+    @Override
+    public void checkValidity(Date date)
+            throws CertificateExpiredException, CertificateNotYetValidException {}
+
+    @Override
+    public int getBasicConstraints() {
+        return 0;
+    }
+
+    @Override
+    public Principal getIssuerDN() {
+        return new MockPrincipal();
+    }
+
+    @Override
+    public boolean[] getIssuerUniqueID() {
+        return null;
+    }
+
+    @Override
+    public boolean[] getKeyUsage() {
+        return null;
+    }
+
+    @Override
+    public Date getNotAfter() {
+        return new Date(System.currentTimeMillis());
+    }
+
+    @Override
+    public Date getNotBefore() {
+        return new Date(System.currentTimeMillis() - 1000);
+    }
+
+    @Override
+    public BigInteger getSerialNumber() {
+        return null;
+    }
+
+    @Override
+    public String getSigAlgName() {
+        return null;
+    }
+
+    @Override
+    public String getSigAlgOID() {
+        return null;
+    }
+
+    @Override
+    public byte[] getSigAlgParams() {
+        return null;
+    }
+
+    @Override
+    public byte[] getSignature() {
+        return null;
+    }
+
+    @Override
+    public Principal getSubjectDN() {
+        return new MockPrincipal();
+    }
+
+    class MockPrincipal implements Principal {
+        public String getName() {
+            return null;
+        }
+    }
+    @Override
+    public boolean[] getSubjectUniqueID() {
+        return null;
+    }
+
+    @Override
+    public byte[] getTBSCertificate() throws CertificateEncodingException {
+        return null;
+    }
+
+    @Override
+    public int getVersion() {
+        return 0;
+    }
+
+    @Override
+    public byte[] getEncoded() throws CertificateEncodingException {
+        return null;
+    }
+
+    @Override
+    public PublicKey getPublicKey() {
+        return null;
+    }
+
+    @Override
+    public String toString() {
+        return null;
+    }
+
+    @Override
+    public void verify(PublicKey key)
+            throws CertificateException, NoSuchAlgorithmException, InvalidKeyException,
+                   NoSuchProviderException, SignatureException {}
+
+    @Override
+    public void verify(PublicKey key, String sigProvider)
+            throws CertificateException, NoSuchAlgorithmException, InvalidKeyException,
+                   NoSuchProviderException, SignatureException {}
+
+    @Override
+    public Set<String> getCriticalExtensionOIDs() {
+        return null;
+    }
+
+    @Override
+    public byte[] getExtensionValue(String oid) {
+        return null;
+    }
+
+    @Override
+    public Set<String> getNonCriticalExtensionOIDs() {
+        return null;
+    }
+
+    @Override
+    public boolean hasUnsupportedCriticalExtension() {
+        return false;
+    }
+}
diff --git a/testing/src/main/java/org/conscrypt/java/security/cert/FakeX509Certificate.java b/testing/src/main/java/org/conscrypt/java/security/cert/FakeX509Certificate.java
new file mode 100644
index 0000000..ed61cc4
--- /dev/null
+++ b/testing/src/main/java/org/conscrypt/java/security/cert/FakeX509Certificate.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.conscrypt.java.security.cert;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.Set;
+
+public class FakeX509Certificate extends X509Certificate {
+    @Override
+    public void checkValidity()
+            throws CertificateExpiredException, CertificateNotYetValidException {}
+
+    @Override
+    public void checkValidity(Date date)
+            throws CertificateExpiredException, CertificateNotYetValidException {}
+
+    @Override
+    public int getBasicConstraints() {
+        return 0;
+    }
+
+    @Override
+    public Principal getIssuerDN() {
+        return new MockPrincipal();
+    }
+
+    @Override
+    public boolean[] getIssuerUniqueID() {
+        return null;
+    }
+
+    @Override
+    public boolean[] getKeyUsage() {
+        return null;
+    }
+
+    @Override
+    public Date getNotAfter() {
+        return new Date(System.currentTimeMillis());
+    }
+
+    @Override
+    public Date getNotBefore() {
+        return new Date(System.currentTimeMillis() - 1000);
+    }
+
+    @Override
+    public BigInteger getSerialNumber() {
+        return null;
+    }
+
+    @Override
+    public String getSigAlgName() {
+        return null;
+    }
+
+    @Override
+    public String getSigAlgOID() {
+        return null;
+    }
+
+    @Override
+    public byte[] getSigAlgParams() {
+        return null;
+    }
+
+    @Override
+    public byte[] getSignature() {
+        return null;
+    }
+
+    @Override
+    public Principal getSubjectDN() {
+        return new MockPrincipal();
+    }
+
+    class MockPrincipal implements Principal {
+        public String getName() {
+            return null;
+        }
+    }
+    @Override
+    public boolean[] getSubjectUniqueID() {
+        return null;
+    }
+
+    @Override
+    public byte[] getTBSCertificate() throws CertificateEncodingException {
+        return null;
+    }
+
+    @Override
+    public int getVersion() {
+        return 0;
+    }
+
+    @Override
+    public byte[] getEncoded() throws CertificateEncodingException {
+        return null;
+    }
+
+    @Override
+    public PublicKey getPublicKey() {
+        return null;
+    }
+
+    @Override
+    public String toString() {
+        return null;
+    }
+
+    @Override
+    public void verify(PublicKey key)
+            throws CertificateException, NoSuchAlgorithmException, InvalidKeyException,
+                   NoSuchProviderException, SignatureException {}
+
+    @Override
+    public void verify(PublicKey key, String sigProvider)
+            throws CertificateException, NoSuchAlgorithmException, InvalidKeyException,
+                   NoSuchProviderException, SignatureException {}
+
+    @Override
+    public Set<String> getCriticalExtensionOIDs() {
+        return null;
+    }
+
+    @Override
+    public byte[] getExtensionValue(String oid) {
+        return null;
+    }
+
+    @Override
+    public Set<String> getNonCriticalExtensionOIDs() {
+        return null;
+    }
+
+    @Override
+    public boolean hasUnsupportedCriticalExtension() {
+        return false;
+    }
+}