Revert "Upstream multiple AOSP changes (#1221)" (#1225)
This reverts commit a9a7e6d91f70433701b7bd531245dc0fae377602.
diff --git a/android/src/main/java/org/conscrypt/Platform.java b/android/src/main/java/org/conscrypt/Platform.java
index b212d4d..64c9769 100644
--- a/android/src/main/java/org/conscrypt/Platform.java
+++ b/android/src/main/java/org/conscrypt/Platform.java
@@ -60,8 +60,8 @@
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.StandardConstants;
import javax.net.ssl.X509TrustManager;
-import org.conscrypt.ct.LogStore;
-import org.conscrypt.ct.Policy;
+import org.conscrypt.ct.CTLogStore;
+import org.conscrypt.ct.CTPolicy;
import org.conscrypt.metrics.CipherSuite;
import org.conscrypt.metrics.ConscryptStatsLog;
import org.conscrypt.metrics.Protocol;
@@ -884,11 +884,11 @@
return null;
}
- static LogStore newDefaultLogStore() {
+ static CTLogStore newDefaultLogStore() {
return null;
}
- static Policy newDefaultPolicy() {
+ static CTPolicy newDefaultPolicy(CTLogStore logStore) {
return null;
}
@@ -955,12 +955,4 @@
public static boolean isTlsV1Deprecated() {
return true;
}
-
- public static boolean isTlsV1Filtered() {
- return false;
- }
-
- public static boolean isTlsV1Supported() {
- return false;
- }
}
diff --git a/common/src/main/java/org/conscrypt/ArrayUtils.java b/common/src/main/java/org/conscrypt/ArrayUtils.java
index 5b4d68f..d946713 100644
--- a/common/src/main/java/org/conscrypt/ArrayUtils.java
+++ b/common/src/main/java/org/conscrypt/ArrayUtils.java
@@ -74,11 +74,4 @@
}
return result;
}
-
- /**
- * Checks if given array is null or has zero elements.
- */
- public static <T> boolean isEmpty(T[] array) {
- return array == null || array.length == 0;
- }
}
diff --git a/common/src/main/java/org/conscrypt/ByteArray.java b/common/src/main/java/org/conscrypt/ByteArray.java
index 3e97eb5..bfc544f 100644
--- a/common/src/main/java/org/conscrypt/ByteArray.java
+++ b/common/src/main/java/org/conscrypt/ByteArray.java
@@ -21,12 +21,11 @@
/**
* Byte array wrapper for hashtable use. Implements equals() and hashCode().
*/
-@Internal
-public final class ByteArray {
+final class ByteArray {
private final byte[] bytes;
private final int hashCode;
- public ByteArray(byte[] bytes) {
+ ByteArray(byte[] bytes) {
this.bytes = bytes;
this.hashCode = Arrays.hashCode(bytes);
}
@@ -38,9 +37,6 @@
@Override
public boolean equals(Object o) {
- if (o == this) {
- return true;
- }
if (!(o instanceof ByteArray)) {
return false;
}
diff --git a/common/src/main/java/org/conscrypt/NativeCrypto.java b/common/src/main/java/org/conscrypt/NativeCrypto.java
index 33f44fa..1f7005f 100644
--- a/common/src/main/java/org/conscrypt/NativeCrypto.java
+++ b/common/src/main/java/org/conscrypt/NativeCrypto.java
@@ -789,8 +789,8 @@
// --- SSL handling --------------------------------------------------------
static final String OBSOLETE_PROTOCOL_SSLV3 = "SSLv3";
- static final String DEPRECATED_PROTOCOL_TLSV1 = "TLSv1";
- static final String DEPRECATED_PROTOCOL_TLSV1_1 = "TLSv1.1";
+ private static final String DEPRECATED_PROTOCOL_TLSV1 = "TLSv1";
+ private static final String DEPRECATED_PROTOCOL_TLSV1_1 = "TLSv1.1";
private static final String SUPPORTED_PROTOCOL_TLSV1_2 = "TLSv1.2";
static final String SUPPORTED_PROTOCOL_TLSV1_3 = "TLSv1.3";
diff --git a/common/src/main/java/org/conscrypt/NativeSsl.java b/common/src/main/java/org/conscrypt/NativeSsl.java
index 7d260bc..79369ca 100644
--- a/common/src/main/java/org/conscrypt/NativeSsl.java
+++ b/common/src/main/java/org/conscrypt/NativeSsl.java
@@ -308,10 +308,8 @@
if (parameters.getEnabledProtocols().length == 0 && parameters.isEnabledProtocolsFiltered) {
throw new SSLHandshakeException("No enabled protocols; "
- + NativeCrypto.OBSOLETE_PROTOCOL_SSLV3 + ", "
- + NativeCrypto.DEPRECATED_PROTOCOL_TLSV1
- + " and " + NativeCrypto.DEPRECATED_PROTOCOL_TLSV1_1
- + " are no longer supported and were filtered from the list");
+ + NativeCrypto.OBSOLETE_PROTOCOL_SSLV3
+ + " is no longer supported and was filtered from the list");
}
NativeCrypto.setEnabledProtocols(ssl, this, parameters.enabledProtocols);
NativeCrypto.setEnabledCipherSuites(
diff --git a/common/src/main/java/org/conscrypt/OpenSSLKey.java b/common/src/main/java/org/conscrypt/OpenSSLKey.java
index 4249b8e..e5e81f7 100644
--- a/common/src/main/java/org/conscrypt/OpenSSLKey.java
+++ b/common/src/main/java/org/conscrypt/OpenSSLKey.java
@@ -32,8 +32,7 @@
/**
* Represents a BoringSSL {@code EVP_PKEY}.
*/
-@Internal
-public final class OpenSSLKey {
+final class OpenSSLKey {
private final NativeRef.EVP_PKEY ctx;
private final boolean wrapped;
@@ -256,7 +255,7 @@
*
* @throws InvalidKeyException if parsing fails
*/
- public static OpenSSLKey fromPublicKeyPemInputStream(InputStream is)
+ static OpenSSLKey fromPublicKeyPemInputStream(InputStream is)
throws InvalidKeyException {
OpenSSLBIOInputStream bis = new OpenSSLBIOInputStream(is, true);
try {
@@ -273,7 +272,7 @@
}
}
- public PublicKey getPublicKey() throws NoSuchAlgorithmException {
+ PublicKey getPublicKey() throws NoSuchAlgorithmException {
switch (NativeCrypto.EVP_PKEY_type(ctx)) {
case NativeConstants.EVP_PKEY_RSA:
return new OpenSSLRSAPublicKey(this);
diff --git a/common/src/main/java/org/conscrypt/SSLParametersImpl.java b/common/src/main/java/org/conscrypt/SSLParametersImpl.java
index 58e1c08..c38da79 100644
--- a/common/src/main/java/org/conscrypt/SSLParametersImpl.java
+++ b/common/src/main/java/org/conscrypt/SSLParametersImpl.java
@@ -144,20 +144,8 @@
}
// initialize the list of cipher suites and protocols enabled by default
- if (protocols == null) {
- enabledProtocols = NativeCrypto.getDefaultProtocols().clone();
- } else {
- String[] filteredProtocols =
- filterFromProtocols(protocols, Arrays.asList(!Platform.isTlsV1Filtered()
- ? new String[0]
- : new String[] {
- NativeCrypto.OBSOLETE_PROTOCOL_SSLV3,
- NativeCrypto.DEPRECATED_PROTOCOL_TLSV1,
- NativeCrypto.DEPRECATED_PROTOCOL_TLSV1_1,
- }));
- isEnabledProtocolsFiltered = protocols.length != filteredProtocols.length;
- enabledProtocols = NativeCrypto.checkEnabledProtocols(filteredProtocols).clone();
- }
+ enabledProtocols = NativeCrypto.checkEnabledProtocols(
+ protocols == null ? NativeCrypto.getDefaultProtocols() : protocols).clone();
boolean x509CipherSuitesNeeded = (x509KeyManager != null) || (x509TrustManager != null);
boolean pskCipherSuitesNeeded = pskKeyManager != null;
enabledCipherSuites = getDefaultCipherSuites(
@@ -294,13 +282,7 @@
throw new IllegalArgumentException("protocols == null");
}
String[] filteredProtocols =
- filterFromProtocols(protocols, Arrays.asList(!Platform.isTlsV1Filtered()
- ? new String[0]
- : new String[] {
- NativeCrypto.OBSOLETE_PROTOCOL_SSLV3,
- NativeCrypto.DEPRECATED_PROTOCOL_TLSV1,
- NativeCrypto.DEPRECATED_PROTOCOL_TLSV1_1,
- }));
+ filterFromProtocols(protocols, NativeCrypto.OBSOLETE_PROTOCOL_SSLV3);
isEnabledProtocolsFiltered = protocols.length != filteredProtocols.length;
enabledProtocols = NativeCrypto.checkEnabledProtocols(filteredProtocols).clone();
}
diff --git a/common/src/main/java/org/conscrypt/TrustManagerImpl.java b/common/src/main/java/org/conscrypt/TrustManagerImpl.java
index 400228d..1bacf7e 100644
--- a/common/src/main/java/org/conscrypt/TrustManagerImpl.java
+++ b/common/src/main/java/org/conscrypt/TrustManagerImpl.java
@@ -34,12 +34,6 @@
package org.conscrypt;
-import org.conscrypt.ct.LogStore;
-import org.conscrypt.ct.Policy;
-import org.conscrypt.ct.PolicyCompliance;
-import org.conscrypt.ct.VerificationResult;
-import org.conscrypt.ct.Verifier;
-
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.Socket;
@@ -69,13 +63,16 @@
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;
-
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.X509ExtendedTrustManager;
+import org.conscrypt.ct.CTLogStore;
+import org.conscrypt.ct.CTPolicy;
+import org.conscrypt.ct.CTVerificationResult;
+import org.conscrypt.ct.CTVerifier;
/**
*
@@ -142,9 +139,8 @@
private final Exception err;
private final CertificateFactory factory;
private final CertBlocklist blocklist;
- private LogStore ctLogStore;
- private Verifier ctVerifier;
- private Policy ctPolicy;
+ private CTVerifier ctVerifier;
+ private CTPolicy ctPolicy;
private ConscryptHostnameVerifier hostnameVerifier;
@@ -167,16 +163,18 @@
this(keyStore, manager, certStore, null);
}
- public TrustManagerImpl(KeyStore keyStore, CertPinManager manager, ConscryptCertStore certStore,
- CertBlocklist blocklist) {
+ public TrustManagerImpl(KeyStore keyStore, CertPinManager manager,
+ ConscryptCertStore certStore,
+ CertBlocklist blocklist) {
this(keyStore, manager, certStore, blocklist, null, null, null);
}
/**
* For testing only.
*/
- public TrustManagerImpl(KeyStore keyStore, CertPinManager manager, ConscryptCertStore certStore,
- CertBlocklist blocklist, LogStore ctLogStore, Verifier ctVerifier, Policy ctPolicy) {
+ public TrustManagerImpl(KeyStore keyStore, CertPinManager manager,
+ ConscryptCertStore certStore, CertBlocklist blocklist, CTLogStore ctLogStore,
+ CTVerifier ctVerifier, CTPolicy ctPolicy) {
CertPathValidator validatorLocal = null;
CertificateFactory factoryLocal = null;
KeyStore rootKeyStoreLocal = null;
@@ -216,7 +214,7 @@
}
if (ctPolicy == null) {
- ctPolicy = Platform.newDefaultPolicy();
+ ctPolicy = Platform.newDefaultPolicy(ctLogStore);
}
this.pinManager = manager;
@@ -229,10 +227,8 @@
this.acceptedIssuers = acceptedIssuersLocal;
this.err = errLocal;
this.blocklist = blocklist;
- this.ctLogStore = ctLogStore;
- this.ctVerifier = new Verifier(ctLogStore);
+ this.ctVerifier = new CTVerifier(ctLogStore);
this.ctPolicy = ctPolicy;
- ctLogStore.setPolicy(ctPolicy);
}
@SuppressWarnings("JdkObsolete") // KeyStore#aliases is the only API available
@@ -684,7 +680,7 @@
if (!clientAuth &&
(ctEnabledOverride || (host != null && Platform
.isCTVerificationRequired(host)))) {
- checkCT(wholeChain, ocspData, tlsSctData);
+ checkCT(host, wholeChain, ocspData, tlsSctData);
}
if (untrustedChain.isEmpty()) {
@@ -730,23 +726,15 @@
}
}
- private void checkCT(List<X509Certificate> chain, byte[] ocspData, byte[] tlsData)
+ private void checkCT(String host, List<X509Certificate> chain, byte[] ocspData, byte[] tlsData)
throws CertificateException {
- if (ctLogStore.getState() != LogStore.State.COMPLIANT) {
- /* Fail open. For some reason, the LogStore is not usable. It could
- * be because there is no log list available or that the log list
- * is too old (according to the policy). */
- return;
- }
- VerificationResult result =
+ CTVerificationResult result =
ctVerifier.verifySignedCertificateTimestamps(chain, tlsData, ocspData);
- X509Certificate leaf = chain.get(0);
- PolicyCompliance compliance = ctPolicy.doesResultConformToPolicy(result, leaf);
- if (compliance != PolicyCompliance.COMPLY) {
+ if (!ctPolicy.doesResultConformToPolicy(result, host,
+ chain.toArray(new X509Certificate[chain.size()]))) {
throw new CertificateException(
- "Certificate chain does not conform to required transparency policy: "
- + compliance.name());
+ "Certificate chain does not conform to required transparency policy.");
}
}
@@ -1037,12 +1025,12 @@
}
// Replace the CTVerifier. For testing only.
- public void setCTVerifier(Verifier verifier) {
+ public void setCTVerifier(CTVerifier verifier) {
this.ctVerifier = verifier;
}
// Replace the CTPolicy. For testing only.
- public void setCTPolicy(Policy policy) {
+ public void setCTPolicy(CTPolicy policy) {
this.ctPolicy = policy;
}
}
diff --git a/common/src/main/java/org/conscrypt/ct/Constants.java b/common/src/main/java/org/conscrypt/ct/CTConstants.java
similarity index 98%
rename from common/src/main/java/org/conscrypt/ct/Constants.java
rename to common/src/main/java/org/conscrypt/ct/CTConstants.java
index 71bcab2..76133d9 100644
--- a/common/src/main/java/org/conscrypt/ct/Constants.java
+++ b/common/src/main/java/org/conscrypt/ct/CTConstants.java
@@ -19,7 +19,7 @@
import org.conscrypt.Internal;
@Internal
-public class Constants {
+public class CTConstants {
public static final String X509_SCT_LIST_OID = "1.3.6.1.4.1.11129.2.4.2";
public static final String OCSP_SCT_LIST_OID = "1.3.6.1.4.1.11129.2.4.5";
@@ -41,3 +41,4 @@
public static final int ISSUER_KEY_HASH_LENGTH = 32;
}
+
diff --git a/common/src/main/java/org/conscrypt/ct/CTLogInfo.java b/common/src/main/java/org/conscrypt/ct/CTLogInfo.java
new file mode 100644
index 0000000..c2e312a
--- /dev/null
+++ b/common/src/main/java/org/conscrypt/ct/CTLogInfo.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2015 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 java.security.InvalidKeyException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.util.Arrays;
+import org.conscrypt.Internal;
+
+/**
+ * Properties about a Certificate Transparency Log.
+ * This object stores information about a CT log, its public key, description and URL.
+ * It allows verification of SCTs against the log's public key.
+ */
+@Internal
+public class CTLogInfo {
+ private final byte[] logId;
+ private final PublicKey publicKey;
+ private final String description;
+ private final String url;
+
+ public CTLogInfo(PublicKey publicKey, String description, String url) {
+ try {
+ this.logId = MessageDigest.getInstance("SHA-256")
+ .digest(publicKey.getEncoded());
+ } catch (NoSuchAlgorithmException e) {
+ // SHA-256 is guaranteed to be available
+ throw new RuntimeException(e);
+ }
+
+ this.publicKey = publicKey;
+ this.description = description;
+ this.url = url;
+ }
+
+ /**
+ * Get the log's ID, that is the SHA-256 hash of it's public key
+ */
+ public byte[] getID() {
+ return logId;
+ }
+
+ public PublicKey getPublicKey() {
+ return publicKey;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof CTLogInfo)) {
+ return false;
+ }
+
+ CTLogInfo that = (CTLogInfo)other;
+ return
+ this.publicKey.equals(that.publicKey) &&
+ this.description.equals(that.description) &&
+ this.url.equals(that.url);
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 1;
+ hash = hash * 31 + publicKey.hashCode();
+ hash = hash * 31 + description.hashCode();
+ hash = hash * 31 + url.hashCode();
+
+ return hash;
+ }
+
+ /**
+ * Verify the signature of a signed certificate timestamp for the given certificate entry
+ * against the log's public key.
+ *
+ * @return the result of the verification
+ */
+ public VerifiedSCT.Status verifySingleSCT(SignedCertificateTimestamp sct,
+ CertificateEntry entry) {
+ if (!Arrays.equals(sct.getLogID(), getID())) {
+ return VerifiedSCT.Status.UNKNOWN_LOG;
+ }
+
+ byte[] toVerify;
+ try {
+ toVerify = sct.encodeTBS(entry);
+ } catch (SerializationException e) {
+ return VerifiedSCT.Status.INVALID_SCT;
+ }
+
+ Signature signature;
+ try {
+ String algorithm = sct.getSignature().getAlgorithm();
+ signature = Signature.getInstance(algorithm);
+ } catch (NoSuchAlgorithmException e) {
+ return VerifiedSCT.Status.INVALID_SCT;
+ }
+
+ try {
+ signature.initVerify(publicKey);
+ } catch (InvalidKeyException e) {
+ return VerifiedSCT.Status.INVALID_SCT;
+ }
+
+ try {
+ signature.update(toVerify);
+ if (!signature.verify(sct.getSignature().getSignature())) {
+ return VerifiedSCT.Status.INVALID_SIGNATURE;
+ }
+ return VerifiedSCT.Status.VALID;
+ } catch (SignatureException e) {
+ // This only happens if the signature is not initialized,
+ // but we call initVerify just before, so it should never do
+ throw new RuntimeException(e);
+ }
+ }
+}
+
diff --git a/common/src/main/java/org/conscrypt/ct/PolicyCompliance.java b/common/src/main/java/org/conscrypt/ct/CTLogStore.java
similarity index 81%
rename from common/src/main/java/org/conscrypt/ct/PolicyCompliance.java
rename to common/src/main/java/org/conscrypt/ct/CTLogStore.java
index d889ee7..bf30d66 100644
--- a/common/src/main/java/org/conscrypt/ct/PolicyCompliance.java
+++ b/common/src/main/java/org/conscrypt/ct/CTLogStore.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2024 The Android Open Source Project
+ * Copyright (C) 2015 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.
@@ -19,8 +19,7 @@
import org.conscrypt.Internal;
@Internal
-public enum PolicyCompliance {
- COMPLY,
- NOT_ENOUGH_SCTS,
- NOT_ENOUGH_DIVERSE_SCTS
+public interface CTLogStore {
+ CTLogInfo getKnownLog(byte[] logId);
}
+
diff --git a/common/src/main/java/org/conscrypt/ct/Policy.java b/common/src/main/java/org/conscrypt/ct/CTPolicy.java
similarity index 81%
rename from common/src/main/java/org/conscrypt/ct/Policy.java
rename to common/src/main/java/org/conscrypt/ct/CTPolicy.java
index 5b3d95a..455cabd 100644
--- a/common/src/main/java/org/conscrypt/ct/Policy.java
+++ b/common/src/main/java/org/conscrypt/ct/CTPolicy.java
@@ -20,7 +20,7 @@
import org.conscrypt.Internal;
@Internal
-public interface Policy {
- boolean isLogStoreCompliant(LogStore store);
- PolicyCompliance doesResultConformToPolicy(VerificationResult result, X509Certificate leaf);
+public interface CTPolicy {
+ boolean doesResultConformToPolicy(CTVerificationResult result, String hostname,
+ X509Certificate[] chain);
}
diff --git a/common/src/main/java/org/conscrypt/ct/VerificationResult.java b/common/src/main/java/org/conscrypt/ct/CTVerificationResult.java
similarity index 75%
rename from common/src/main/java/org/conscrypt/ct/VerificationResult.java
rename to common/src/main/java/org/conscrypt/ct/CTVerificationResult.java
index 354b16a..b21e9ac 100644
--- a/common/src/main/java/org/conscrypt/ct/VerificationResult.java
+++ b/common/src/main/java/org/conscrypt/ct/CTVerificationResult.java
@@ -21,21 +21,13 @@
import java.util.List;
import org.conscrypt.Internal;
-/**
- * Container for verified SignedCertificateTimestamp.
- *
- * getValidSCTs returns SCTs which were found to match a known log and for
- * which the signature has been verified. There is no guarantee on the state of
- * the log (e.g., getLogInfo.getState() may return STATE_UNKNOWN). Further
- * verification on the compliance with the policy is performed in PolicyImpl.
- */
@Internal
-public class VerificationResult {
+public class CTVerificationResult {
private final ArrayList<VerifiedSCT> validSCTs = new ArrayList<VerifiedSCT>();
private final ArrayList<VerifiedSCT> invalidSCTs = new ArrayList<VerifiedSCT>();
public void add(VerifiedSCT result) {
- if (result.isValid()) {
+ if (result.status == VerifiedSCT.Status.VALID) {
validSCTs.add(result);
} else {
invalidSCTs.add(result);
@@ -50,3 +42,4 @@
return Collections.unmodifiableList(invalidSCTs);
}
}
+
diff --git a/common/src/main/java/org/conscrypt/ct/Verifier.java b/common/src/main/java/org/conscrypt/ct/CTVerifier.java
similarity index 73%
rename from common/src/main/java/org/conscrypt/ct/Verifier.java
rename to common/src/main/java/org/conscrypt/ct/CTVerifier.java
index 79d90d9..2f1f79b 100644
--- a/common/src/main/java/org/conscrypt/ct/Verifier.java
+++ b/common/src/main/java/org/conscrypt/ct/CTVerifier.java
@@ -27,18 +27,18 @@
import org.conscrypt.OpenSSLX509Certificate;
@Internal
-public class Verifier {
- private final LogStore store;
+public class CTVerifier {
+ private final CTLogStore store;
- public Verifier(LogStore store) {
+ public CTVerifier(CTLogStore store) {
this.store = store;
}
- public VerificationResult verifySignedCertificateTimestamps(List<X509Certificate> chain,
+ public CTVerificationResult verifySignedCertificateTimestamps(List<X509Certificate> chain,
byte[] tlsData, byte[] ocspData) throws CertificateEncodingException {
OpenSSLX509Certificate[] certs = new OpenSSLX509Certificate[chain.size()];
int i = 0;
- for (X509Certificate cert : chain) {
+ for(X509Certificate cert : chain) {
certs[i++] = OpenSSLX509Certificate.fromCertificate(cert);
}
return verifySignedCertificateTimestamps(certs, tlsData, ocspData);
@@ -50,7 +50,7 @@
* response, and verified against the list of known logs.
* @throws IllegalArgumentException if the chain is empty
*/
- public VerificationResult verifySignedCertificateTimestamps(OpenSSLX509Certificate[] chain,
+ public CTVerificationResult verifySignedCertificateTimestamps(OpenSSLX509Certificate[] chain,
byte[] tlsData, byte[] ocspData) throws CertificateEncodingException {
if (chain.length == 0) {
throw new IllegalArgumentException("Chain of certificates mustn't be empty.");
@@ -58,7 +58,7 @@
OpenSSLX509Certificate leaf = chain[0];
- VerificationResult result = new VerificationResult();
+ CTVerificationResult result = new CTVerificationResult();
List<SignedCertificateTimestamp> tlsScts = getSCTsFromTLSExtension(tlsData);
verifyExternalSCTs(tlsScts, leaf, result);
@@ -75,7 +75,8 @@
* The result of the verification for each sct is added to {@code result}.
*/
private void verifyEmbeddedSCTs(List<SignedCertificateTimestamp> scts,
- OpenSSLX509Certificate[] chain, VerificationResult result) {
+ OpenSSLX509Certificate[] chain,
+ CTVerificationResult result) {
// Avoid creating the cert entry if we don't need it
if (scts.isEmpty()) {
return;
@@ -98,7 +99,10 @@
return;
}
- verifySCTs(scts, precertEntry, result);
+ for (SignedCertificateTimestamp sct: scts) {
+ VerifiedSCT.Status status = verifySingleSCT(sct, precertEntry);
+ result.add(new VerifiedSCT(sct, status));
+ }
}
/**
@@ -107,7 +111,8 @@
* The result of the verification for each sct is added to {@code result}.
*/
private void verifyExternalSCTs(List<SignedCertificateTimestamp> scts,
- OpenSSLX509Certificate leaf, VerificationResult result) {
+ OpenSSLX509Certificate leaf,
+ CTVerificationResult result) {
// Avoid creating the cert entry if we don't need it
if (scts.isEmpty()) {
return;
@@ -121,38 +126,32 @@
return;
}
- verifySCTs(scts, x509Entry, result);
+ for (SignedCertificateTimestamp sct: scts) {
+ VerifiedSCT.Status status = verifySingleSCT(sct, x509Entry);
+ result.add(new VerifiedSCT(sct, status));
+ }
}
/**
- * Verify a list of SCTs.
+ * Verify a single SCT for the given Certificate Entry
*/
- private void verifySCTs(List<SignedCertificateTimestamp> scts, CertificateEntry certEntry,
- VerificationResult result) {
- for (SignedCertificateTimestamp sct : scts) {
- VerifiedSCT.Builder builder = new VerifiedSCT.Builder(sct);
- LogInfo log = store.getKnownLog(sct.getLogID());
- if (log == null) {
- builder.setStatus(VerifiedSCT.Status.UNKNOWN_LOG);
- } else {
- VerifiedSCT.Status status = log.verifySingleSCT(sct, certEntry);
- builder.setStatus(status);
- if (status == VerifiedSCT.Status.VALID) {
- builder.setLogInfo(log);
- }
- }
- result.add(builder.build());
+ private VerifiedSCT.Status verifySingleSCT(SignedCertificateTimestamp sct,
+ CertificateEntry certEntry) {
+ CTLogInfo log = store.getKnownLog(sct.getLogID());
+ if (log == null) {
+ return VerifiedSCT.Status.UNKNOWN_LOG;
}
+
+ return log.verifySingleSCT(sct, certEntry);
}
/**
* Add every SCT in {@code scts} to {@code result} with INVALID_SCT as status
*/
- private void markSCTsAsInvalid(
- List<SignedCertificateTimestamp> scts, VerificationResult result) {
- for (SignedCertificateTimestamp sct : scts) {
- VerifiedSCT.Builder builder = new VerifiedSCT.Builder(sct);
- result.add(builder.setStatus(VerifiedSCT.Status.INVALID_SCT).build());
+ private void markSCTsAsInvalid(List<SignedCertificateTimestamp> scts,
+ CTVerificationResult result) {
+ for (SignedCertificateTimestamp sct: scts) {
+ result.add(new VerifiedSCT(sct, VerifiedSCT.Status.INVALID_SCT));
}
}
@@ -164,25 +163,24 @@
* @param origin used to create the SignedCertificateTimestamp instances.
*/
@SuppressWarnings("MixedMutabilityReturnType")
- private static List<SignedCertificateTimestamp> getSCTsFromSCTList(
- byte[] data, SignedCertificateTimestamp.Origin origin) {
+ private static List<SignedCertificateTimestamp> getSCTsFromSCTList(byte[] data,
+ SignedCertificateTimestamp.Origin origin) {
if (data == null) {
return Collections.emptyList();
}
byte[][] sctList;
try {
- sctList = Serialization.readList(
- data, Constants.SCT_LIST_LENGTH_BYTES, Constants.SERIALIZED_SCT_LENGTH_BYTES);
+ sctList = Serialization.readList(data, CTConstants.SCT_LIST_LENGTH_BYTES,
+ CTConstants.SERIALIZED_SCT_LENGTH_BYTES);
} catch (SerializationException e) {
return Collections.emptyList();
}
List<SignedCertificateTimestamp> scts = new ArrayList<SignedCertificateTimestamp>();
- for (byte[] encodedSCT : sctList) {
- try {
- SignedCertificateTimestamp sct =
- SignedCertificateTimestamp.decode(encodedSCT, origin);
+ for (byte[] encodedSCT: sctList) {
+ try {
+ SignedCertificateTimestamp sct = SignedCertificateTimestamp.decode(encodedSCT, origin);
scts.add(sct);
} catch (SerializationException e) {
// Ignore errors
@@ -212,21 +210,23 @@
* issuer in order to identify the relevant SingleResponse from the OCSP response,
* or an empty list is returned
*/
- private List<SignedCertificateTimestamp> getSCTsFromOCSPResponse(
- byte[] data, OpenSSLX509Certificate[] chain) {
+ private List<SignedCertificateTimestamp> getSCTsFromOCSPResponse(byte[] data,
+ OpenSSLX509Certificate[] chain) {
if (data == null || chain.length < 2) {
return Collections.emptyList();
}
- byte[] extData = NativeCrypto.get_ocsp_single_extension(data, Constants.OCSP_SCT_LIST_OID,
- chain[0].getContext(), chain[0], chain[1].getContext(), chain[1]);
+ byte[] extData = NativeCrypto.get_ocsp_single_extension(data, CTConstants.OCSP_SCT_LIST_OID,
+ chain[0].getContext(), chain[0],
+ chain[1].getContext(), chain[1]);
if (extData == null) {
return Collections.emptyList();
}
try {
return getSCTsFromSCTList(
- Serialization.readDEROctetString(Serialization.readDEROctetString(extData)),
+ Serialization.readDEROctetString(
+ Serialization.readDEROctetString(extData)),
SignedCertificateTimestamp.Origin.OCSP_RESPONSE);
} catch (SerializationException e) {
return Collections.emptyList();
@@ -240,17 +240,19 @@
* to be parsed, an empty list is returned. Individual SCTs which fail to be parsed are ignored.
*/
private List<SignedCertificateTimestamp> getSCTsFromX509Extension(OpenSSLX509Certificate leaf) {
- byte[] extData = leaf.getExtensionValue(Constants.X509_SCT_LIST_OID);
+ byte[] extData = leaf.getExtensionValue(CTConstants.X509_SCT_LIST_OID);
if (extData == null) {
return Collections.emptyList();
}
try {
return getSCTsFromSCTList(
- Serialization.readDEROctetString(Serialization.readDEROctetString(extData)),
+ Serialization.readDEROctetString(
+ Serialization.readDEROctetString(extData)),
SignedCertificateTimestamp.Origin.EMBEDDED);
} catch (SerializationException e) {
return Collections.emptyList();
}
}
}
+
diff --git a/common/src/main/java/org/conscrypt/ct/CertificateEntry.java b/common/src/main/java/org/conscrypt/ct/CertificateEntry.java
index 137ded1..72ed530 100644
--- a/common/src/main/java/org/conscrypt/ct/CertificateEntry.java
+++ b/common/src/main/java/org/conscrypt/ct/CertificateEntry.java
@@ -61,8 +61,8 @@
} else if (entryType == LogEntryType.X509_ENTRY && issuerKeyHash != null) {
throw new IllegalArgumentException("unexpected issuerKeyHash for X509 entry.");
}
-
- if (issuerKeyHash != null && issuerKeyHash.length != Constants.ISSUER_KEY_HASH_LENGTH) {
+
+ if (issuerKeyHash != null && issuerKeyHash.length != CTConstants.ISSUER_KEY_HASH_LENGTH) {
throw new IllegalArgumentException("issuerKeyHash must be 32 bytes long");
}
@@ -83,11 +83,11 @@
public static CertificateEntry createForPrecertificate(OpenSSLX509Certificate leaf,
OpenSSLX509Certificate issuer) throws CertificateException {
try {
- if (!leaf.getNonCriticalExtensionOIDs().contains(Constants.X509_SCT_LIST_OID)) {
+ if (!leaf.getNonCriticalExtensionOIDs().contains(CTConstants.X509_SCT_LIST_OID)) {
throw new CertificateException("Certificate does not contain embedded signed timestamps");
}
- byte[] tbs = leaf.getTBSCertificateWithoutExtension(Constants.X509_SCT_LIST_OID);
+ byte[] tbs = leaf.getTBSCertificateWithoutExtension(CTConstants.X509_SCT_LIST_OID);
byte[] issuerKey = issuer.getPublicKey().getEncoded();
MessageDigest md = MessageDigest.getInstance("SHA-256");
@@ -124,11 +124,11 @@
* TLS encode the CertificateEntry structure.
*/
public void encode(OutputStream output) throws SerializationException {
- Serialization.writeNumber(output, entryType.ordinal(), Constants.LOG_ENTRY_TYPE_LENGTH);
+ Serialization.writeNumber(output, entryType.ordinal(), CTConstants.LOG_ENTRY_TYPE_LENGTH);
if (entryType == LogEntryType.PRECERT_ENTRY) {
Serialization.writeFixedBytes(output, issuerKeyHash);
}
- Serialization.writeVariableBytes(output, certificate, Constants.CERTIFICATE_LENGTH_BYTES);
+ Serialization.writeVariableBytes(output, certificate, CTConstants.CERTIFICATE_LENGTH_BYTES);
}
}
diff --git a/common/src/main/java/org/conscrypt/ct/DigitallySigned.java b/common/src/main/java/org/conscrypt/ct/DigitallySigned.java
index 15720d9..b5f4478 100644
--- a/common/src/main/java/org/conscrypt/ct/DigitallySigned.java
+++ b/common/src/main/java/org/conscrypt/ct/DigitallySigned.java
@@ -107,9 +107,10 @@
throws SerializationException {
try {
return new DigitallySigned(
- Serialization.readNumber(input, Constants.HASH_ALGORITHM_LENGTH),
- Serialization.readNumber(input, Constants.SIGNATURE_ALGORITHM_LENGTH),
- Serialization.readVariableBytes(input, Constants.SIGNATURE_LENGTH_BYTES));
+ Serialization.readNumber(input, CTConstants.HASH_ALGORITHM_LENGTH),
+ Serialization.readNumber(input, CTConstants.SIGNATURE_ALGORITHM_LENGTH),
+ Serialization.readVariableBytes(input, CTConstants.SIGNATURE_LENGTH_BYTES)
+ );
} catch (IllegalArgumentException e) {
throw new SerializationException(e);
}
diff --git a/common/src/main/java/org/conscrypt/ct/LogInfo.java b/common/src/main/java/org/conscrypt/ct/LogInfo.java
deleted file mode 100644
index 99c8139..0000000
--- a/common/src/main/java/org/conscrypt/ct/LogInfo.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright (C) 2015 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 java.security.InvalidKeyException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.security.PublicKey;
-import java.security.Signature;
-import java.security.SignatureException;
-import java.util.Arrays;
-import java.util.Objects;
-import org.conscrypt.Internal;
-
-/**
- * Properties about a Certificate Transparency Log.
- * This object stores information about a CT log, its public key, description and URL.
- * It allows verification of SCTs against the log's public key.
- */
-@Internal
-public class LogInfo {
- public static final int STATE_UNKNOWN = 0;
- public static final int STATE_PENDING = 1;
- public static final int STATE_QUALIFIED = 2;
- public static final int STATE_USABLE = 3;
- public static final int STATE_READONLY = 4;
- public static final int STATE_RETIRED = 5;
- public static final int STATE_REJECTED = 6;
-
- private final byte[] logId;
- private final PublicKey publicKey;
- private final int state;
- private final long stateTimestamp;
- private final String description;
- private final String url;
- private final String operator;
-
- private LogInfo(Builder builder) {
- /* Based on the required fields for the log list schema v3. Notably,
- * the state may be absent. The logId must match the public key, this
- * is validated in the builder. */
- Objects.requireNonNull(builder.logId);
- Objects.requireNonNull(builder.publicKey);
- Objects.requireNonNull(builder.url);
- Objects.requireNonNull(builder.operator);
-
- this.logId = builder.logId;
- this.publicKey = builder.publicKey;
- this.state = builder.state;
- this.stateTimestamp = builder.stateTimestamp;
- this.description = builder.description;
- this.url = builder.url;
- this.operator = builder.operator;
- }
-
- public static class Builder {
- private byte[] logId;
- private PublicKey publicKey;
- private int state;
- private long stateTimestamp;
- private String description;
- private String url;
- private String operator;
-
- public Builder setPublicKey(PublicKey publicKey) {
- Objects.requireNonNull(publicKey);
- this.publicKey = publicKey;
- try {
- this.logId = MessageDigest.getInstance("SHA-256").digest(publicKey.getEncoded());
- } catch (NoSuchAlgorithmException e) {
- // SHA-256 is guaranteed to be available
- throw new RuntimeException(e);
- }
- return this;
- }
-
- public Builder setState(int state, long timestamp) {
- if (state < 0 || state > STATE_REJECTED) {
- throw new IllegalArgumentException("invalid state value");
- }
- this.state = state;
- this.stateTimestamp = timestamp;
- return this;
- }
-
- public Builder setDescription(String description) {
- Objects.requireNonNull(description);
- this.description = description;
- return this;
- }
-
- public Builder setUrl(String url) {
- Objects.requireNonNull(url);
- this.url = url;
- return this;
- }
-
- public Builder setOperator(String operator) {
- Objects.requireNonNull(operator);
- this.operator = operator;
- return this;
- }
-
- public LogInfo build() {
- return new LogInfo(this);
- }
- }
-
- /**
- * Get the log's ID, that is the SHA-256 hash of it's public key
- */
- public byte[] getID() {
- return logId;
- }
-
- public PublicKey getPublicKey() {
- return publicKey;
- }
-
- public String getDescription() {
- return description;
- }
-
- public String getUrl() {
- return url;
- }
-
- public int getState() {
- return state;
- }
-
- public int getStateAt(long when) {
- if (when >= this.stateTimestamp) {
- return state;
- }
- return STATE_UNKNOWN;
- }
-
- public long getStateTimestamp() {
- return stateTimestamp;
- }
-
- public String getOperator() {
- return operator;
- }
-
- @Override
- public boolean equals(Object other) {
- if (this == other) {
- return true;
- }
- if (!(other instanceof LogInfo)) {
- return false;
- }
-
- LogInfo that = (LogInfo) other;
- return this.state == that.state && this.description.equals(that.description)
- && this.url.equals(that.url) && this.operator.equals(that.operator)
- && this.stateTimestamp == that.stateTimestamp
- && Arrays.equals(this.logId, that.logId);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(
- Arrays.hashCode(logId), description, url, state, stateTimestamp, operator);
- }
-
- /**
- * Verify the signature of a signed certificate timestamp for the given certificate entry
- * against the log's public key.
- *
- * @return the result of the verification
- */
- public VerifiedSCT.Status verifySingleSCT(
- SignedCertificateTimestamp sct, CertificateEntry entry) {
- if (!Arrays.equals(sct.getLogID(), getID())) {
- return VerifiedSCT.Status.UNKNOWN_LOG;
- }
-
- byte[] toVerify;
- try {
- toVerify = sct.encodeTBS(entry);
- } catch (SerializationException e) {
- return VerifiedSCT.Status.INVALID_SCT;
- }
-
- Signature signature;
- try {
- String algorithm = sct.getSignature().getAlgorithm();
- signature = Signature.getInstance(algorithm);
- } catch (NoSuchAlgorithmException e) {
- return VerifiedSCT.Status.INVALID_SCT;
- }
-
- try {
- signature.initVerify(publicKey);
- } catch (InvalidKeyException e) {
- return VerifiedSCT.Status.INVALID_SCT;
- }
-
- try {
- signature.update(toVerify);
- if (!signature.verify(sct.getSignature().getSignature())) {
- return VerifiedSCT.Status.INVALID_SIGNATURE;
- }
- return VerifiedSCT.Status.VALID;
- } catch (SignatureException e) {
- // This only happens if the signature is not initialized,
- // but we call initVerify just before, so it should never do
- throw new RuntimeException(e);
- }
- }
-}
diff --git a/common/src/main/java/org/conscrypt/ct/LogStore.java b/common/src/main/java/org/conscrypt/ct/LogStore.java
deleted file mode 100644
index 10e099c..0000000
--- a/common/src/main/java/org/conscrypt/ct/LogStore.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2015 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 org.conscrypt.Internal;
-
-@Internal
-public interface LogStore {
- public enum State {
- UNINITIALIZED,
- NOT_FOUND,
- MALFORMED,
- LOADED,
- COMPLIANT,
- NON_COMPLIANT,
- }
-
- void setPolicy(Policy policy);
-
- State getState();
-
- long getTimestamp();
-
- LogInfo getKnownLog(byte[] logId);
-}
diff --git a/common/src/main/java/org/conscrypt/ct/SignedCertificateTimestamp.java b/common/src/main/java/org/conscrypt/ct/SignedCertificateTimestamp.java
index 8ad3788..d23f9ed 100644
--- a/common/src/main/java/org/conscrypt/ct/SignedCertificateTimestamp.java
+++ b/common/src/main/java/org/conscrypt/ct/SignedCertificateTimestamp.java
@@ -87,16 +87,19 @@
*/
public static SignedCertificateTimestamp decode(InputStream input, Origin origin)
throws SerializationException {
- int version = Serialization.readNumber(input, Constants.VERSION_LENGTH);
+ int version = Serialization.readNumber(input, CTConstants.VERSION_LENGTH);
if (version != Version.V1.ordinal()) {
throw new SerializationException("Unsupported SCT version " + version);
}
- return new SignedCertificateTimestamp(Version.V1,
- Serialization.readFixedBytes(input, Constants.LOGID_LENGTH),
- Serialization.readLong(input, Constants.TIMESTAMP_LENGTH),
- Serialization.readVariableBytes(input, Constants.EXTENSIONS_LENGTH_BYTES),
- DigitallySigned.decode(input), origin);
+ return new SignedCertificateTimestamp(
+ Version.V1,
+ Serialization.readFixedBytes(input, CTConstants.LOGID_LENGTH),
+ Serialization.readLong(input, CTConstants.TIMESTAMP_LENGTH),
+ Serialization.readVariableBytes(input, CTConstants.EXTENSIONS_LENGTH_BYTES),
+ DigitallySigned.decode(input),
+ origin
+ );
}
/**
@@ -112,12 +115,12 @@
*/
public void encodeTBS(OutputStream output, CertificateEntry certEntry)
throws SerializationException {
- Serialization.writeNumber(output, version.ordinal(), Constants.VERSION_LENGTH);
+ Serialization.writeNumber(output, version.ordinal(), CTConstants.VERSION_LENGTH);
Serialization.writeNumber(output, SignatureType.CERTIFICATE_TIMESTAMP.ordinal(),
- Constants.SIGNATURE_TYPE_LENGTH);
- Serialization.writeNumber(output, timestamp, Constants.TIMESTAMP_LENGTH);
+ CTConstants.SIGNATURE_TYPE_LENGTH);
+ Serialization.writeNumber(output, timestamp, CTConstants.TIMESTAMP_LENGTH);
certEntry.encode(output);
- Serialization.writeVariableBytes(output, extensions, Constants.EXTENSIONS_LENGTH_BYTES);
+ Serialization.writeVariableBytes(output, extensions, CTConstants.EXTENSIONS_LENGTH_BYTES);
}
/**
diff --git a/common/src/main/java/org/conscrypt/ct/VerifiedSCT.java b/common/src/main/java/org/conscrypt/ct/VerifiedSCT.java
index 6c9c008..7eaf45d 100644
--- a/common/src/main/java/org/conscrypt/ct/VerifiedSCT.java
+++ b/common/src/main/java/org/conscrypt/ct/VerifiedSCT.java
@@ -16,7 +16,6 @@
package org.conscrypt.ct;
-import java.util.Objects;
import org.conscrypt.Internal;
/**
@@ -31,61 +30,12 @@
INVALID_SCT
}
- private final SignedCertificateTimestamp sct;
- private final Status status;
- private final LogInfo logInfo;
+ public final SignedCertificateTimestamp sct;
+ public final Status status;
- private VerifiedSCT(Builder builder) {
- Objects.requireNonNull(builder.sct);
- Objects.requireNonNull(builder.status);
- if (builder.status == Status.VALID) {
- Objects.requireNonNull(builder.logInfo);
- }
-
- this.sct = builder.sct;
- this.status = builder.status;
- this.logInfo = builder.logInfo;
- }
-
- public SignedCertificateTimestamp getSct() {
- return sct;
- }
-
- public Status getStatus() {
- return status;
- }
-
- public boolean isValid() {
- return status == Status.VALID;
- }
-
- public LogInfo getLogInfo() {
- return logInfo;
- }
-
- public static class Builder {
- private SignedCertificateTimestamp sct;
- private Status status;
- private LogInfo logInfo;
-
- public Builder(SignedCertificateTimestamp sct) {
- this.sct = sct;
- }
-
- public Builder setStatus(Status status) {
- this.status = status;
- return this;
- }
-
- public Builder setLogInfo(LogInfo logInfo) {
- Objects.requireNonNull(logInfo);
- this.logInfo = logInfo;
- return this;
- }
-
- public VerifiedSCT build() {
- return new VerifiedSCT(this);
- }
+ public VerifiedSCT(SignedCertificateTimestamp sct, Status status) {
+ this.sct = sct;
+ this.status = status;
}
}
diff --git a/common/src/test/java/org/conscrypt/ct/VerifierTest.java b/common/src/test/java/org/conscrypt/ct/CTVerifierTest.java
similarity index 64%
rename from common/src/test/java/org/conscrypt/ct/VerifierTest.java
rename to common/src/test/java/org/conscrypt/ct/CTVerifierTest.java
index e7b94ba..9aaf8db 100644
--- a/common/src/test/java/org/conscrypt/ct/VerifierTest.java
+++ b/common/src/test/java/org/conscrypt/ct/CTVerifierTest.java
@@ -30,44 +30,25 @@
import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
-public class VerifierTest {
+public class CTVerifierTest {
private OpenSSLX509Certificate ca;
private OpenSSLX509Certificate cert;
private OpenSSLX509Certificate certEmbedded;
- private Verifier ctVerifier;
+ private CTVerifier ctVerifier;
@Before
public void setUp() throws Exception {
ca = OpenSSLX509Certificate.fromX509PemInputStream(openTestFile("ca-cert.pem"));
cert = OpenSSLX509Certificate.fromX509PemInputStream(openTestFile("cert.pem"));
- certEmbedded =
- OpenSSLX509Certificate.fromX509PemInputStream(openTestFile("cert-ct-embedded.pem"));
+ certEmbedded = OpenSSLX509Certificate.fromX509PemInputStream(
+ openTestFile("cert-ct-embedded.pem"));
PublicKey key = TestUtils.readPublicKeyPemFile("ct-server-key-public.pem");
- final LogInfo log = new LogInfo.Builder()
- .setPublicKey(key)
- .setDescription("Test Log")
- .setUrl("http://example.com")
- .setOperator("LogOperator")
- .setState(LogInfo.STATE_USABLE, 1643709600000L)
- .build();
- LogStore store = new LogStore() {
+ final CTLogInfo log = new CTLogInfo(key, "Test Log", "foo");
+ CTLogStore store = new CTLogStore() {
@Override
- public void setPolicy(Policy policy) {}
-
- @Override
- public State getState() {
- return LogStore.State.COMPLIANT;
- }
-
- @Override
- public long getTimestamp() {
- return 0;
- }
-
- @Override
- public LogInfo getKnownLog(byte[] logId) {
+ public CTLogInfo getKnownLog(byte[] logId) {
if (Arrays.equals(logId, log.getID())) {
return log;
} else {
@@ -76,116 +57,120 @@
}
};
- ctVerifier = new Verifier(store);
+ ctVerifier = new CTVerifier(store);
}
@Test
public void test_verifySignedCertificateTimestamps_withOCSPResponse() throws Exception {
- OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] {cert, ca};
+ OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] { cert, ca };
byte[] ocspResponse = readTestFile("ocsp-response.der");
- VerificationResult result =
- ctVerifier.verifySignedCertificateTimestamps(chain, null, ocspResponse);
+ CTVerificationResult result =
+ ctVerifier.verifySignedCertificateTimestamps(chain, null, ocspResponse);
assertEquals(1, result.getValidSCTs().size());
assertEquals(0, result.getInvalidSCTs().size());
}
@Test
public void test_verifySignedCertificateTimestamps_withTLSExtension() throws Exception {
- OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] {cert, ca};
+ OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] { cert, ca };
byte[] tlsExtension = readTestFile("ct-signed-timestamp-list");
- VerificationResult result =
- ctVerifier.verifySignedCertificateTimestamps(chain, tlsExtension, null);
+ CTVerificationResult result =
+ ctVerifier.verifySignedCertificateTimestamps(chain, tlsExtension, null);
assertEquals(1, result.getValidSCTs().size());
assertEquals(0, result.getInvalidSCTs().size());
}
@Test
public void test_verifySignedCertificateTimestamps_withEmbeddedExtension() throws Exception {
- OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] {certEmbedded, ca};
+ OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] { certEmbedded, ca };
- VerificationResult result = ctVerifier.verifySignedCertificateTimestamps(chain, null, null);
+ CTVerificationResult result =
+ ctVerifier.verifySignedCertificateTimestamps(chain, null, null);
assertEquals(1, result.getValidSCTs().size());
assertEquals(0, result.getInvalidSCTs().size());
}
@Test
public void test_verifySignedCertificateTimestamps_withoutTimestamp() throws Exception {
- OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] {cert, ca};
+ OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] { cert, ca };
- VerificationResult result = ctVerifier.verifySignedCertificateTimestamps(chain, null, null);
+ CTVerificationResult result =
+ ctVerifier.verifySignedCertificateTimestamps(chain, null, null);
assertEquals(0, result.getValidSCTs().size());
assertEquals(0, result.getInvalidSCTs().size());
}
@Test
public void test_verifySignedCertificateTimestamps_withInvalidSignature() throws Exception {
- OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] {cert, ca};
+ OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] { cert, ca };
byte[] tlsExtension = readTestFile("ct-signed-timestamp-list-invalid");
- VerificationResult result =
- ctVerifier.verifySignedCertificateTimestamps(chain, tlsExtension, null);
+ CTVerificationResult result =
+ ctVerifier.verifySignedCertificateTimestamps(chain, tlsExtension, null);
assertEquals(0, result.getValidSCTs().size());
assertEquals(1, result.getInvalidSCTs().size());
- assertEquals(
- VerifiedSCT.Status.INVALID_SIGNATURE, result.getInvalidSCTs().get(0).getStatus());
+ assertEquals(VerifiedSCT.Status.INVALID_SIGNATURE,
+ result.getInvalidSCTs().get(0).status);
}
@Test
public void test_verifySignedCertificateTimestamps_withUnknownLog() throws Exception {
- OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] {cert, ca};
+ OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] { cert, ca };
byte[] tlsExtension = readTestFile("ct-signed-timestamp-list-unknown");
- VerificationResult result =
- ctVerifier.verifySignedCertificateTimestamps(chain, tlsExtension, null);
+ CTVerificationResult result =
+ ctVerifier.verifySignedCertificateTimestamps(chain, tlsExtension, null);
assertEquals(0, result.getValidSCTs().size());
assertEquals(1, result.getInvalidSCTs().size());
- assertEquals(VerifiedSCT.Status.UNKNOWN_LOG, result.getInvalidSCTs().get(0).getStatus());
+ assertEquals(VerifiedSCT.Status.UNKNOWN_LOG,
+ result.getInvalidSCTs().get(0).status);
}
@Test
public void test_verifySignedCertificateTimestamps_withInvalidEncoding() throws Exception {
- OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] {cert, ca};
+ OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] { cert, ca };
// Just some garbage data which will fail to deserialize
- byte[] tlsExtension = new byte[] {1, 2, 3, 4};
+ byte[] tlsExtension = new byte[] { 1, 2, 3, 4 };
- VerificationResult result =
- ctVerifier.verifySignedCertificateTimestamps(chain, tlsExtension, null);
+ CTVerificationResult result =
+ ctVerifier.verifySignedCertificateTimestamps(chain, tlsExtension, null);
assertEquals(0, result.getValidSCTs().size());
assertEquals(0, result.getInvalidSCTs().size());
}
@Test
public void test_verifySignedCertificateTimestamps_withInvalidOCSPResponse() throws Exception {
- OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] {cert, ca};
+ OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] { cert, ca };
// Just some garbage data which will fail to deserialize
- byte[] ocspResponse = new byte[] {1, 2, 3, 4};
+ byte[] ocspResponse = new byte[] { 1, 2, 3, 4 };
- VerificationResult result =
- ctVerifier.verifySignedCertificateTimestamps(chain, null, ocspResponse);
+ CTVerificationResult result =
+ ctVerifier.verifySignedCertificateTimestamps(chain, null, ocspResponse);
assertEquals(0, result.getValidSCTs().size());
assertEquals(0, result.getInvalidSCTs().size());
}
@Test
public void test_verifySignedCertificateTimestamps_withMultipleTimestamps() throws Exception {
- OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] {cert, ca};
+ OpenSSLX509Certificate[] chain = new OpenSSLX509Certificate[] { cert, ca };
byte[] tlsExtension = readTestFile("ct-signed-timestamp-list-invalid");
byte[] ocspResponse = readTestFile("ocsp-response.der");
- VerificationResult result =
- ctVerifier.verifySignedCertificateTimestamps(chain, tlsExtension, ocspResponse);
+ CTVerificationResult result =
+ ctVerifier.verifySignedCertificateTimestamps(chain, tlsExtension, ocspResponse);
assertEquals(1, result.getValidSCTs().size());
assertEquals(1, result.getInvalidSCTs().size());
assertEquals(SignedCertificateTimestamp.Origin.OCSP_RESPONSE,
- result.getValidSCTs().get(0).getSct().getOrigin());
+ result.getValidSCTs().get(0).sct.getOrigin());
assertEquals(SignedCertificateTimestamp.Origin.TLS_EXTENSION,
- result.getInvalidSCTs().get(0).getSct().getOrigin());
+ result.getInvalidSCTs().get(0).sct.getOrigin());
}
}
+
diff --git a/common/src/test/java/org/conscrypt/javax/net/ssl/SSLContextTest.java b/common/src/test/java/org/conscrypt/javax/net/ssl/SSLContextTest.java
index f24d864..40acd1b 100644
--- a/common/src/test/java/org/conscrypt/javax/net/ssl/SSLContextTest.java
+++ b/common/src/test/java/org/conscrypt/javax/net/ssl/SSLContextTest.java
@@ -119,16 +119,6 @@
}
@Test
- public void test_SSLContext_allProtocols() throws Exception {
- SSLConfigurationAsserts.assertSSLContextDefaultConfiguration(SSLContext.getDefault());
-
- for (String protocol : StandardNames.SSL_CONTEXT_PROTOCOLS_ALL) {
- SSLContext sslContext = SSLContext.getInstance(protocol);
- sslContext.init(null, null, null);
- }
- }
-
- @Test
public void test_SSLContext_pskOnlyConfiguration_defaultProviderOnly() throws Exception {
// Test the scenario where only a PSKKeyManager is provided and no TrustManagers are
// provided.
diff --git a/common/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketVersionCompatibilityTest.java b/common/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketVersionCompatibilityTest.java
index 24277ad..5ce4d5f 100644
--- a/common/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketVersionCompatibilityTest.java
+++ b/common/src/test/java/org/conscrypt/javax/net/ssl/SSLSocketVersionCompatibilityTest.java
@@ -16,16 +16,10 @@
package org.conscrypt.javax.net.ssl;
-import libcore.junit.util.SwitchTargetSdkVersionRule;
-import libcore.junit.util.SwitchTargetSdkVersionRule.TargetSdkVersion;
-
import static org.conscrypt.TestUtils.osName;
import static org.conscrypt.TestUtils.isOsx;
import static org.conscrypt.TestUtils.isLinux;
import static org.conscrypt.TestUtils.isWindows;
-import static org.conscrypt.TestUtils.isTlsV1Deprecated;
-import static org.conscrypt.TestUtils.isTlsV1Filtered;
-import static org.conscrypt.TestUtils.isTlsV1Supported;
import static org.conscrypt.TestUtils.UTF_8;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -115,9 +109,7 @@
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
-import org.junit.Rule;
import org.junit.Test;
-import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import tests.net.DelegatingSSLSocketFactory;
@@ -131,9 +123,6 @@
@RunWith(Parameterized.class)
public class SSLSocketVersionCompatibilityTest {
- @Rule
- public TestRule switchTargetSdkVersionRule = SwitchTargetSdkVersionRule.getInstance();
-
@Parameterized.Parameters(name = "{index}: {0} client, {1} server")
public static Iterable<Object[]> data() {
return Arrays.asList(new Object[][] {
@@ -1701,7 +1690,7 @@
@Test
public void test_SSLSocket_ClientHello_ALPN() throws Exception {
final String[] protocolList = new String[] { "h2", "http/1.1" };
-
+
ForEachRunner.runNamed(new ForEachRunner.Callback<SSLSocketFactory>() {
@Override
public void run(SSLSocketFactory sslSocketFactory) throws Exception {
@@ -1937,35 +1926,7 @@
}
@Test
- public void test_SSLSocket_TLSv1Supported() throws Exception {
- assumeTrue(isTlsV1Supported());
- TestSSLContext context = new TestSSLContext.Builder()
- .clientProtocol(clientVersion)
- .serverProtocol(serverVersion)
- .build();
- final SSLSocket client =
- (SSLSocket) context.clientContext.getSocketFactory().createSocket();
- client.setEnabledProtocols(new String[] {"TLSv1", "TLSv1.1"});
- assertEquals(2, client.getEnabledProtocols().length);
- }
-
- @TargetSdkVersion(35)
- @Test
- public void test_SSLSocket_SSLv3Unsupported_35() throws Exception {
- assumeFalse(isTlsV1Filtered());
- TestSSLContext context = new TestSSLContext.Builder()
- .clientProtocol(clientVersion)
- .serverProtocol(serverVersion)
- .build();
- final SSLSocket client =
- (SSLSocket) context.clientContext.getSocketFactory().createSocket();
- assertThrows(IllegalArgumentException.class, () -> client.setEnabledProtocols(new String[] {"SSLv3"}));
- assertThrows(IllegalArgumentException.class, () -> client.setEnabledProtocols(new String[] {"SSL"}));
- }
-
- @TargetSdkVersion(34)
- @Test
- public void test_SSLSocket_SSLv3Unsupported_34() throws Exception {
+ public void test_SSLSocket_SSLv3Unsupported() throws Exception {
TestSSLContext context = new TestSSLContext.Builder()
.clientProtocol(clientVersion)
.serverProtocol(serverVersion)
@@ -1983,40 +1944,6 @@
}
}
- @TargetSdkVersion(34)
- @Test
- public void test_TLSv1Filtered_34() throws Exception {
- TestSSLContext context = new TestSSLContext.Builder()
- .clientProtocol(clientVersion)
- .serverProtocol(serverVersion)
- .build();
- final SSLSocket client =
- (SSLSocket) context.clientContext.getSocketFactory().createSocket();
- client.setEnabledProtocols(new String[] {"TLSv1", "TLSv1.1", "TLSv1.2"});
- assertEquals(1, client.getEnabledProtocols().length);
- assertEquals("TLSv1.2", client.getEnabledProtocols()[0]);
- }
-
- @TargetSdkVersion(35)
- @Test
- public void test_TLSv1Filtered_35() throws Exception {
- assumeFalse(isTlsV1Filtered());
- TestSSLContext context = new TestSSLContext.Builder()
- .clientProtocol(clientVersion)
- .serverProtocol(serverVersion)
- .build();
- final SSLSocket client =
- (SSLSocket) context.clientContext.getSocketFactory().createSocket();
- assertThrows(IllegalArgumentException.class, () ->
- client.setEnabledProtocols(new String[] {"TLSv1", "TLSv1.1", "TLSv1.2"}));
- }
-
- @Test
- public void test_TLSv1Unsupported_notEnabled() throws Exception {
- assumeTrue(!isTlsV1Supported());
- assertTrue(isTlsV1Deprecated());
- }
-
// Under some circumstances, the file descriptor socket may get finalized but still
// be reused by the JDK's built-in HTTP connection reuse code. Ensure that a
// SocketException is thrown if that happens.
diff --git a/libcore-stub/src/main/java/libcore/net/NetworkSecurityPolicy.java b/libcore-stub/src/main/java/libcore/net/NetworkSecurityPolicy.java
deleted file mode 100644
index e7ca0f1..0000000
--- a/libcore-stub/src/main/java/libcore/net/NetworkSecurityPolicy.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2015 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 libcore.net;
-
-/**
- * Network security policy for this process/application.
- *
- * <p>Network stacks/components are expected to honor this policy. Components which can use the
- * Android framework API should be accessing this policy via the framework's
- * {@code android.security.NetworkSecurityPolicy} instead of via this class.
- *
- * <p>The policy currently consists of a single flag: whether cleartext network traffic is
- * permitted. See {@link #isCleartextTrafficPermitted()}.
- */
-public abstract class NetworkSecurityPolicy {
- private static volatile NetworkSecurityPolicy instance = new DefaultNetworkSecurityPolicy();
-
- public static NetworkSecurityPolicy getInstance() {
- return instance;
- }
-
- public static void setInstance(NetworkSecurityPolicy policy) {
- if (policy == null) {
- throw new NullPointerException("policy == null");
- }
- instance = policy;
- }
-
- /**
- * Returns {@code true} if cleartext network traffic (e.g. HTTP, FTP, XMPP, IMAP, SMTP --
- * without TLS or STARTTLS) is permitted for all network communications of this process.
- *
- * <p>{@link #isCleartextTrafficPermitted(String)} should be used to determine if cleartext
- * traffic is permitted for a specific host.
- *
- * <p>When cleartext network traffic is not permitted, the platform's components (e.g. HTTP
- * stacks, {@code WebView}, {@code MediaPlayer}) will refuse this process's requests to use
- * cleartext traffic. Third-party libraries are encouraged to do the same.
- *
- * <p>This flag is honored on a best effort basis because it's impossible to prevent all
- * cleartext traffic from an application given the level of access provided to applications on
- * Android. For example, there's no expectation that {@link java.net.Socket} API will honor this
- * flag. Luckily, most network traffic from apps is handled by higher-level network stacks which
- * can be made to honor this flag. Platform-provided network stacks (e.g. HTTP and FTP) honor
- * this flag from day one, and well-established third-party network stacks will eventually
- * honor it.
- */
- public abstract boolean isCleartextTrafficPermitted();
-
- /**
- * Returns {@code true} if cleartext network traffic (e.g. HTTP, FTP, XMPP, IMAP, SMTP --
- * without TLS or STARTTLS) is permitted for communicating with {@code hostname} for this
- * process.
- *
- * <p>See {@link #isCleartextTrafficPermitted} for more details.
- */
- public abstract boolean isCleartextTrafficPermitted(String hostname);
-
- /**
- * Returns {@code true} if Certificate Transparency information is required to be presented by
- * the server and verified by the client in TLS connections to {@code hostname}.
- *
- * <p>See RFC6962 section 3.3 for more details.
- */
- public abstract boolean isCertificateTransparencyVerificationRequired(String hostname);
-
- public static final class DefaultNetworkSecurityPolicy extends NetworkSecurityPolicy {
- @Override
- public boolean isCleartextTrafficPermitted() {
- return true;
- }
-
- @Override
- public boolean isCleartextTrafficPermitted(String hostname) {
- return isCleartextTrafficPermitted();
- }
-
- @Override
- public boolean isCertificateTransparencyVerificationRequired(String hostname) {
- return false;
- }
- }
-}
diff --git a/openjdk/src/main/java/org/conscrypt/Platform.java b/openjdk/src/main/java/org/conscrypt/Platform.java
index 78e2236..f5770ca 100644
--- a/openjdk/src/main/java/org/conscrypt/Platform.java
+++ b/openjdk/src/main/java/org/conscrypt/Platform.java
@@ -78,9 +78,8 @@
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509ExtendedTrustManager;
import javax.net.ssl.X509TrustManager;
-import org.conscrypt.ct.LogStore;
-import org.conscrypt.ct.Policy;
-import sun.security.x509.AlgorithmId;
+import org.conscrypt.ct.CTLogStore;
+import org.conscrypt.ct.CTPolicy;
/**
* Platform-specific methods for OpenJDK.
@@ -719,11 +718,11 @@
return null;
}
- static LogStore newDefaultLogStore() {
+ static CTLogStore newDefaultLogStore() {
return null;
}
- static Policy newDefaultPolicy() {
+ static CTPolicy newDefaultPolicy(CTLogStore logStore) {
return null;
}
@@ -814,12 +813,4 @@
public static boolean isTlsV1Deprecated() {
return true;
}
-
- public static boolean isTlsV1Filtered() {
- return false;
- }
-
- public static boolean isTlsV1Supported() {
- return false;
- }
}
diff --git a/openjdk/src/test/java/org/conscrypt/ConscryptOpenJdkSuite.java b/openjdk/src/test/java/org/conscrypt/ConscryptOpenJdkSuite.java
index f5ae14b..d5401e3 100644
--- a/openjdk/src/test/java/org/conscrypt/ConscryptOpenJdkSuite.java
+++ b/openjdk/src/test/java/org/conscrypt/ConscryptOpenJdkSuite.java
@@ -18,8 +18,8 @@
import static org.conscrypt.TestUtils.installConscryptAsDefaultProvider;
+import org.conscrypt.ct.CTVerifierTest;
import org.conscrypt.ct.SerializationTest;
-import org.conscrypt.ct.VerifierTest;
import org.conscrypt.java.security.AlgorithmParameterGeneratorTestDH;
import org.conscrypt.java.security.AlgorithmParameterGeneratorTestDSA;
import org.conscrypt.java.security.AlgorithmParametersPSSTest;
@@ -111,7 +111,7 @@
TestSessionBuilderTest.class,
TrustManagerImplTest.class,
// org.conscrypt.ct tests
- VerifierTest.class,
+ CTVerifierTest.class,
SerializationTest.class,
// java.security tests
CertificateFactoryTest.class,
diff --git a/openjdk/src/test/resources/test_blocklist_ca2.pem b/openjdk/src/test/resources/test_blocklist_ca2.pem
deleted file mode 100644
index ca33594..0000000
--- a/openjdk/src/test/resources/test_blocklist_ca2.pem
+++ /dev/null
@@ -1,19 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDHTCCAgWgAwIBAgIUY4GMRArmOpdsPFvMChsC64re26kwDQYJKoZIhvcNAQEL
-BQAwHjEcMBoGA1UEAwwTYmxhY2tsaXN0IHRlc3QgQ0EgMjAeFw0yNDA2MDcwNTAx
-NTJaFw0zNDA2MDUwNTAxNTJaMB4xHDAaBgNVBAMME2JsYWNrbGlzdCB0ZXN0IENB
-IDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCZiCGg9O8L4drk5R0J
-AwFvnm4aS2NZXnD0xUwE4iK0Nhw0Fb5A/yd4aW1RL8gCqcYXQywHrQAZq+PBUnG9
-ArtRoOTugkSD7gRFPFi7xcq6tdjVinkG33BUqSoyZb584sAwLfuKmG4WgGF6Bm2g
-vTh4kzvvqzJmWiDMHAxJCUiE+OQ3kBKoGUqplyn97Td3ZKs6mi1lAYV5xAu5M3EK
-fFC6g4Ckvy/5ZMLrROwz2bTtMQEsIRAeFRWWQJlDKF4RbceFmhDavwMSHCZu9ZGM
-HPAapXg+3LdQM+uqiQoguItY9dv1SJbWlcsxl5NzqDkPLfZeIhMTEYk/PtMKIsLk
-7aUvAgMBAAGjUzBRMB0GA1UdDgQWBBQyrTPvjxNE7FvnFRmD50u9H+o5nTAfBgNV
-HSMEGDAWgBQyrTPvjxNE7FvnFRmD50u9H+o5nTAPBgNVHRMBAf8EBTADAQH/MA0G
-CSqGSIb3DQEBCwUAA4IBAQBOAdrI1ycTfwL/PMUCXAlwbosKFyDESgGgbfE0blHc
-MkT0AY4ODxU2+oEM+UTwFJ/3ZC88hlJdhqL4spwC1lTCP8DpydxzR+KN8iEUDQT6
-MeXjmll7qUzk5f+/xF3BCp+5ZqympYNPT3vwf25k308aT6/LNrWCvQYxPJJue1aS
-kPQU6y3ktgsdXmSL696fGi/VcuNmJKjDJn+po7NS+F07Addnf5t1v9iwNMI2OwiG
-LzZ/3wiQNU03KlM6fiy++e0VIxrxShg1cYMlKQanzFo3cFkigT5JNDHTA2gVV0Kz
-7bEMyIVMLL59ky3bVdxVCJdi5brhgqV1C8Wly0bgm555
------END CERTIFICATE-----
diff --git a/openjdk/src/test/resources/test_blocklist_ca2_key.pem b/openjdk/src/test/resources/test_blocklist_ca2_key.pem
deleted file mode 100644
index f8a4bb5..0000000
--- a/openjdk/src/test/resources/test_blocklist_ca2_key.pem
+++ /dev/null
@@ -1,28 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCZiCGg9O8L4drk
-5R0JAwFvnm4aS2NZXnD0xUwE4iK0Nhw0Fb5A/yd4aW1RL8gCqcYXQywHrQAZq+PB
-UnG9ArtRoOTugkSD7gRFPFi7xcq6tdjVinkG33BUqSoyZb584sAwLfuKmG4WgGF6
-Bm2gvTh4kzvvqzJmWiDMHAxJCUiE+OQ3kBKoGUqplyn97Td3ZKs6mi1lAYV5xAu5
-M3EKfFC6g4Ckvy/5ZMLrROwz2bTtMQEsIRAeFRWWQJlDKF4RbceFmhDavwMSHCZu
-9ZGMHPAapXg+3LdQM+uqiQoguItY9dv1SJbWlcsxl5NzqDkPLfZeIhMTEYk/PtMK
-IsLk7aUvAgMBAAECggEAP2Jww8MrJ4QseyBNvukzQBIv0YI7N2uihaMokcGMY0sN
-lME/RRUyBee8nm50DAlsQzFTra2SI4cP5cG0PDyy+e3LZd55C+CJec4Csi7j1fZ6
-WRqsgZZgiUs3pQvVOzjf8GQje6IXnQmOdLLPsrM766eZcIaErbXa4XlY5xRCkMaO
-RavPwvbAFKKKCjndJs5OZpwZwR/UcHMlYLR3Dg+ozzlG48dMr0ao/3bimGPsc8/t
-eXzlVq2vi8xdRm53MdzarH9VWTYg3AalKEedLxxfvyGaZrpviCZdftHvH+sRruCy
-D280CSlmwLFc5xVGQTN9zNolEWarxU4fcusgmyfXrQKBgQDVqbrSOBDKF1WlyT/J
-vsCCRywoTBVDxvB0BeoC3ICHh5KISbtfjqy/CR4qLGnuov0ZXVR5UmGHs3gl21qm
-HjX1IRWo+8bfaoxBqK1zcFd4XtkPNPtEAcQvH0MFjnBXd0WcC/7qzvUUIC2RGuWY
-YmxCj4uFdSTLwLwiTDwXdAy7HQKBgQC39C8Ygu7MlTO9EpyQdoOSbQC+VgaPPABO
-LgQLoGH5K7sNOjutHo3Bt3iKFsdPkTHkZc3alBhH+61zgbsmGFrNJI+XRgkeGpLR
-/6Bbi7ivswsJcHmodOKOr62RKMJArwqOqN2MhNlZTBDjgIy4owN2B0YHwd9GTQWu
-JOjfwHwjuwKBgQCpxjtPjQMyQcZpfHc2LF81Za5dus7u0yX/Wy+t5F4w0vYJW2UK
-sgjrpygT5MSrvVEVlYZo/J/Ivz+J/TmTY9AGHqriYmWM41HdXlWss6idWehp3/SD
-/k9QDiwoPx1fMsPaEeIV3Cr7OfJbKZ8kLZjObtczTXjWeihDrIXXMPxotQKBgQC3
-mO1QZ43zfo7PDL5aqQ6UnFp7ndyaJOahIOhEumROjsj4YMCi/rW5PGcAW8+9qErF
-jJ4ypFC/t3/cowSo9vHZgb4W233KH/edxKbF9+Py6J4BY9LowRBGHSz8jlOiv5Gn
-5P6KeyV7LKJGjkzlEz4nFQdeQq+XuNQMhSYv/CtqdQKBgEQKDQRiKgl4DjbDWNjV
-3EUFH/LBvwPUXnrfeECXuyiTrTHrUsTtahcrjTQs/ByX15YSmyVhbUSsYQ6dkafZ
-aVNl9zNLQYYa2y3VbBs0q5xEW+iCmc4w/LsW+mnUiFmKlYVokwGVEDkqMyDkk3oB
-58f2hIryzy4MDkh0Iqixr6o1
------END PRIVATE KEY-----
diff --git a/platform/src/main/java/org/conscrypt/CertBlocklistImpl.java b/platform/src/main/java/org/conscrypt/CertBlocklistImpl.java
index 305b74b..2428d4c 100644
--- a/platform/src/main/java/org/conscrypt/CertBlocklistImpl.java
+++ b/platform/src/main/java/org/conscrypt/CertBlocklistImpl.java
@@ -24,16 +24,14 @@
import java.io.IOException;
import java.io.RandomAccessFile;
import java.math.BigInteger;
+import java.security.GeneralSecurityException;
import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
-import java.util.LinkedHashMap;
import java.util.List;
-import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -43,35 +41,14 @@
private static final Logger logger = Logger.getLogger(CertBlocklistImpl.class.getName());
private final Set<BigInteger> serialBlocklist;
- private final Set<ByteArray> sha1PubkeyBlocklist;
- private final Set<ByteArray> sha256PubkeyBlocklist;
- private Map<ByteArray, Boolean> cache;
-
- /**
- * Number of entries in the cache. The cache contains public keys which are
- * at most 4096 bits (512 bytes) for RSA. For a cache size of 64, that is
- * at most 512 * 64 = 32,768 bytes.
- */
- private static final int CACHE_SIZE = 64;
+ private final Set<ByteString> pubkeyBlocklist;
/**
* public for testing only.
*/
- public CertBlocklistImpl(Set<BigInteger> serialBlocklist, Set<ByteArray> sha1PubkeyBlocklist) {
- this(serialBlocklist, sha1PubkeyBlocklist, Collections.emptySet());
- }
-
- public CertBlocklistImpl(Set<BigInteger> serialBlocklist, Set<ByteArray> sha1PubkeyBlocklist,
- Set<ByteArray> sha256PubkeyBlocklist) {
- this.cache = Collections.synchronizedMap(new LinkedHashMap<ByteArray, Boolean>() {
- @Override
- protected boolean removeEldestEntry(Map.Entry<ByteArray, Boolean> eldest) {
- return size() > CACHE_SIZE;
- }
- });
+ public CertBlocklistImpl(Set<BigInteger> serialBlocklist, Set<ByteString> pubkeyBlocklist) {
this.serialBlocklist = serialBlocklist;
- this.sha1PubkeyBlocklist = sha1PubkeyBlocklist;
- this.sha256PubkeyBlocklist = sha256PubkeyBlocklist;
+ this.pubkeyBlocklist = pubkeyBlocklist;
}
public static CertBlocklist getDefault() {
@@ -79,14 +56,10 @@
String blocklistRoot = androidData + "/misc/keychain/";
String defaultPubkeyBlocklistPath = blocklistRoot + "pubkey_blacklist.txt";
String defaultSerialBlocklistPath = blocklistRoot + "serial_blacklist.txt";
- String defaultPubkeySha256BlocklistPath = blocklistRoot + "pubkey_sha256_blocklist.txt";
- Set<ByteArray> sha1PubkeyBlocklist =
- readPublicKeyBlockList(defaultPubkeyBlocklistPath, "SHA-1");
- Set<ByteArray> sha256PubkeyBlocklist =
- readPublicKeyBlockList(defaultPubkeySha256BlocklistPath, "SHA-256");
+ Set<ByteString> pubkeyBlocklist = readPublicKeyBlockList(defaultPubkeyBlocklistPath);
Set<BigInteger> serialBlocklist = readSerialBlockList(defaultSerialBlocklistPath);
- return new CertBlocklistImpl(serialBlocklist, sha1PubkeyBlocklist, sha256PubkeyBlocklist);
+ return new CertBlocklistImpl(serialBlocklist, pubkeyBlocklist);
}
private static boolean isHex(String value) {
@@ -99,8 +72,8 @@
}
}
- private static boolean isPubkeyHash(String value, int expectedHashLength) {
- if (value.length() != expectedHashLength) {
+ private static boolean isPubkeyHash(String value) {
+ if (value.length() != 40) {
logger.log(Level.WARNING, "Invalid pubkey hash length: " + value.length());
return false;
}
@@ -156,12 +129,32 @@
}
private static Set<BigInteger> readSerialBlockList(String path) {
- /*
- * Deprecated. Serials may inadvertently match a certificate that was
- * issued not in compliance with the Baseline Requirements. Prefer
- * using the certificate public key.
+
+ /* Start out with a base set of known bad values.
+ *
+ * WARNING: Do not add short serials to this list!
+ *
+ * Since this currently doesn't compare the serial + issuer, you
+ * should only add serials that have enough entropy here. Short
+ * serials may inadvertently match a certificate that was issued
+ * not in compliance with the Baseline Requirements.
*/
- Set<BigInteger> bl = new HashSet<BigInteger>();
+ Set<BigInteger> bl = new HashSet<BigInteger>(Arrays.asList(
+ // From http://src.chromium.org/viewvc/chrome/trunk/src/net/base/x509_certificate.cc?revision=78748&view=markup
+ // Not a real certificate. For testing only.
+ new BigInteger("077a59bcd53459601ca6907267a6dd1c", 16),
+ new BigInteger("047ecbe9fca55f7bd09eae36e10cae1e", 16),
+ new BigInteger("d8f35f4eb7872b2dab0692e315382fb0", 16),
+ new BigInteger("b0b7133ed096f9b56fae91c874bd3ac0", 16),
+ new BigInteger("9239d5348f40d1695a745470e1f23f43", 16),
+ new BigInteger("e9028b9578e415dc1a710a2b88154447", 16),
+ new BigInteger("d7558fdaf5f1105bb213282b707729a3", 16),
+ new BigInteger("f5c86af36162f13a64f54f6dc9587c06", 16),
+ new BigInteger("392a434f0e07df1f8aa305de34e0c229", 16),
+ new BigInteger("3e75ced46b693021218830ae86a82a71", 16)
+ ));
+
+ // attempt to augment it with values taken from gservices
String serialBlocklist = readBlocklist(path);
if (!serialBlocklist.equals("")) {
for (String value : serialBlocklist.split(",", -1)) {
@@ -177,13 +170,15 @@
return Collections.unmodifiableSet(bl);
}
- static final byte[][] SHA1_BUILTINS = {
+ private static Set<ByteString> readPublicKeyBlockList(String path) {
+
+ // start out with a base set of known bad values
+ Set<ByteString> bl = new HashSet<ByteString>(toByteStrings(
// Blocklist test cert for CTS. The cert and key can be found in
// src/test/resources/blocklist_test_ca.pem and
// src/test/resources/blocklist_test_ca_key.pem.
"bae78e6bed65a2bf60ddedde7fd91e825865e93d".getBytes(UTF_8),
- // From
- // http://src.chromium.org/viewvc/chrome/branches/782/src/net/base/x509_certificate.cc?r1=98750&r2=98749&pathrev=98750
+ // From http://src.chromium.org/viewvc/chrome/branches/782/src/net/base/x509_certificate.cc?r1=98750&r2=98749&pathrev=98750
// C=NL, O=DigiNotar, CN=DigiNotar Root CA/emailAddress=info@diginotar.nl
"410f36363258f30b347d12ce4863e433437806a8".getBytes(UTF_8),
// Subject: CN=DigiNotar Cyber CA
@@ -210,49 +205,16 @@
"783333c9687df63377efceddd82efa9101913e8e".getBytes(UTF_8),
// Subject: Subject: C=FR, O=DG Tr\xC3\xA9sor, CN=AC DG Tr\xC3\xA9sor SSL
// Issuer: C=FR, O=DGTPE, CN=AC DGTPE Signature Authentification
- "3ecf4bbbe46096d514bb539bb913d77aa4ef31bf".getBytes(UTF_8),
- };
-
- static final byte[][] SHA256_BUILTINS = {
- // Blocklist test cert for CTS. The cert and key can be found in
- // src/test/resources/blocklist_test_ca2.pem and
- // src/test/resources/blocklist_test_ca2_key.pem.
- "809964b15e9bd312993d9984045551f503f2cf8e68f39188921ba30fe623f9fd".getBytes(UTF_8),
- };
-
- private static Set<ByteArray> readPublicKeyBlockList(String path, String hashType) {
- Set<ByteArray> bl;
-
- switch (hashType) {
- case "SHA-1":
- bl = new HashSet<ByteArray>(toByteArrays(SHA1_BUILTINS));
- break;
- case "SHA-256":
- bl = new HashSet<ByteArray>(toByteArrays(SHA256_BUILTINS));
- break;
- default:
- throw new RuntimeException(
- "Unknown hashType: " + hashType + ". Expected SHA-1 or SHA-256");
- }
-
- MessageDigest md;
- try {
- md = MessageDigest.getInstance(hashType);
- } catch (NoSuchAlgorithmException e) {
- logger.log(Level.SEVERE, "Unable to get " + hashType + " MessageDigest", e);
- return bl;
- }
- // The hashes are encoded with hexadecimal values. There should be
- // twice as many characters as the digest length in bytes.
- int hashLength = md.getDigestLength() * 2;
+ "3ecf4bbbe46096d514bb539bb913d77aa4ef31bf".getBytes(UTF_8)
+ ));
// attempt to augment it with values taken from gservices
String pubkeyBlocklist = readBlocklist(path);
if (!pubkeyBlocklist.equals("")) {
for (String value : pubkeyBlocklist.split(",", -1)) {
value = value.trim();
- if (isPubkeyHash(value, hashLength)) {
- bl.add(new ByteArray(value.getBytes(UTF_8)));
+ if (isPubkeyHash(value)) {
+ bl.add(new ByteString(value.getBytes(UTF_8)));
} else {
logger.log(Level.WARNING, "Tried to blocklist invalid pubkey " + value);
}
@@ -262,46 +224,22 @@
return bl;
}
- private static boolean isPublicKeyBlockListed(
- byte[] encodedPublicKey, Set<ByteArray> blocklist, String hashType) {
- MessageDigest md;
- try {
- md = MessageDigest.getInstance(hashType);
- } catch (NoSuchAlgorithmException e) {
- logger.log(Level.SEVERE, "Unable to get " + hashType + " MessageDigest", e);
- return false;
- }
- ByteArray out = new ByteArray(toHex(md.digest(encodedPublicKey)));
- if (blocklist.contains(out)) {
- return true;
- }
- return false;
- }
-
@Override
public boolean isPublicKeyBlockListed(PublicKey publicKey) {
- byte[] encodedPublicKey = publicKey.getEncoded();
- // cacheKey is a view on encodedPublicKey. Because it is used as a key
- // for a Map, its underlying array (encodedPublicKey) should not be
- // modified.
- ByteArray cacheKey = new ByteArray(encodedPublicKey);
- Boolean cachedResult = cache.get(cacheKey);
- if (cachedResult != null) {
- return cachedResult.booleanValue();
+ byte[] encoded = publicKey.getEncoded();
+ MessageDigest md;
+ try {
+ md = MessageDigest.getInstance("SHA1");
+ } catch (GeneralSecurityException e) {
+ logger.log(Level.SEVERE, "Unable to get SHA1 MessageDigest", e);
+ return false;
}
- if (!sha1PubkeyBlocklist.isEmpty()) {
- if (isPublicKeyBlockListed(encodedPublicKey, sha1PubkeyBlocklist, "SHA-1")) {
- cache.put(cacheKey, true);
+ byte[] out = toHex(md.digest(encoded));
+ for (ByteString blocklisted : pubkeyBlocklist) {
+ if (Arrays.equals(blocklisted.bytes, out)) {
return true;
}
}
- if (!sha256PubkeyBlocklist.isEmpty()) {
- if (isPublicKeyBlockListed(encodedPublicKey, sha256PubkeyBlocklist, "SHA-256")) {
- cache.put(cacheKey, true);
- return true;
- }
- }
- cache.put(cacheKey, false);
return false;
}
@@ -325,11 +263,37 @@
return serialBlocklist.contains(serial);
}
- private static List<ByteArray> toByteArrays(byte[]... allBytes) {
- List<ByteArray> byteArrays = new ArrayList<>(allBytes.length + 1);
+ private static List<ByteString> toByteStrings(byte[]... allBytes) {
+ List<ByteString> byteStrings = new ArrayList<>(allBytes.length + 1);
for (byte[] bytes : allBytes) {
- byteArrays.add(new ByteArray(bytes));
+ byteStrings.add(new ByteString(bytes));
}
- return byteArrays;
+ return byteStrings;
+ }
+
+ private static class ByteString {
+ final byte[] bytes;
+
+ public ByteString(byte[] bytes) {
+ this.bytes = bytes;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (!(o instanceof ByteString)) {
+ return false;
+ }
+
+ ByteString other = (ByteString) o;
+ return Arrays.equals(bytes, other.bytes);
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(bytes);
+ }
}
}
diff --git a/platform/src/main/java/org/conscrypt/InternalUtil.java b/platform/src/main/java/org/conscrypt/InternalUtil.java
new file mode 100644
index 0000000..39558c4
--- /dev/null
+++ b/platform/src/main/java/org/conscrypt/InternalUtil.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2017 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;
+
+import java.io.InputStream;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import org.conscrypt.OpenSSLX509CertificateFactory.ParsingException;
+
+/**
+ * Helper to initialize the JNI libraries. This version runs when compiled
+ * as part of the platform.
+ */
+@Internal
+public final class InternalUtil {
+ public static PublicKey logKeyToPublicKey(byte[] logKey)
+ throws NoSuchAlgorithmException {
+ try {
+ return new OpenSSLKey(NativeCrypto.EVP_parse_public_key(logKey)).getPublicKey();
+ } catch (ParsingException e) {
+ throw new NoSuchAlgorithmException(e);
+ }
+ }
+
+ public static PublicKey readPublicKeyPem(InputStream pem) throws InvalidKeyException, NoSuchAlgorithmException {
+ return OpenSSLKey.fromPublicKeyPemInputStream(pem).getPublicKey();
+ }
+
+ private InternalUtil() {
+ }
+}
diff --git a/platform/src/main/java/org/conscrypt/Platform.java b/platform/src/main/java/org/conscrypt/Platform.java
index 85bd6da..36bc5bc 100644
--- a/platform/src/main/java/org/conscrypt/Platform.java
+++ b/platform/src/main/java/org/conscrypt/Platform.java
@@ -25,7 +25,6 @@
import android.system.StructTimeval;
import dalvik.system.BlockGuard;
import dalvik.system.CloseGuard;
-import dalvik.system.VMRuntime;
import java.io.FileDescriptor;
import java.io.IOException;
import java.lang.System;
@@ -62,14 +61,12 @@
import javax.net.ssl.StandardConstants;
import javax.net.ssl.X509ExtendedTrustManager;
import javax.net.ssl.X509TrustManager;
-import libcore.net.NetworkSecurityPolicy;
-import org.conscrypt.ct.LogStore;
-import org.conscrypt.ct.LogStoreImpl;
-import org.conscrypt.ct.Policy;
-import org.conscrypt.ct.PolicyImpl;
+import org.conscrypt.ct.CTLogStore;
+import org.conscrypt.ct.CTLogStoreImpl;
+import org.conscrypt.ct.CTPolicy;
+import org.conscrypt.ct.CTPolicyImpl;
import org.conscrypt.metrics.CipherSuite;
import org.conscrypt.metrics.ConscryptStatsLog;
-import org.conscrypt.metrics.OptionalMethod;
import org.conscrypt.metrics.Protocol;
import sun.security.x509.AlgorithmId;
@@ -464,10 +461,6 @@
}
static boolean isCTVerificationRequired(String hostname) {
- if (Flags.certificateTransparencyPlatform()) {
- return NetworkSecurityPolicy.getInstance()
- .isCertificateTransparencyVerificationRequired(hostname);
- }
return false;
}
@@ -493,12 +486,12 @@
return CertBlocklistImpl.getDefault();
}
- static LogStore newDefaultLogStore() {
- return new LogStoreImpl();
+ static CTLogStore newDefaultLogStore() {
+ return new CTLogStoreImpl();
}
- static Policy newDefaultPolicy() {
- return new PolicyImpl();
+ static CTPolicy newDefaultPolicy(CTLogStore logStore) {
+ return new CTPolicyImpl(logStore, 2);
}
static boolean serverNamePermitted(SSLParametersImpl parameters, String serverName) {
@@ -544,34 +537,6 @@
}
public static boolean isTlsV1Deprecated() {
- return true;
- }
-
- public static boolean isTlsV1Filtered() {
- Object targetSdkVersion = getTargetSdkVersion();
- if ((targetSdkVersion != null) && ((int) targetSdkVersion > 34))
- return false;
- return true;
- }
-
- public static boolean isTlsV1Supported() {
return false;
}
-
- static Object getTargetSdkVersion() {
- try {
- Class<?> vmRuntime = Class.forName("dalvik.system.VMRuntime");
- if (vmRuntime == null) {
- return null;
- }
- OptionalMethod getSdkVersion =
- new OptionalMethod(vmRuntime,
- "getTargetSdkVersion");
- return getSdkVersion.invokeStatic();
- } catch (ClassNotFoundException e) {
- return null;
- } catch (NullPointerException e) {
- return null;
- }
- }
}
diff --git a/platform/src/main/java/org/conscrypt/TrustedCertificateStore.java b/platform/src/main/java/org/conscrypt/TrustedCertificateStore.java
index bcf7816..14df376 100644
--- a/platform/src/main/java/org/conscrypt/TrustedCertificateStore.java
+++ b/platform/src/main/java/org/conscrypt/TrustedCertificateStore.java
@@ -35,7 +35,6 @@
import java.util.List;
import java.util.Set;
import javax.security.auth.x500.X500Principal;
-import org.conscrypt.ArrayUtils;
import org.conscrypt.io.IoUtils;
import org.conscrypt.metrics.OptionalMethod;
@@ -117,7 +116,7 @@
if ((System.getProperty("system.certs.enabled") != null)
&& (System.getProperty("system.certs.enabled")).equals("true"))
return false;
- if (updatableDir.exists() && !(ArrayUtils.isEmpty(updatableDir.list())))
+ if (updatableDir.exists() && !(updatableDir.list().length == 0))
return true;
return false;
}
diff --git a/platform/src/main/java/org/conscrypt/ct/CTLogStoreImpl.java b/platform/src/main/java/org/conscrypt/ct/CTLogStoreImpl.java
new file mode 100644
index 0000000..0f37a8d
--- /dev/null
+++ b/platform/src/main/java/org/conscrypt/ct/CTLogStoreImpl.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2015 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 java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Scanner;
+import java.util.Set;
+import org.conscrypt.Internal;
+import org.conscrypt.InternalUtil;
+
+@Internal
+public class CTLogStoreImpl implements CTLogStore {
+ private static final Charset US_ASCII = StandardCharsets.US_ASCII;
+
+ /**
+ * Thrown when parsing of a log file fails.
+ */
+ public static class InvalidLogFileException extends Exception {
+ public InvalidLogFileException() {
+ }
+
+ public InvalidLogFileException(String message) {
+ super(message);
+ }
+
+ public InvalidLogFileException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public InvalidLogFileException(Throwable cause) {
+ super(cause);
+ }
+ }
+
+ private static final File defaultUserLogDir;
+ private static final File defaultSystemLogDir;
+ // Lazy loaded by CTLogStoreImpl()
+ private static volatile CTLogInfo[] defaultFallbackLogs = null;
+ static {
+ String ANDROID_DATA = System.getenv("ANDROID_DATA");
+ String ANDROID_ROOT = System.getenv("ANDROID_ROOT");
+ defaultUserLogDir = new File(ANDROID_DATA + "/misc/keychain/trusted_ct_logs/current/");
+ defaultSystemLogDir = new File(ANDROID_ROOT + "/etc/security/ct_known_logs/");
+ }
+
+ private final File userLogDir;
+ private final File systemLogDir;
+ private final CTLogInfo[] fallbackLogs;
+
+ private final HashMap<ByteBuffer, CTLogInfo> logCache = new HashMap<>();
+ private final Set<ByteBuffer> missingLogCache
+ = Collections.synchronizedSet(new HashSet<ByteBuffer>());
+
+ public CTLogStoreImpl() {
+ this(defaultUserLogDir,
+ defaultSystemLogDir,
+ getDefaultFallbackLogs());
+ }
+
+ public CTLogStoreImpl(File userLogDir, File systemLogDir, CTLogInfo[] fallbackLogs) {
+ this.userLogDir = userLogDir;
+ this.systemLogDir = systemLogDir;
+ this.fallbackLogs = fallbackLogs;
+ }
+
+ @Override
+ public CTLogInfo getKnownLog(byte[] logId) {
+ ByteBuffer buf = ByteBuffer.wrap(logId);
+ CTLogInfo log = logCache.get(buf);
+ if (log != null) {
+ return log;
+ }
+ if (missingLogCache.contains(buf)) {
+ return null;
+ }
+
+ log = findKnownLog(logId);
+ if (log != null) {
+ logCache.put(buf, log);
+ } else {
+ missingLogCache.add(buf);
+ }
+
+ return log;
+ }
+
+ private CTLogInfo findKnownLog(byte[] logId) {
+ String filename = hexEncode(logId);
+ try {
+ return loadLog(new File(userLogDir, filename));
+ } catch (InvalidLogFileException e) {
+ return null;
+ } catch (FileNotFoundException e) {
+ // Ignored
+ }
+
+ try {
+ return loadLog(new File(systemLogDir, filename));
+ } catch (InvalidLogFileException e) {
+ return null;
+ } catch (FileNotFoundException e) {
+ // Ignored
+ }
+
+ // If the updateable logs dont exist then use the fallback logs.
+ if (!userLogDir.exists()) {
+ for (CTLogInfo log: fallbackLogs) {
+ if (Arrays.equals(logId, log.getID())) {
+ return log;
+ }
+ }
+ }
+ return null;
+ }
+
+ public static CTLogInfo[] getDefaultFallbackLogs() {
+ CTLogInfo[] result = defaultFallbackLogs;
+ if (result == null) {
+ // single-check idiom
+ defaultFallbackLogs = result = createDefaultFallbackLogs();
+ }
+ return result;
+ }
+
+ private static CTLogInfo[] createDefaultFallbackLogs() {
+ CTLogInfo[] logs = new CTLogInfo[KnownLogs.LOG_COUNT];
+ for (int i = 0; i < KnownLogs.LOG_COUNT; i++) {
+ try {
+ PublicKey key = InternalUtil.logKeyToPublicKey(KnownLogs.LOG_KEYS[i]);
+
+ logs[i] = new CTLogInfo(key,
+ KnownLogs.LOG_DESCRIPTIONS[i],
+ KnownLogs.LOG_URLS[i]);
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ defaultFallbackLogs = logs;
+ return logs;
+ }
+
+ /**
+ * Load a CTLogInfo from a file.
+ * @throws FileNotFoundException if the file does not exist
+ * @throws InvalidLogFileException if the file could not be parsed properly
+ * @return a CTLogInfo or null if the file is empty
+ */
+ public static CTLogInfo loadLog(File file) throws FileNotFoundException,
+ InvalidLogFileException {
+ return loadLog(new FileInputStream(file));
+ }
+
+ /**
+ * Load a CTLogInfo from a textual representation. Closes {@code input} upon completion
+ * of loading.
+ *
+ * @throws InvalidLogFileException if the input could not be parsed properly
+ * @return a CTLogInfo or null if the input is empty
+ */
+ public static CTLogInfo loadLog(InputStream input) throws InvalidLogFileException {
+ final Scanner scan = new Scanner(input, "UTF-8");
+ scan.useDelimiter("\n");
+
+ String description = null;
+ String url = null;
+ String key = null;
+ try {
+ // If the scanner can't even read one token then the file must be empty/blank
+ if (!scan.hasNext()) {
+ return null;
+ }
+
+ while (scan.hasNext()) {
+ String[] parts = scan.next().split(":", 2);
+ if (parts.length < 2) {
+ continue;
+ }
+
+ String name = parts[0];
+ String value = parts[1];
+ switch (name) {
+ case "description":
+ description = value;
+ break;
+ case "url":
+ url = value;
+ break;
+ case "key":
+ key = value;
+ break;
+ }
+ }
+ } finally {
+ scan.close();
+ }
+
+ if (description == null || url == null || key == null) {
+ throw new InvalidLogFileException("Missing one of 'description', 'url' or 'key'");
+ }
+
+ PublicKey pubkey;
+ try {
+ pubkey = InternalUtil.readPublicKeyPem(new ByteArrayInputStream(
+ ("-----BEGIN PUBLIC KEY-----\n" +
+ key + "\n" +
+ "-----END PUBLIC KEY-----").getBytes(US_ASCII)));
+ } catch (InvalidKeyException e) {
+ throw new InvalidLogFileException(e);
+ } catch (NoSuchAlgorithmException e) {
+ throw new InvalidLogFileException(e);
+ }
+
+ return new CTLogInfo(pubkey, description, url);
+ }
+
+ private final static char[] HEX_DIGITS = new char[] {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+ };
+
+ private static String hexEncode(byte[] data) {
+ StringBuilder sb = new StringBuilder(data.length * 2);
+ for (byte b: data) {
+ sb.append(HEX_DIGITS[(b >> 4) & 0x0f]);
+ sb.append(HEX_DIGITS[b & 0x0f]);
+ }
+ return sb.toString();
+ }
+}
diff --git a/platform/src/main/java/org/conscrypt/ct/CTPolicyImpl.java b/platform/src/main/java/org/conscrypt/ct/CTPolicyImpl.java
new file mode 100644
index 0000000..3faca6f
--- /dev/null
+++ b/platform/src/main/java/org/conscrypt/ct/CTPolicyImpl.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 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 java.security.cert.X509Certificate;
+import java.util.HashSet;
+import java.util.Set;
+import org.conscrypt.Internal;
+
+@Internal
+public class CTPolicyImpl implements CTPolicy {
+ private final CTLogStore logStore;
+ private final int minimumLogCount;
+
+ public CTPolicyImpl(CTLogStore logStore, int minimumLogCount) {
+ this.logStore = logStore;
+ this.minimumLogCount = minimumLogCount;
+ }
+
+ @Override
+ public boolean doesResultConformToPolicy(CTVerificationResult result, String hostname,
+ X509Certificate[] chain) {
+ Set<CTLogInfo> logSet = new HashSet<>();
+ for (VerifiedSCT verifiedSCT: result.getValidSCTs()) {
+ CTLogInfo log = logStore.getKnownLog(verifiedSCT.sct.getLogID());
+ if (log != null) {
+ logSet.add(log);
+ }
+ }
+
+ return logSet.size() >= minimumLogCount;
+ }
+}
diff --git a/platform/src/main/java/org/conscrypt/ct/KnownLogs.java b/platform/src/main/java/org/conscrypt/ct/KnownLogs.java
new file mode 100644
index 0000000..dba00cb
--- /dev/null
+++ b/platform/src/main/java/org/conscrypt/ct/KnownLogs.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+/* This file is generated by print_log_list.py
+ * https://github.com/google/certificate-transparency/blob/master/python/utilities/log_list/print_log_list.py */
+
+package org.conscrypt.ct;
+
+import org.conscrypt.Internal;
+
+@Internal
+public final class KnownLogs {
+ public static final int LOG_COUNT = 8;
+ public static final String[] LOG_DESCRIPTIONS = new String[] {
+ "Google 'Pilot' log",
+ "Google 'Aviator' log",
+ "DigiCert Log Server",
+ "Google 'Rocketeer' log",
+ "Certly.IO log",
+ "Izenpe log",
+ "Symantec log",
+ "Venafi log",
+ };
+ public static final String[] LOG_URLS = new String[] {
+ "ct.googleapis.com/pilot",
+ "ct.googleapis.com/aviator",
+ "ct1.digicert-ct.com/log",
+ "ct.googleapis.com/rocketeer",
+ "log.certly.io",
+ "ct.izenpe.com",
+ "ct.ws.symantec.com",
+ "ctlog.api.venafi.com",
+ };
+ public static final byte[][] LOG_KEYS = new byte[][] {
+ // Google 'Pilot' log
+ new byte[] {
+ 48, 89, 48, 19, 6, 7, 42, -122, 72, -50, 61, 2, 1, 6, 8, 42, -122, 72,
+ -50, 61, 3, 1, 7, 3, 66, 0, 4, 125, -88, 75, 18, 41, -128, -93, 61, -83,
+ -45, 90, 119, -72, -52, -30, -120, -77, -91, -3, -15, -45, 12, -51, 24,
+ 12, -24, 65, 70, -24, -127, 1, 27, 21, -31, 75, -15, 27, 98, -35, 54, 10,
+ 8, 24, -70, -19, 11, 53, -124, -48, -98, 64, 60, 45, -98, -101, -126,
+ 101, -67, 31, 4, 16, 65, 76, -96
+ },
+ // Google 'Aviator' log
+ new byte[] {
+ 48, 89, 48, 19, 6, 7, 42, -122, 72, -50, 61, 2, 1, 6, 8, 42, -122, 72,
+ -50, 61, 3, 1, 7, 3, 66, 0, 4, -41, -12, -52, 105, -78, -28, 14, -112,
+ -93, -118, -22, 90, 112, 9, 79, -17, 19, 98, -48, -115, 73, 96, -1, 27,
+ 64, 80, 7, 12, 109, 113, -122, -38, 37, 73, -115, 101, -31, 8, 13, 71,
+ 52, 107, -67, 39, -68, -106, 33, 62, 52, -11, -121, 118, 49, -79, 127,
+ 29, -55, -123, 59, 13, -9, 31, 63, -23
+ },
+ // DigiCert Log Server
+ new byte[] {
+ 48, 89, 48, 19, 6, 7, 42, -122, 72, -50, 61, 2, 1, 6, 8, 42, -122, 72,
+ -50, 61, 3, 1, 7, 3, 66, 0, 4, 2, 70, -59, -66, 27, -69, -126, 64, 22,
+ -24, -63, -46, -84, 25, 105, 19, 89, -8, -8, 112, -123, 70, 64, -71, 56,
+ -80, 35, -126, -88, 100, 76, 127, -65, -69, 52, -97, 74, 95, 40, -118,
+ -49, 25, -60, 0, -10, 54, 6, -109, 101, -19, 76, -11, -87, 33, 98, 90,
+ -40, -111, -21, 56, 36, 64, -84, -24
+ },
+ // Google 'Rocketeer' log
+ new byte[] {
+ 48, 89, 48, 19, 6, 7, 42, -122, 72, -50, 61, 2, 1, 6, 8, 42, -122, 72,
+ -50, 61, 3, 1, 7, 3, 66, 0, 4, 32, 91, 24, -56, 60, -63, -117, -77, 49,
+ 8, 0, -65, -96, -112, 87, 43, -73, 71, -116, 111, -75, 104, -80, -114,
+ -112, 120, -23, -96, 115, -22, 79, 40, 33, 46, -100, -64, -12, 22, 27,
+ -86, -7, -43, -41, -87, -128, -61, 78, 47, 82, 60, -104, 1, 37, 70, 36,
+ 37, 40, 35, 119, 45, 5, -62, 64, 122
+ },
+ // Certly.IO log
+ new byte[] {
+ 48, 89, 48, 19, 6, 7, 42, -122, 72, -50, 61, 2, 1, 6, 8, 42, -122, 72,
+ -50, 61, 3, 1, 7, 3, 66, 0, 4, 11, 35, -53, -123, 98, -104, 97, 72, 4,
+ 115, -21, 84, 93, -13, -48, 7, -116, 45, 25, 45, -116, 54, -11, -21,
+ -113, 1, 66, 10, 124, -104, 38, 39, -63, -75, -35, -110, -109, -80, -82,
+ -8, -101, 61, 12, -40, 76, 78, 29, -7, 21, -5, 71, 104, 123, -70, 102,
+ -73, 37, -100, -48, 74, -62, 102, -37, 72
+ },
+ // Izenpe log
+ new byte[] {
+ 48, 89, 48, 19, 6, 7, 42, -122, 72, -50, 61, 2, 1, 6, 8, 42, -122, 72,
+ -50, 61, 3, 1, 7, 3, 66, 0, 4, 39, 100, 57, 12, 45, -36, 80, 24, -8, 33,
+ 0, -94, 14, -19, 44, -22, 62, 117, -70, -97, -109, 100, 9, 0, 17, -60,
+ 17, 23, -85, 92, -49, 15, 116, -84, -75, -105, -112, -109, 0, 91, -72,
+ -21, -9, 39, 61, -39, -78, 10, -127, 95, 47, 13, 117, 56, -108, 55, -103,
+ 30, -10, 7, 118, -32, -18, -66
+ },
+ // Symantec log
+ new byte[] {
+ 48, 89, 48, 19, 6, 7, 42, -122, 72, -50, 61, 2, 1, 6, 8, 42, -122, 72,
+ -50, 61, 3, 1, 7, 3, 66, 0, 4, -106, -22, -84, 28, 70, 12, 27, 85, -36,
+ 13, -4, -75, -108, 39, 70, 87, 66, 112, 58, 105, 24, -30, -65, 59, -60,
+ -37, -85, -96, -12, -74, 108, -64, 83, 63, 77, 66, 16, 51, -16, 88, -105,
+ -113, 107, -66, 114, -12, 42, -20, 28, 66, -86, 3, 47, 26, 126, 40, 53,
+ 118, -103, 8, 61, 33, 20, -122
+ },
+ // Venafi log
+ new byte[] {
+ 48, -126, 1, 34, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 1, 5, 0,
+ 3, -126, 1, 15, 0, 48, -126, 1, 10, 2, -126, 1, 1, 0, -94, 90, 72, 31,
+ 23, 82, -107, 53, -53, -93, 91, 58, 31, 83, -126, 118, -108, -93, -1,
+ -128, -14, 28, 55, 60, -64, -79, -67, -63, 89, -117, -85, 45, 101, -109,
+ -41, -13, -32, 4, -43, -102, 111, -65, -42, 35, 118, 54, 79, 35, -103,
+ -53, 84, 40, -83, -116, 21, 75, 101, 89, 118, 65, 74, -100, -90, -9, -77,
+ 59, 126, -79, -91, 73, -92, 23, 81, 108, -128, -36, 42, -112, 80, 75,
+ -120, 36, -23, -91, 18, 50, -109, 4, 72, -112, 2, -6, 95, 14, 48, -121,
+ -114, 85, 118, 5, -18, 42, 76, -50, -93, 106, 105, 9, 110, 37, -83, -126,
+ 118, 15, -124, -110, -6, 56, -42, -122, 78, 36, -113, -101, -80, 114,
+ -53, -98, -30, 107, 63, -31, 109, -55, 37, 117, 35, -120, -95, 24, 88, 6,
+ 35, 51, 120, -38, 0, -48, 56, -111, 103, -46, -90, 125, 39, -105, 103,
+ 90, -63, -13, 47, 23, -26, -22, -46, 91, -24, -127, -51, -3, -110, 104,
+ -25, -13, 6, -16, -23, 114, -124, -18, 1, -91, -79, -40, 51, -38, -50,
+ -125, -91, -37, -57, -49, -42, 22, 126, -112, 117, 24, -65, 22, -36, 50,
+ 59, 109, -115, -85, -126, 23, 31, -119, 32, -115, 29, -102, -26, 77, 35,
+ 8, -33, 120, 111, -58, 5, -65, 95, -82, -108, -105, -37, 95, 100, -44,
+ -18, 22, -117, -93, -124, 108, 113, 43, -15, -85, 127, 93, 13, 50, -18,
+ 4, -30, -112, -20, 65, -97, -5, 57, -63, 2, 3, 1, 0, 1
+ },
+ };
+}
diff --git a/platform/src/main/java/org/conscrypt/ct/LogStoreImpl.java b/platform/src/main/java/org/conscrypt/ct/LogStoreImpl.java
deleted file mode 100644
index b7141d4..0000000
--- a/platform/src/main/java/org/conscrypt/ct/LogStoreImpl.java
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * Copyright (C) 2015 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 java.nio.charset.StandardCharsets.US_ASCII;
-import static java.nio.charset.StandardCharsets.UTF_8;
-
-import org.conscrypt.ByteArray;
-import org.conscrypt.Internal;
-import org.conscrypt.OpenSSLKey;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.NoSuchFileException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-import java.security.PublicKey;
-import java.text.DateFormat;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Arrays;
-import java.util.Base64;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-@Internal
-public class LogStoreImpl implements LogStore {
- private static final Logger logger = Logger.getLogger(LogStoreImpl.class.getName());
- public static final String V3_PATH = "/misc/keychain/ct/v3/log_list.json";
- private static final Path defaultLogList;
-
- static {
- String ANDROID_DATA = System.getenv("ANDROID_DATA");
- defaultLogList = Paths.get(ANDROID_DATA, V3_PATH);
- }
-
- private final Path logList;
- private State state;
- private Policy policy;
- private String version;
- private long timestamp;
- private Map<ByteArray, LogInfo> logs;
-
- public LogStoreImpl() {
- this(defaultLogList);
- }
-
- public LogStoreImpl(Path logList) {
- this.state = State.UNINITIALIZED;
- this.logList = logList;
- }
-
- @Override
- public State getState() {
- ensureLogListIsLoaded();
- return state;
- }
-
- @Override
- public long getTimestamp() {
- return timestamp;
- }
-
- @Override
- public void setPolicy(Policy policy) {
- this.policy = policy;
- }
-
- @Override
- public LogInfo getKnownLog(byte[] logId) {
- if (logId == null) {
- return null;
- }
- if (!ensureLogListIsLoaded()) {
- return null;
- }
- ByteArray buf = new ByteArray(logId);
- LogInfo log = logs.get(buf);
- if (log != null) {
- return log;
- }
- return null;
- }
-
- /* Ensures the log list is loaded.
- * Returns true if the log list is usable.
- */
- private boolean ensureLogListIsLoaded() {
- synchronized (this) {
- if (state == State.UNINITIALIZED) {
- state = loadLogList();
- }
- if (state == State.LOADED && policy != null) {
- state = policy.isLogStoreCompliant(this) ? State.COMPLIANT : State.NON_COMPLIANT;
- }
- return state == State.COMPLIANT;
- }
- }
-
- private State loadLogList() {
- byte[] content;
- try {
- content = Files.readAllBytes(logList);
- } catch (IOException e) {
- return State.NOT_FOUND;
- }
- if (content == null) {
- return State.NOT_FOUND;
- }
- JSONObject json;
- try {
- json = new JSONObject(new String(content, UTF_8));
- } catch (JSONException e) {
- logger.log(Level.WARNING, "Unable to parse log list", e);
- return State.MALFORMED;
- }
- HashMap<ByteArray, LogInfo> logsMap = new HashMap<>();
- try {
- version = json.getString("version");
- timestamp = parseTimestamp(json.getString("log_list_timestamp"));
- JSONArray operators = json.getJSONArray("operators");
- for (int i = 0; i < operators.length(); i++) {
- JSONObject operator = operators.getJSONObject(i);
- String operatorName = operator.getString("name");
- JSONArray logs = operator.getJSONArray("logs");
- for (int j = 0; j < logs.length(); j++) {
- JSONObject log = logs.getJSONObject(j);
-
- LogInfo.Builder builder =
- new LogInfo.Builder()
- .setDescription(log.getString("description"))
- .setPublicKey(parsePubKey(log.getString("key")))
- .setUrl(log.getString("url"))
- .setOperator(operatorName);
-
- JSONObject stateObject = log.optJSONObject("state");
- if (stateObject != null) {
- String state = stateObject.keys().next();
- String stateTimestamp =
- stateObject.getJSONObject(state).getString("timestamp");
- builder.setState(parseState(state), parseTimestamp(stateTimestamp));
- }
-
- LogInfo logInfo = builder.build();
- byte[] logId = Base64.getDecoder().decode(log.getString("log_id"));
-
- // The logId computed using the public key should match the log_id field.
- if (!Arrays.equals(logInfo.getID(), logId)) {
- throw new IllegalArgumentException("logId does not match publicKey");
- }
-
- logsMap.put(new ByteArray(logId), logInfo);
- }
- }
- } catch (JSONException | IllegalArgumentException e) {
- logger.log(Level.WARNING, "Unable to parse log list", e);
- return State.MALFORMED;
- }
- this.logs = Collections.unmodifiableMap(logsMap);
- return State.LOADED;
- }
-
- private static int parseState(String state) {
- switch (state) {
- case "pending":
- return LogInfo.STATE_PENDING;
- case "qualified":
- return LogInfo.STATE_QUALIFIED;
- case "usable":
- return LogInfo.STATE_USABLE;
- case "readonly":
- return LogInfo.STATE_READONLY;
- case "retired":
- return LogInfo.STATE_RETIRED;
- case "rejected":
- return LogInfo.STATE_REJECTED;
- default:
- throw new IllegalArgumentException("Unknown log state: " + state);
- }
- }
-
- // ISO 8601
- private static DateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
-
- @SuppressWarnings("JavaUtilDate")
- private static long parseTimestamp(String timestamp) {
- try {
- Date date = dateFormatter.parse(timestamp);
- return date.getTime();
- } catch (ParseException e) {
- throw new IllegalArgumentException(e);
- }
- }
-
- private static PublicKey parsePubKey(String key) {
- byte[] pem = ("-----BEGIN PUBLIC KEY-----\n" + key + "\n-----END PUBLIC KEY-----")
- .getBytes(US_ASCII);
- PublicKey pubkey;
- try {
- pubkey = OpenSSLKey.fromPublicKeyPemInputStream(new ByteArrayInputStream(pem))
- .getPublicKey();
- } catch (InvalidKeyException | NoSuchAlgorithmException e) {
- throw new IllegalArgumentException(e);
- }
- return pubkey;
- }
-}
diff --git a/platform/src/main/java/org/conscrypt/ct/PolicyImpl.java b/platform/src/main/java/org/conscrypt/ct/PolicyImpl.java
deleted file mode 100644
index 8bcd463..0000000
--- a/platform/src/main/java/org/conscrypt/ct/PolicyImpl.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright (C) 2015 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 org.conscrypt.Internal;
-
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
-@Internal
-public class PolicyImpl implements Policy {
- @Override
- public boolean isLogStoreCompliant(LogStore store) {
- long now = System.currentTimeMillis();
- return isLogStoreCompliantAt(store, now);
- }
-
- public boolean isLogStoreCompliantAt(LogStore store, long atTime) {
- long storeTimestamp = store.getTimestamp();
- long seventyDaysInMs = 70L * 24 * 60 * 60 * 1000;
- if (storeTimestamp + seventyDaysInMs < atTime) {
- // Expired log list.
- return false;
- } else if (storeTimestamp > atTime) {
- // Log list from the future. It is likely that the device has an
- // incorrect time.
- return false;
- }
- return true;
- }
-
- @Override
- public PolicyCompliance doesResultConformToPolicy(
- VerificationResult result, X509Certificate leaf) {
- long now = System.currentTimeMillis();
- return doesResultConformToPolicyAt(result, leaf, now);
- }
-
- public PolicyCompliance doesResultConformToPolicyAt(
- VerificationResult result, X509Certificate leaf, long atTime) {
- List<VerifiedSCT> validSCTs = new ArrayList<VerifiedSCT>(result.getValidSCTs());
- /* While the log list supports logs without a state, these entries are
- * not supported by the log policy. Filter them out. */
- filterOutUnknown(validSCTs);
- /* Filter out any SCT issued after a log was retired */
- filterOutAfterRetired(validSCTs);
-
- Set<VerifiedSCT> embeddedValidSCTs = new HashSet<>();
- Set<VerifiedSCT> ocspOrTLSValidSCTs = new HashSet<>();
- for (VerifiedSCT vsct : validSCTs) {
- if (vsct.getSct().getOrigin() == SignedCertificateTimestamp.Origin.EMBEDDED) {
- embeddedValidSCTs.add(vsct);
- } else {
- ocspOrTLSValidSCTs.add(vsct);
- }
- }
- if (embeddedValidSCTs.size() > 0) {
- return conformEmbeddedSCTs(embeddedValidSCTs, leaf, atTime);
- }
- return PolicyCompliance.NOT_ENOUGH_SCTS;
- }
-
- private void filterOutUnknown(List<VerifiedSCT> scts) {
- Iterator<VerifiedSCT> it = scts.iterator();
- while (it.hasNext()) {
- VerifiedSCT vsct = it.next();
- if (vsct.getLogInfo().getState() == LogInfo.STATE_UNKNOWN) {
- it.remove();
- }
- }
- }
-
- private void filterOutAfterRetired(List<VerifiedSCT> scts) {
- /* From the policy:
- *
- * In order to contribute to a certificate’s CT Compliance, an SCT must
- * have been issued before the Log’s Retired timestamp, if one exists.
- * Chrome uses the earliest SCT among all SCTs presented to evaluate CT
- * compliance against CT Log Retired timestamps. This accounts for edge
- * cases in which a CT Log becomes Retired during the process of
- * submitting certificate logging requests.
- */
-
- if (scts.size() < 1) {
- return;
- }
- long minTimestamp = scts.get(0).getSct().getTimestamp();
- for (VerifiedSCT vsct : scts) {
- long ts = vsct.getSct().getTimestamp();
- if (ts < minTimestamp) {
- minTimestamp = ts;
- }
- }
- Iterator<VerifiedSCT> it = scts.iterator();
- while (it.hasNext()) {
- VerifiedSCT vsct = it.next();
- if (vsct.getLogInfo().getState() == LogInfo.STATE_RETIRED
- && minTimestamp > vsct.getLogInfo().getStateTimestamp()) {
- it.remove();
- }
- }
- }
-
- private PolicyCompliance conformEmbeddedSCTs(
- Set<VerifiedSCT> embeddedValidSCTs, X509Certificate leaf, long atTime) {
- /* 1. At least one Embedded SCT from a CT Log that was Qualified,
- * Usable, or ReadOnly at the time of check;
- */
- boolean found = false;
- for (VerifiedSCT vsct : embeddedValidSCTs) {
- LogInfo log = vsct.getLogInfo();
- switch (log.getStateAt(atTime)) {
- case LogInfo.STATE_QUALIFIED:
- case LogInfo.STATE_USABLE:
- case LogInfo.STATE_READONLY:
- found = true;
- }
- }
- if (!found) {
- return PolicyCompliance.NOT_ENOUGH_SCTS;
- }
-
- /* 2. There are Embedded SCTs from at least N distinct CT Logs that
- * were Qualified, Usable, ReadOnly, or Retired at the time of check,
- * where N is defined in the following table;
- *
- * Certificate Lifetime Number of SCTs from distinct CT Logs
- * <= 180 days 2
- * > 180 days 3
- */
- Set<LogInfo> validLogs = new HashSet<>();
- int numberSCTsRequired;
- long certLifetimeMs = leaf.getNotAfter().getTime() - leaf.getNotBefore().getTime();
- long certLifetimeDays = TimeUnit.DAYS.convert(certLifetimeMs, TimeUnit.MILLISECONDS);
- if (certLifetimeDays <= 180) {
- numberSCTsRequired = 2;
- } else {
- numberSCTsRequired = 3;
- }
- for (VerifiedSCT vsct : embeddedValidSCTs) {
- LogInfo log = vsct.getLogInfo();
- switch (log.getStateAt(atTime)) {
- case LogInfo.STATE_QUALIFIED:
- case LogInfo.STATE_USABLE:
- case LogInfo.STATE_READONLY:
- case LogInfo.STATE_RETIRED:
- validLogs.add(log);
- }
- }
- if (validLogs.size() < numberSCTsRequired) {
- return PolicyCompliance.NOT_ENOUGH_SCTS;
- }
-
- /* 3. Among the SCTs satisfying requirements 1 and 2, at least two SCTs
- * must be issued from distinct CT Log Operators as recognized by
- * Chrome.
- */
- Set<String> operators = new HashSet<>();
- for (LogInfo logInfo : validLogs) {
- operators.add(logInfo.getOperator());
- }
- if (operators.size() < 2) {
- return PolicyCompliance.NOT_ENOUGH_DIVERSE_SCTS;
- }
-
- return PolicyCompliance.COMPLY;
- }
-}
diff --git a/platform/src/test/java/org/conscrypt/CertBlocklistTest.java b/platform/src/test/java/org/conscrypt/CertBlocklistTest.java
index 4d9a5c1..39561e5 100644
--- a/platform/src/test/java/org/conscrypt/CertBlocklistTest.java
+++ b/platform/src/test/java/org/conscrypt/CertBlocklistTest.java
@@ -29,7 +29,6 @@
public class CertBlocklistTest extends TestCase {
private static final String BLOCKLIST_CA = "test_blocklist_ca.pem";
- private static final String BLOCKLIST_CA2 = "test_blocklist_ca2.pem";
private static final String BLOCKLISTED_CHAIN = "blocklist_test_chain.pem";
private static final String BLOCKLIST_FALLBACK_VALID_CA = "blocklist_test_valid_ca.pem";
private static final String BLOCKLISTED_VALID_CHAIN = "blocklist_test_valid_chain.pem";
@@ -44,15 +43,6 @@
}
/**
- * Ensure that the test blocklisted CA 2 is actually blocklisted by default.
- */
- public void testBlocklistedPublicKeySHA256() throws Exception {
- X509Certificate blocklistedCa = loadCertificate(BLOCKLIST_CA2);
- CertBlocklist blocklist = CertBlocklistImpl.getDefault();
- assertTrue(blocklist.isPublicKeyBlockListed(blocklistedCa.getPublicKey()));
- }
-
- /**
* Check that the blocklisted CA is rejected even if it used as a root of trust
*/
public void testBlocklistedCaUntrusted() throws Exception {
diff --git a/platform/src/test/java/org/conscrypt/ct/CTLogStoreImplTest.java b/platform/src/test/java/org/conscrypt/ct/CTLogStoreImplTest.java
new file mode 100644
index 0000000..f95a3e6
--- /dev/null
+++ b/platform/src/test/java/org/conscrypt/ct/CTLogStoreImplTest.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2015 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 java.nio.charset.StandardCharsets.UTF_8;
+
+import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.security.PublicKey;
+import junit.framework.TestCase;
+import org.conscrypt.InternalUtil;
+
+public class CTLogStoreImplTest extends TestCase {
+ private static final String[] LOG_KEYS = new String[] {
+ "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEmXg8sUUzwBYaWrRb+V0IopzQ6o3U" +
+ "yEJ04r5ZrRXGdpYM8K+hB0pXrGRLI0eeWz+3skXrS0IO83AhA3GpRL6s6w==",
+
+ "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAErEULmlBnX9L/+AK20hLYzPMFozYx" +
+ "pP0Wm1ylqGkPEwuDKn9DSpNSOym49SN77BLGuAXu9twOW/qT+ddIYVBEIw==",
+
+ "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEP6PGcXmjlyCBz2ZFUuUjrgbZLaEF" +
+ "gfLUkt2cEqlSbb4vTuB6WWmgC9h0L6PN6JF0CPcajpBKGlTI15242a8d4g==",
+
+ "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAER3qB0NADsP1szXxe4EagrD/ryPVh" +
+ "Y/azWbKyXcK12zhXnO8WH2U4QROVUMctFXLflIzw0EivdRN9t7UH1Od30w==",
+
+ "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEY0ww9JqeJvzVtKNTPVb3JZa7s0ZV" +
+ "duH3PpshpMS5XVoPRSjSQCph6f3HjUcM3c4N2hpa8OFbrFFy37ttUrgD+A=="
+ };
+ private static final String[] LOG_FILENAMES = new String[] {
+ "df1c2ec11500945247a96168325ddc5c7959e8f7c6d388fc002e0bbd3f74d764",
+ "84f8ae3f613b13407a75fa2893b93ab03b18d86c455fe7c241ae020033216446",
+ "89baa01a445100009d8f9a238947115b30702275aafee675a7d94b6b09287619",
+ "57456bffe268e49a190dce4318456034c2b4958f3c0201bed5a366737d1e74ca",
+ "896c898ced4b8e6547fa351266caae4ca304f1c1ec2b623c2ee259c5452147b0"
+ };
+
+ private static final CTLogInfo[] LOGS;
+ private static final String[] LOGS_SERIALIZED;
+
+ static {
+ try {
+ int logCount = LOG_KEYS.length;
+ LOGS = new CTLogInfo[logCount];
+ LOGS_SERIALIZED = new String[logCount];
+ for (int i = 0; i < logCount; i++) {
+ PublicKey key = InternalUtil.readPublicKeyPem(new ByteArrayInputStream(
+ ("-----BEGIN PUBLIC KEY-----\n" +
+ LOG_KEYS[i] + "\n" +
+ "-----END PUBLIC KEY-----\n").getBytes(StandardCharsets.US_ASCII)));
+ String description = String.format("Test Log %d", i);
+ String url = String.format("log%d.example.com", i);
+ LOGS[i] = new CTLogInfo(key, description, url);
+ LOGS_SERIALIZED[i] = String.format("description:%s\nurl:%s\nkey:%s",
+ description, url, LOG_KEYS[i]);
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /* CTLogStoreImpl loads the list of logs lazily when they are first needed
+ * to avoid any overhead when CT is disabled.
+ * This test simply forces the logs to be loaded to make sure it doesn't
+ * fail, as all of the other tests use a different log store.
+ */
+ public void test_getDefaultFallbackLogs() {
+ CTLogInfo[] knownLogs = CTLogStoreImpl.getDefaultFallbackLogs();
+ assertEquals(KnownLogs.LOG_COUNT, knownLogs.length);
+ }
+
+ public void test_loadLog() throws Exception {
+ CTLogInfo log = CTLogStoreImpl.loadLog(
+ new ByteArrayInputStream(LOGS_SERIALIZED[0].getBytes(StandardCharsets.US_ASCII)));
+ assertEquals(LOGS[0], log);
+
+ File testFile = writeFile(LOGS_SERIALIZED[0]);
+ log = CTLogStoreImpl.loadLog(testFile);
+ assertEquals(LOGS[0], log);
+
+ // Empty log file, used to mask fallback logs
+ assertEquals(null, CTLogStoreImpl.loadLog(new ByteArrayInputStream(new byte[0])));
+ try {
+ CTLogStoreImpl.loadLog(new ByteArrayInputStream(
+ "randomgarbage".getBytes(StandardCharsets.US_ASCII)));
+ fail("InvalidLogFileException not thrown");
+ } catch (CTLogStoreImpl.InvalidLogFileException e) {}
+
+ try {
+ CTLogStoreImpl.loadLog(new File("/nonexistent"));
+ fail("FileNotFoundException not thrown");
+ } catch (FileNotFoundException e) {}
+ }
+
+ public void test_getKnownLog() throws Exception {
+ File userDir = createTempDirectory();
+ userDir.deleteOnExit();
+
+ File systemDir = createTempDirectory();
+ systemDir.deleteOnExit();
+
+ CTLogInfo[] fallback = new CTLogInfo[] { LOGS[2], LOGS[3] };
+
+ CTLogStore store = new CTLogStoreImpl(userDir, systemDir, fallback);
+
+ /* Add logs 0 and 1 to the user and system directories respectively
+ * Log 2 & 3 are part of the fallbacks
+ * But mask log 3 with an empty file in the user directory.
+ * Log 4 is not in the store
+ */
+ File log0File = new File(userDir, LOG_FILENAMES[0]);
+ File log1File = new File(systemDir, LOG_FILENAMES[1]);
+ File log3File = new File(userDir, LOG_FILENAMES[3]);
+ File log4File = new File(userDir, LOG_FILENAMES[4]);
+
+ writeFile(log0File, LOGS_SERIALIZED[0]);
+ writeFile(log1File, LOGS_SERIALIZED[1]);
+ writeFile(log3File, "");
+
+ // Logs 01 are present, log 2 is in the fallback and unused, log 3 is present but masked,
+ // log 4 is missing
+ assertEquals(LOGS[0], store.getKnownLog(LOGS[0].getID()));
+ assertEquals(LOGS[1], store.getKnownLog(LOGS[1].getID()));
+ // Fallback logs are not used if the userDir is present.
+ assertEquals(null, store.getKnownLog(LOGS[2].getID()));
+ assertEquals(null, store.getKnownLog(LOGS[3].getID()));
+ assertEquals(null, store.getKnownLog(LOGS[4].getID()));
+
+ /* Test whether CTLogStoreImpl caches properly
+ * Modify the files on the disk, the result of the store should not change
+ * Delete log 0, mask log 1, add log 4
+ */
+ log0File.delete();
+ writeFile(log1File, "");
+ writeFile(log4File, LOGS_SERIALIZED[4]);
+
+ assertEquals(LOGS[0], store.getKnownLog(LOGS[0].getID()));
+ assertEquals(LOGS[1], store.getKnownLog(LOGS[1].getID()));
+ assertEquals(null, store.getKnownLog(LOGS[4].getID()));
+
+ // Test that fallback logs are used when the userDir doesn't exist.
+ File doesntExist = new File("/doesnt/exist/");
+ store = new CTLogStoreImpl(doesntExist, doesntExist, fallback);
+ assertEquals(LOGS[2], store.getKnownLog(LOGS[2].getID()));
+ assertEquals(LOGS[3], store.getKnownLog(LOGS[3].getID()));
+ }
+
+ /**
+ * Create a temporary file and write to it.
+ * The file will be deleted on exit.
+ * @param contents The data to be written to the file
+ * @return A reference to the temporary file
+ */
+ private File writeFile(String contents) throws IOException {
+ File file = File.createTempFile("test", null);
+ file.deleteOnExit();
+ writeFile(file, contents);
+ return file;
+ }
+
+ private static void writeFile(File file, String contents) throws FileNotFoundException {
+ PrintWriter writer = new PrintWriter(
+ new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), UTF_8)),
+ false);
+ try {
+ writer.write(contents);
+ } finally {
+ writer.close();
+ }
+ }
+
+ /*
+ * This is NOT safe, as another process could create a file between delete() and mkdir()
+ * It should be fine for tests though
+ */
+ private static File createTempDirectory() throws IOException {
+ File folder = File.createTempFile("test", "");
+ folder.delete();
+ folder.mkdir();
+ return folder;
+ }
+}
+
diff --git a/platform/src/test/java/org/conscrypt/ct/LogStoreImplTest.java b/platform/src/test/java/org/conscrypt/ct/LogStoreImplTest.java
deleted file mode 100644
index 81b6cd6..0000000
--- a/platform/src/test/java/org/conscrypt/ct/LogStoreImplTest.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2015 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 java.nio.charset.StandardCharsets.US_ASCII;
-import static java.nio.charset.StandardCharsets.UTF_8;
-
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.security.PublicKey;
-import java.util.Base64;
-import junit.framework.TestCase;
-import org.conscrypt.OpenSSLKey;
-
-public class LogStoreImplTest extends TestCase {
- public void test_loadLogList() throws Exception {
- // clang-format off
- String content = "" +
-"{" +
-" \"version\": \"1.1\"," +
-" \"log_list_timestamp\": \"2024-01-01T11:55:12Z\"," +
-" \"operators\": [" +
-" {" +
-" \"name\": \"Operator 1\"," +
-" \"email\": [\"ct@operator1.com\"]," +
-" \"logs\": [" +
-" {" +
-" \"description\": \"Operator 1 'Test2024' log\"," +
-" \"log_id\": \"7s3QZNXbGs7FXLedtM0TojKHRny87N7DUUhZRnEftZs=\"," +
-" \"key\": \"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHblsqctplMVc5ramA7vSuNxUQxcomQwGAVAdnWTAWUYr3MgDHQW0LagJ95lB7QT75Ve6JgT2EVLOFGU7L3YrwA==\"," +
-" \"url\": \"https://operator1.example.com/logs/test2024/\"," +
-" \"mmd\": 86400," +
-" \"state\": {" +
-" \"usable\": {" +
-" \"timestamp\": \"2022-11-01T18:54:00Z\"" +
-" }" +
-" }," +
-" \"temporal_interval\": {" +
-" \"start_inclusive\": \"2024-01-01T00:00:00Z\"," +
-" \"end_exclusive\": \"2025-01-01T00:00:00Z\"" +
-" }" +
-" }," +
-" {" +
-" \"description\": \"Operator 1 'Test2025' log\"," +
-" \"log_id\": \"TnWjJ1yaEMM4W2zU3z9S6x3w4I4bjWnAsfpksWKaOd8=\"," +
-" \"key\": \"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIIKh+WdoqOTblJji4WiH5AltIDUzODyvFKrXCBjw/Rab0/98J4LUh7dOJEY7+66+yCNSICuqRAX+VPnV8R1Fmg==\"," +
-" \"url\": \"https://operator1.example.com/logs/test2025/\"," +
-" \"mmd\": 86400," +
-" \"state\": {" +
-" \"usable\": {" +
-" \"timestamp\": \"2023-11-26T12:00:00Z\"" +
-" }" +
-" }," +
-" \"temporal_interval\": {" +
-" \"start_inclusive\": \"2025-01-01T00:00:00Z\"," +
-" \"end_exclusive\": \"2025-07-01T00:00:00Z\"" +
-" }" +
-" }" +
-" ]" +
-" }," +
-" {" +
-" \"name\": \"Operator 2\"," +
-" \"email\": [\"ct@operator2.com\"]," +
-" \"logs\": [" +
-" {" +
-" \"description\": \"Operator 2 'Test2024' Log\"," +
-" \"log_id\": \"2ra/az+1tiKfm8K7XGvocJFxbLtRhIU0vaQ9MEjX+6s=\"," +
-" \"key\": \"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEd7Gbe4/mizX+OpIpLayKjVGKJfyTttegiyk3cR0zyswz6ii5H+Ksw6ld3Ze+9p6UJd02gdHrXSnDK0TxW8oVSA==\"," +
-" \"url\": \"https://operator2.example.com/logs/test2024/\"," +
-" \"mmd\": 86400," +
-" \"state\": {" +
-" \"usable\": {" +
-" \"timestamp\": \"2022-11-30T17:00:00Z\"" +
-" }" +
-" }," +
-" \"temporal_interval\": {" +
-" \"start_inclusive\": \"2024-01-01T00:00:00Z\"," +
-" \"end_exclusive\": \"2025-01-01T00:00:00Z\"" +
-" }" +
-" }" +
-" ]" +
-" }" +
-" ]" +
-"}";
- // clang-format on
-
- File logList = writeFile(content);
- LogStore store = new LogStoreImpl(logList.toPath());
- store.setPolicy(new PolicyImpl() {
- @Override
- public boolean isLogStoreCompliant(LogStore store) {
- return true;
- }
- });
-
- assertNull("A null logId should return null", store.getKnownLog(null));
-
- byte[] pem = ("-----BEGIN PUBLIC KEY-----\n"
- + "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEHblsqctplMVc5ramA7vSuNxUQxcomQwGAVAdnWTAWUYr"
- + "3MgDHQW0LagJ95lB7QT75Ve6JgT2EVLOFGU7L3YrwA=="
- + "\n-----END PUBLIC KEY-----\n")
- .getBytes(US_ASCII);
- ByteArrayInputStream is = new ByteArrayInputStream(pem);
-
- LogInfo log1 =
- new LogInfo.Builder()
- .setPublicKey(OpenSSLKey.fromPublicKeyPemInputStream(is).getPublicKey())
- .setDescription("Operator 1 'Test2024' log")
- .setUrl("https://operator1.example.com/logs/test2024/")
- .setState(LogInfo.STATE_USABLE, 1667328840000L)
- .setOperator("Operator 1")
- .build();
- byte[] log1Id = Base64.getDecoder().decode("7s3QZNXbGs7FXLedtM0TojKHRny87N7DUUhZRnEftZs=");
- assertEquals("An existing logId should be returned", log1, store.getKnownLog(log1Id));
- }
-
- private File writeFile(String content) throws IOException {
- File file = File.createTempFile("test", null);
- file.deleteOnExit();
- try (FileWriter fw = new FileWriter(file)) {
- fw.write(content);
- }
- return file;
- }
-}
diff --git a/platform/src/test/java/org/conscrypt/ct/PolicyImplTest.java b/platform/src/test/java/org/conscrypt/ct/PolicyImplTest.java
deleted file mode 100644
index c4b70f9..0000000
--- a/platform/src/test/java/org/conscrypt/ct/PolicyImplTest.java
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * 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.assertEquals;
-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 final String OPERATOR1 = "operator 1";
- private static final String OPERATOR2 = "operator 2";
- private static LogInfo usableOp1Log1;
- private static LogInfo usableOp1Log2;
- private static LogInfo retiredOp1LogOld;
- private static LogInfo retiredOp1LogNew;
- private static LogInfo usableOp2Log;
- private static LogInfo retiredOp2Log;
- private static SignedCertificateTimestamp embeddedSCT;
-
- /* Some test dates. By default:
- * - The verification is occurring in January 2024;
- * - The log list was created in December 2023;
- * - The SCTs were generated in January 2023; and
- * - The logs got into their state in January 2022.
- * Other dates are used to exercise edge cases.
- */
- private static final long JAN2025 = 1735725600000L;
- private static final long JAN2024 = 1704103200000L;
- private static final long DEC2023 = 1701424800000L;
- private static final long JUN2023 = 1672999200000L;
- private static final long JAN2023 = 1672567200000L;
- private static final long JAN2022 = 1641031200000L;
-
- 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(OPERATOR1)
- .setState(LogInfo.STATE_USABLE, JAN2022)
- .build();
- usableOp1Log2 = new LogInfo.Builder()
- .setPublicKey(new FakePublicKey(new byte[] {0x02}))
- .setUrl("")
- .setOperator(OPERATOR1)
- .setState(LogInfo.STATE_USABLE, JAN2022)
- .build();
- retiredOp1LogOld = new LogInfo.Builder()
- .setPublicKey(new FakePublicKey(new byte[] {0x03}))
- .setUrl("")
- .setOperator(OPERATOR1)
- .setState(LogInfo.STATE_RETIRED, JAN2022)
- .build();
- retiredOp1LogNew = new LogInfo.Builder()
- .setPublicKey(new FakePublicKey(new byte[] {0x06}))
- .setUrl("")
- .setOperator(OPERATOR1)
- .setState(LogInfo.STATE_RETIRED, JUN2023)
- .build();
- usableOp2Log = new LogInfo.Builder()
- .setPublicKey(new FakePublicKey(new byte[] {0x04}))
- .setUrl("")
- .setOperator(OPERATOR2)
- .setState(LogInfo.STATE_USABLE, JAN2022)
- .build();
- retiredOp2Log = new LogInfo.Builder()
- .setPublicKey(new FakePublicKey(new byte[] {0x05}))
- .setUrl("")
- .setOperator(OPERATOR2)
- .setState(LogInfo.STATE_RETIRED, JAN2022)
- .build();
- /* The origin of the SCT and its timestamp are 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,
- JAN2023, null, null, SignedCertificateTimestamp.Origin.EMBEDDED);
- }
-
- @Test
- public void emptyVerificationResult() throws Exception {
- PolicyImpl p = new PolicyImpl();
- VerificationResult result = new VerificationResult();
-
- X509Certificate leaf = new FakeX509Certificate();
- assertEquals("An empty VerificationResult", PolicyCompliance.NOT_ENOUGH_SCTS,
- p.doesResultConformToPolicyAt(result, leaf, JAN2024));
- }
-
- @Test
- public void validVerificationResult() throws Exception {
- PolicyImpl 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();
- assertEquals("Two valid SCTs from different operators", PolicyCompliance.COMPLY,
- p.doesResultConformToPolicyAt(result, leaf, JAN2024));
- }
-
- @Test
- public void validWithRetiredVerificationResult() throws Exception {
- PolicyImpl p = new PolicyImpl();
-
- VerifiedSCT vsct1 = new VerifiedSCT.Builder(embeddedSCT)
- .setStatus(VerifiedSCT.Status.VALID)
- .setLogInfo(retiredOp1LogNew)
- .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();
- assertEquals("One valid, one retired SCTs from different operators",
- PolicyCompliance.COMPLY, p.doesResultConformToPolicyAt(result, leaf, JAN2024));
- }
-
- @Test
- public void invalidWithRetiredVerificationResult() throws Exception {
- PolicyImpl p = new PolicyImpl();
-
- VerifiedSCT vsct1 = new VerifiedSCT.Builder(embeddedSCT)
- .setStatus(VerifiedSCT.Status.VALID)
- .setLogInfo(retiredOp1LogOld)
- .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();
- assertEquals("One valid, one retired (before SCT timestamp) SCTs from different operators",
- PolicyCompliance.NOT_ENOUGH_SCTS,
- p.doesResultConformToPolicyAt(result, leaf, JAN2024));
- }
-
- @Test
- public void invalidOneSctVerificationResult() throws Exception {
- PolicyImpl 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();
- assertEquals("One valid SCT", PolicyCompliance.NOT_ENOUGH_SCTS,
- p.doesResultConformToPolicyAt(result, leaf, JAN2024));
- }
-
- @Test
- public void invalidTwoSctsVerificationResult() throws Exception {
- PolicyImpl p = new PolicyImpl();
-
- VerifiedSCT vsct1 = new VerifiedSCT.Builder(embeddedSCT)
- .setStatus(VerifiedSCT.Status.VALID)
- .setLogInfo(retiredOp1LogNew)
- .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();
- assertEquals("Two retired SCTs from different operators", PolicyCompliance.NOT_ENOUGH_SCTS,
- p.doesResultConformToPolicyAt(result, leaf, JAN2024));
- }
-
- @Test
- public void invalidTwoSctsSameOperatorVerificationResult() throws Exception {
- PolicyImpl 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(usableOp1Log2)
- .build();
-
- VerificationResult result = new VerificationResult();
- result.add(vsct1);
- result.add(vsct2);
-
- X509Certificate leaf = new FakeX509Certificate();
- assertEquals("Two SCTs from the same operator", PolicyCompliance.NOT_ENOUGH_DIVERSE_SCTS,
- p.doesResultConformToPolicyAt(result, leaf, JAN2024));
- }
-
- @Test
- @NonCts(reason = NonCtsReasons.INTERNAL_APIS)
- public void validRecentLogStore() throws Exception {
- PolicyImpl p = new PolicyImpl();
-
- LogStore store = new LogStoreImpl() {
- @Override
- public long getTimestamp() {
- return DEC2023;
- }
- };
- assertTrue("A recent log list is compliant", p.isLogStoreCompliantAt(store, JAN2024));
- }
-
- @Test
- @NonCts(reason = NonCtsReasons.INTERNAL_APIS)
- public void invalidFutureLogStore() throws Exception {
- PolicyImpl p = new PolicyImpl();
-
- LogStore store = new LogStoreImpl() {
- @Override
- public long getTimestamp() {
- return JAN2025;
- }
- };
- assertFalse("A future log list is non-compliant", p.isLogStoreCompliantAt(store, JAN2024));
- }
-
- @Test
- @NonCts(reason = NonCtsReasons.INTERNAL_APIS)
- public void invalidOldLogStore() throws Exception {
- PolicyImpl p = new PolicyImpl();
-
- LogStore store = new LogStoreImpl() {
- @Override
- public long getTimestamp() {
- return JAN2023;
- }
- };
- assertFalse("A expired log list is non-compliant", p.isLogStoreCompliantAt(store, JAN2024));
- }
-}
diff --git a/testing/src/main/java/org/conscrypt/ChannelType.java b/testing/src/main/java/org/conscrypt/ChannelType.java
index 23e09a0..09dd582 100644
--- a/testing/src/main/java/org/conscrypt/ChannelType.java
+++ b/testing/src/main/java/org/conscrypt/ChannelType.java
@@ -38,24 +38,24 @@
public enum ChannelType {
NONE {
@Override
- public SSLSocket newClientSocket(SSLSocketFactory factory, InetAddress address, int port)
+ SSLSocket newClientSocket(SSLSocketFactory factory, InetAddress address, int port)
throws IOException {
return clientMode(factory.createSocket(address, port));
}
@Override
- public ServerSocket newServerSocket(SSLServerSocketFactory factory) throws IOException {
+ ServerSocket newServerSocket(SSLServerSocketFactory factory) throws IOException {
return factory.createServerSocket(0, 50, InetAddress.getLoopbackAddress());
}
@Override
- public SSLSocket accept(ServerSocket socket, SSLSocketFactory unused) throws IOException {
+ SSLSocket accept(ServerSocket socket, SSLSocketFactory unused) throws IOException {
return serverMode(socket.accept());
}
},
NO_CHANNEL {
@Override
- public SSLSocket newClientSocket(SSLSocketFactory factory, InetAddress address, int port)
+ SSLSocket newClientSocket(SSLSocketFactory factory, InetAddress address, int port)
throws IOException {
Socket wrapped = new Socket(address, port);
assertNull(wrapped.getChannel());
@@ -64,13 +64,13 @@
}
@Override
- public ServerSocket newServerSocket(SSLServerSocketFactory unused) throws IOException {
+ ServerSocket newServerSocket(SSLServerSocketFactory unused) throws IOException {
return ServerSocketFactory.getDefault().createServerSocket(
0, 50, InetAddress.getLoopbackAddress());
}
@Override
- public SSLSocket accept(ServerSocket serverSocket, SSLSocketFactory factory) throws IOException {
+ SSLSocket accept(ServerSocket serverSocket, SSLSocketFactory factory) throws IOException {
assertFalse(serverSocket instanceof SSLServerSocket);
Socket wrapped = serverSocket.accept();
assertNull(wrapped.getChannel());
@@ -81,21 +81,21 @@
},
CHANNEL {
@Override
- public SSLSocket newClientSocket(SSLSocketFactory factory, InetAddress address, int port)
+ SSLSocket newClientSocket(SSLSocketFactory factory, InetAddress address, int port)
throws IOException {
Socket wrapped = SocketChannel.open(new InetSocketAddress(address, port)).socket();
return clientMode(factory.createSocket(wrapped, address.getHostName(), port, true));
}
@Override
- public ServerSocket newServerSocket(SSLServerSocketFactory unused) throws IOException {
+ ServerSocket newServerSocket(SSLServerSocketFactory unused) throws IOException {
return ServerSocketChannel.open()
.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0))
.socket();
}
@Override
- public SSLSocket accept(ServerSocket serverSocket, SSLSocketFactory factory) throws IOException {
+ SSLSocket accept(ServerSocket serverSocket, SSLSocketFactory factory) throws IOException {
assertFalse(serverSocket instanceof SSLServerSocket);
ServerSocketChannel serverChannel = serverSocket.getChannel();
@@ -111,10 +111,10 @@
}
};
- public abstract SSLSocket newClientSocket(SSLSocketFactory factory, InetAddress address, int port)
+ abstract SSLSocket newClientSocket(SSLSocketFactory factory, InetAddress address, int port)
throws IOException;
- public abstract ServerSocket newServerSocket(SSLServerSocketFactory factory) throws IOException;
- public abstract SSLSocket accept(ServerSocket socket, SSLSocketFactory factory) throws IOException;
+ abstract ServerSocket newServerSocket(SSLServerSocketFactory factory) throws IOException;
+ abstract SSLSocket accept(ServerSocket socket, SSLSocketFactory factory) throws IOException;
private static SSLSocket clientMode(Socket socket) {
SSLSocket sslSocket = (SSLSocket) socket;
diff --git a/testing/src/main/java/org/conscrypt/TestUtils.java b/testing/src/main/java/org/conscrypt/TestUtils.java
index b6ee45b..503102d 100644
--- a/testing/src/main/java/org/conscrypt/TestUtils.java
+++ b/testing/src/main/java/org/conscrypt/TestUtils.java
@@ -355,7 +355,7 @@
}
}
- public static SSLSocketFactory setUseEngineSocket(
+ static SSLSocketFactory setUseEngineSocket(
SSLSocketFactory conscryptFactory, boolean useEngineSocket) {
try {
Class<?> clazz = conscryptClass("Conscrypt");
@@ -368,7 +368,7 @@
}
}
- public static SSLServerSocketFactory setUseEngineSocket(
+ static SSLServerSocketFactory setUseEngineSocket(
SSLServerSocketFactory conscryptFactory, boolean useEngineSocket) {
try {
Class<?> clazz = conscryptClass("Conscrypt");
@@ -513,12 +513,12 @@
return msg;
}
- public static SSLContext newClientSslContext(Provider provider) {
+ static SSLContext newClientSslContext(Provider provider) {
SSLContext context = newContext(provider);
return initClientSslContext(context);
}
- public static SSLContext newServerSslContext(Provider provider) {
+ static SSLContext newServerSslContext(Provider provider) {
SSLContext context = newContext(provider);
return initServerSslContext(context);
}
@@ -871,18 +871,4 @@
throw new RuntimeException(e);
}
}
-
- // Find base method via reflection due to possible version skew on Android
- // and visibility issues when building with Gradle.
- public static boolean isTlsV1Filtered() {
- try {
- return (Boolean) conscryptClass("Platform")
- .getDeclaredMethod("isTlsV1Filtered")
- .invoke(null);
- } catch (NoSuchMethodException e) {
- return true;
- } catch (ClassNotFoundException | IllegalAccessException | InvocationTargetException e) {
- throw new IllegalStateException("Reflection failure", e);
- }
- }
}
diff --git a/testing/src/main/java/org/conscrypt/java/security/StandardNames.java b/testing/src/main/java/org/conscrypt/java/security/StandardNames.java
index 6d4e871..54a26d0 100644
--- a/testing/src/main/java/org/conscrypt/java/security/StandardNames.java
+++ b/testing/src/main/java/org/conscrypt/java/security/StandardNames.java
@@ -161,8 +161,6 @@
}
public static final String SSL_CONTEXT_PROTOCOLS_DEFAULT = "Default";
- public static final Set<String> SSL_CONTEXT_PROTOCOLS_ALL =
- new HashSet<String>(Arrays.asList("TLS", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"));
public static final Set<String> SSL_CONTEXT_PROTOCOLS = new HashSet<String>(
Arrays.asList(SSL_CONTEXT_PROTOCOLS_DEFAULT, "TLS", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"));
public static final Set<String> SSL_CONTEXT_PROTOCOLS_WITH_DEFAULT_CONFIG = new HashSet<String>(
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
deleted file mode 100644
index ed61cc4..0000000
--- a/testing/src/main/java/org/conscrypt/java/security/cert/FakeX509Certificate.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * 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;
- }
-}