summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--JavaLibrary.mk10
-rw-r--r--dalvik/src/main/java/dalvik/system/Zygote.java57
-rw-r--r--expectations/brokentests.txt7
-rw-r--r--luni/src/main/java/java/lang/Object.java2
-rw-r--r--luni/src/main/java/libcore/io/DropBox.java72
-rw-r--r--luni/src/main/java/libcore/io/EventLogger.java69
-rw-r--r--luni/src/main/java/org/apache/harmony/xnet/provider/jsse/CertPinManager.java184
-rw-r--r--luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientHandshakeImpl.java24
-rw-r--r--luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java6
-rw-r--r--luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLProvider.java40
-rw-r--r--luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAPrivateCrtKey.java43
-rw-r--r--luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAPrivateKey.java9
-rw-r--r--luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java62
-rw-r--r--luni/src/main/java/org/apache/harmony/xnet/provider/jsse/PinEntryException.java29
-rw-r--r--luni/src/main/java/org/apache/harmony/xnet/provider/jsse/PinFailureLogger.java70
-rw-r--r--luni/src/main/java/org/apache/harmony/xnet/provider/jsse/PinListEntry.java155
-rw-r--r--luni/src/main/java/org/apache/harmony/xnet/provider/jsse/PinManagerException.java32
-rw-r--r--luni/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLSocketFactoryImpl.java2
-rw-r--r--luni/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLSocketImpl.java37
-rw-r--r--luni/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLSocketWrapper.java5
-rw-r--r--luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustManagerImpl.java138
-rw-r--r--luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustedCertificateStore.java8
-rw-r--r--luni/src/main/native/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp43
-rw-r--r--luni/src/main/native/zip.h2
-rw-r--r--luni/src/test/java/libcore/java/lang/OldObjectTest.java31
-rw-r--r--luni/src/test/java/libcore/java/security/KeyStoreTest.java467
-rw-r--r--luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java49
-rw-r--r--luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/CipherTest.java6
-rw-r--r--luni/src/test/java/org/apache/harmony/security/tests/java/security/KeyRepTest.java135
-rw-r--r--luni/src/test/java/org/apache/harmony/security/tests/java/security/KeyStoreLoadStoreParameterTest.java15
-rw-r--r--luni/src/test/java/org/apache/harmony/security/tests/java/security/Security2Test.java108
-rw-r--r--luni/src/test/java/org/apache/harmony/xnet/provider/jsse/CertPinManagerTest.java175
-rw-r--r--luni/src/test/java/org/apache/harmony/xnet/provider/jsse/NativeCryptoTest.java107
-rw-r--r--luni/src/test/java/org/apache/harmony/xnet/provider/jsse/TrustManagerImplTest.java133
-rw-r--r--luni/src/test/java/org/apache/harmony/xnet/provider/jsse/TrustedCertificateStoreTest.java20
-rw-r--r--support/src/test/java/libcore/java/security/StandardNames.java14
36 files changed, 1892 insertions, 474 deletions
diff --git a/JavaLibrary.mk b/JavaLibrary.mk
index 59ac2e1..26a586a 100644
--- a/JavaLibrary.mk
+++ b/JavaLibrary.mk
@@ -55,9 +55,11 @@ core_resource_dirs := $(call all-core-resource-dirs,main)
test_resource_dirs := $(call all-core-resource-dirs,test)
ifeq ($(EMMA_INSTRUMENT),true)
+ifneq ($(EMMA_INSTRUMENT_STATIC),true)
core_src_files += $(call all-java-files-under, ../external/emma/core ../external/emma/pregenerated)
core_resource_dirs += ../external/emma/core/res ../external/emma/pregenerated/res
endif
+endif
local_javac_flags=-encoding UTF-8
#local_javac_flags+=-Xlint:all -Xlint:-serial,-deprecation,-unchecked
@@ -78,8 +80,6 @@ LOCAL_NO_STANDARD_LIBRARIES := true
LOCAL_JAVACFLAGS := $(local_javac_flags)
LOCAL_DX_FLAGS := --core-library
-LOCAL_NO_EMMA_INSTRUMENT := true
-LOCAL_NO_EMMA_COMPILE := true
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := core
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/JavaLibrary.mk
@@ -100,8 +100,6 @@ LOCAL_JAVACFLAGS := $(local_javac_flags)
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := core-tests
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/JavaLibrary.mk
-LOCAL_NO_EMMA_INSTRUMENT := true
-LOCAL_NO_EMMA_COMPILE := true
include $(BUILD_STATIC_JAVA_LIBRARY)
# This one's tricky. One of our tests needs to have a
@@ -136,8 +134,6 @@ ifeq ($(WITH_HOST_DALVIK),true)
LOCAL_JAVACFLAGS := $(local_javac_flags)
LOCAL_DX_FLAGS := --core-library
- LOCAL_NO_EMMA_INSTRUMENT := true
- LOCAL_NO_EMMA_COMPILE := true
LOCAL_BUILD_HOST_DEX := true
LOCAL_MODULE_TAGS := optional
@@ -157,8 +153,6 @@ ifeq ($(WITH_HOST_DALVIK),true)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := core-tests-hostdex
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/JavaLibrary.mk
- LOCAL_NO_EMMA_INSTRUMENT := true
- LOCAL_NO_EMMA_COMPILE := true
LOCAL_BUILD_HOST_DEX := true
include $(BUILD_HOST_JAVA_LIBRARY)
endif
diff --git a/dalvik/src/main/java/dalvik/system/Zygote.java b/dalvik/src/main/java/dalvik/system/Zygote.java
index ec114ed..c06314e 100644
--- a/dalvik/src/main/java/dalvik/system/Zygote.java
+++ b/dalvik/src/main/java/dalvik/system/Zygote.java
@@ -41,6 +41,15 @@ public class Zygote {
/** Enable logging of third-party JNI activity. */
public static final int DEBUG_ENABLE_JNI_LOGGING = 1 << 4;
+ /** No external storage should be mounted. */
+ public static final int MOUNT_EXTERNAL_NONE = 0;
+ /** Single-user external storage should be mounted. */
+ public static final int MOUNT_EXTERNAL_SINGLEUSER = 1;
+ /** Multi-user external storage should be mounted. */
+ public static final int MOUNT_EXTERNAL_MULTIUSER = 2;
+ /** All multi-user external storage should be mounted. */
+ public static final int MOUNT_EXTERNAL_MULTIUSER_ALL = 3;
+
/**
* When set by the system server, all subsequent apps will be launched in
* VM safe mode.
@@ -114,27 +123,17 @@ public class Zygote {
* @return 0 if this is the child, pid of the child
* if this is the parent, or -1 on error.
*/
- public static int forkAndSpecialize(int uid, int gid, int[] gids,
- int debugFlags, int[][] rlimits, String seInfo, String niceName) {
+ public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
+ int[][] rlimits, int mountExternal, String seInfo, String niceName) {
preFork();
- int pid = nativeForkAndSpecialize(uid, gid, gids, debugFlags, rlimits, seInfo, niceName);
+ int pid = nativeForkAndSpecialize(
+ uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName);
postFork();
return pid;
}
- native public static int nativeForkAndSpecialize(int uid, int gid,
- int[] gids, int debugFlags, int[][] rlimits, String seInfo, String niceName);
-
- /**
- * Forks a new VM instance.
- * @deprecated use {@link Zygote#forkAndSpecialize(int, int, int[], int, int[][])}
- */
- @Deprecated
- public static int forkAndSpecialize(int uid, int gid, int[] gids,
- boolean enableDebugger, int[][] rlimits) {
- int debugFlags = enableDebugger ? DEBUG_ENABLE_DEBUGGER : 0;
- return forkAndSpecialize(uid, gid, gids, debugFlags, rlimits, null, null);
- }
+ native public static int nativeForkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
+ int[][] rlimits, int mountExternal, String seInfo, String niceName);
/**
* Special method to start the system server process. In addition to the
@@ -159,31 +158,17 @@ public class Zygote {
* @return 0 if this is the child, pid of the child
* if this is the parent, or -1 on error.
*/
- public static int forkSystemServer(int uid, int gid, int[] gids,
- int debugFlags, int[][] rlimits,
- long permittedCapabilities, long effectiveCapabilities) {
+ public static int forkSystemServer(int uid, int gid, int[] gids, int debugFlags,
+ int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
preFork();
- int pid = nativeForkSystemServer(uid, gid, gids, debugFlags, rlimits,
- permittedCapabilities,
- effectiveCapabilities);
+ int pid = nativeForkSystemServer(
+ uid, gid, gids, debugFlags, rlimits, permittedCapabilities, effectiveCapabilities);
postFork();
return pid;
}
- /**
- * Special method to start the system server process.
- * @deprecated use {@link Zygote#forkSystemServer(int, int, int[], int, int[][])}
- */
- @Deprecated
- public static int forkSystemServer(int uid, int gid, int[] gids,
- boolean enableDebugger, int[][] rlimits) {
- int debugFlags = enableDebugger ? DEBUG_ENABLE_DEBUGGER : 0;
- return forkAndSpecialize(uid, gid, gids, debugFlags, rlimits, null, null);
- }
-
- native public static int nativeForkSystemServer(int uid, int gid,
- int[] gids, int debugFlags, int[][] rlimits,
- long permittedCapabilities, long effectiveCapabilities);
+ native public static int nativeForkSystemServer(int uid, int gid, int[] gids, int debugFlags,
+ int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);
/**
* Executes "/system/bin/sh -c &lt;command&gt;" using the exec() system call.
diff --git a/expectations/brokentests.txt b/expectations/brokentests.txt
index 6fc48cd..e1d81e0 100644
--- a/expectations/brokentests.txt
+++ b/expectations/brokentests.txt
@@ -8,7 +8,12 @@
bug: 5834665
},
{
- description: "libcore.java.net.URLConnectionTest#testServerShutdownInput fails on ICL27 mysid-userdebug",
+ description: "FIONREAD/SIOCINQ returns the wrong result on sockets (5731252 is the root cause of 5534202)",
+ name: "libcore.java.net.SocketTest#testAvailable",
+ bug: 5731252
+},
+{
+ description: "libcore.java.net.URLConnectionTest#testServerShutdownInput fails on ICL27 mysid-userdebug (5534202 is caused by 5731252)",
name: "libcore.java.net.URLConnectionTest#testServerShutdownInput",
bug: 5534202
},
diff --git a/luni/src/main/java/java/lang/Object.java b/luni/src/main/java/java/lang/Object.java
index 7f4b490..4bca034 100644
--- a/luni/src/main/java/java/lang/Object.java
+++ b/luni/src/main/java/java/lang/Object.java
@@ -361,7 +361,7 @@ public class Object {
* @see java.lang.Thread
*/
public final void wait() throws InterruptedException {
- wait(0 ,0);
+ wait(0, 0);
}
/**
diff --git a/luni/src/main/java/libcore/io/DropBox.java b/luni/src/main/java/libcore/io/DropBox.java
new file mode 100644
index 0000000..cf88106
--- /dev/null
+++ b/luni/src/main/java/libcore/io/DropBox.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2012 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.io;
+
+public final class DropBox {
+
+ /**
+ * Hook for customizing how events are reported.
+ */
+ private static volatile Reporter REPORTER = new DefaultReporter();
+
+ /**
+ * Used to replace default Reporter for logging events. Must be non-null.
+ */
+ public static void setReporter(Reporter reporter) {
+ if (reporter == null) {
+ throw new NullPointerException("reporter == null");
+ }
+ REPORTER = reporter;
+ }
+
+ /**
+ * Returns non-null Reporter.
+ */
+ public static Reporter getReporter() {
+ return REPORTER;
+ }
+
+ /**
+ * Interface to allow customization of reporting behavior.
+ */
+ public static interface Reporter {
+ public void addData(String tag, byte[] data, int flags);
+ public void addText(String tag, String data);
+ }
+
+ /**
+ * Default Reporter which reports events to the log.
+ */
+ private static final class DefaultReporter implements Reporter {
+
+ public void addData(String tag, byte[] data, int flags) {
+ System.out.println(tag + ": " + Base64.encode(data));
+ }
+
+ public void addText(String tag, String data) {
+ System.out.println(tag + ": " + data);
+ }
+ }
+
+ public static void addData(String tag, byte[] data, int flags) {
+ getReporter().addData(tag, data, flags);
+ }
+
+ public static void addText(String tag, String data) {
+ getReporter().addText(tag, data);
+ }
+}
diff --git a/luni/src/main/java/libcore/io/EventLogger.java b/luni/src/main/java/libcore/io/EventLogger.java
new file mode 100644
index 0000000..9709cc9
--- /dev/null
+++ b/luni/src/main/java/libcore/io/EventLogger.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2012 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.io;
+
+public final class EventLogger {
+
+ /**
+ * Hook for customizing how events are reported.
+ */
+ private static volatile Reporter REPORTER = new DefaultReporter();
+
+ /**
+ * Used to replace default Reporter for logging events. Must be non-null.
+ */
+ public static void setReporter(Reporter reporter) {
+ if (reporter == null) {
+ throw new NullPointerException("reporter == null");
+ }
+ REPORTER = reporter;
+ }
+
+ /**
+ * Returns non-null Reporter.
+ */
+ public static Reporter getReporter() {
+ return REPORTER;
+ }
+
+ /**
+ * Interface to allow customization of reporting behavior.
+ */
+ public static interface Reporter {
+ public void report (int code, Object... list);
+ }
+
+ /**
+ * Default Reporter which reports events to the log.
+ */
+ private static final class DefaultReporter implements Reporter {
+ @Override
+ public void report (int code, Object... list) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(code);
+ for (Object o : list) {
+ sb.append(",");
+ sb.append(o.toString());
+ }
+ System.out.println(sb);
+ }
+ }
+
+ public static void writeEvent(int code, Object... list) {
+ getReporter().report(code, list);
+ }
+}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/CertPinManager.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/CertPinManager.java
new file mode 100644
index 0000000..4cdd8d2
--- /dev/null
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/CertPinManager.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2012 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.apache.harmony.xnet.provider.jsse;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.security.cert.X509Certificate;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.net.ssl.DefaultHostnameVerifier;
+import libcore.io.IoUtils;
+import libcore.util.BasicLruCache;
+
+/**
+ * This class provides a simple interface for cert pinning.
+ */
+public class CertPinManager {
+
+ private long lastModified;
+
+ private final Map<String, PinListEntry> entries = new HashMap<String, PinListEntry>();
+ private final BasicLruCache<String, String> hostnameCache = new BasicLruCache<String, String>(10);
+ private final DefaultHostnameVerifier verifier = new DefaultHostnameVerifier();
+
+ private boolean initialized = false;
+ private static final boolean DEBUG = false;
+
+ private final File pinFile;
+ private final TrustedCertificateStore certStore;
+
+ public CertPinManager(TrustedCertificateStore store) throws PinManagerException {
+ pinFile = new File("/data/misc/keychain/pins");
+ certStore = store;
+ rebuild();
+ }
+
+ /** Test only */
+ public CertPinManager(String path, TrustedCertificateStore store) throws PinManagerException {
+ if (path == null) {
+ throw new NullPointerException("path == null");
+ }
+ pinFile = new File(path);
+ certStore = store;
+ rebuild();
+ }
+
+ /**
+ * This is the public interface for cert pinning.
+ *
+ * Given a hostname and a certificate chain this verifies that the chain includes
+ * certs from the pinned list provided.
+ *
+ * If the chain doesn't include those certs and is in enforcing mode, then this method
+ * returns true and the certificate check should fail.
+ */
+ public boolean chainIsNotPinned(String hostname, List<X509Certificate> chain)
+ throws PinManagerException {
+ // lookup the entry
+ PinListEntry entry = lookup(hostname);
+
+ // return its result or false if there's no pin
+ if (entry != null) {
+ return entry.chainIsNotPinned(chain);
+ }
+ return false;
+ }
+
+ private synchronized void rebuild() throws PinManagerException {
+ // reread the pin file
+ String pinFileContents = readPinFile();
+
+ if (pinFileContents != null) {
+ // rebuild the pinned certs
+ for (String entry : getPinFileEntries(pinFileContents)) {
+ try {
+ PinListEntry pin = new PinListEntry(entry, certStore);
+ entries.put(pin.getCommonName(), pin);
+ } catch (PinEntryException e) {
+ log("Pinlist contains a malformed pin: " + entry, e);
+ }
+ }
+
+ // clear the cache
+ hostnameCache.evictAll();
+
+ // set the last modified time
+ lastModified = pinFile.lastModified();
+
+ // we've been fully initialized and are ready to go
+ initialized = true;
+ }
+ }
+
+ private String readPinFile() throws PinManagerException {
+ try {
+ return IoUtils.readFileAsString(pinFile.getPath());
+ } catch (FileNotFoundException e) {
+ // there's no pin list, all certs are unpinned
+ return null;
+ } catch (IOException e) {
+ // this is unexpected, fail
+ throw new PinManagerException("Unexpected error reading pin list; failing.", e);
+ }
+ }
+
+ private static String[] getPinFileEntries(String pinFileContents) {
+ return pinFileContents.split("\n");
+ }
+
+ private synchronized PinListEntry lookup(String hostname) throws PinManagerException {
+
+ // if we don't have any data, don't bother
+ if (!initialized) {
+ return null;
+ }
+
+ // check to see if our cache is valid
+ if (cacheIsNotValid()) {
+ rebuild();
+ }
+
+ // if so, check the hostname cache
+ String cn = hostnameCache.get(hostname);
+ if (cn != null) {
+ // if we hit, return the corresponding entry
+ return entries.get(cn);
+ }
+
+ // otherwise, get the matching cn
+ cn = getMatchingCN(hostname);
+ if (cn != null) {
+ hostnameCache.put(hostname, cn);
+ // we have a matching CN, return that entry
+ return entries.get(cn);
+ }
+
+ // if we got here, we don't have a matching CN for this hostname
+ return null;
+ }
+
+ private boolean cacheIsNotValid() {
+ return pinFile.lastModified() != lastModified;
+ }
+
+ private String getMatchingCN(String hostname) {
+ String bestMatch = "";
+ for (String cn : entries.keySet()) {
+ // skip shorter CNs since they can't be better matches
+ if (cn.length() < bestMatch.length()) {
+ continue;
+ }
+ // now verify that the CN matches at all
+ if (verifier.verifyHostName(hostname, cn)) {
+ bestMatch = cn;
+ }
+ }
+ return bestMatch;
+ }
+
+ private static void log(String s, Exception e) {
+ if (DEBUG) {
+ System.out.println("PINFILE: " + s);
+ if (e != null) {
+ e.printStackTrace();
+ }
+ }
+ }
+}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientHandshakeImpl.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientHandshakeImpl.java
index 83f86ae..c855c0c 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientHandshakeImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientHandshakeImpl.java
@@ -37,6 +37,7 @@ import javax.crypto.spec.DHPublicKeySpec;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.X509ExtendedKeyManager;
import javax.net.ssl.X509KeyManager;
+import javax.net.ssl.X509TrustManager;
import javax.security.auth.x500.X500Principal;
/**
@@ -88,7 +89,7 @@ public class ClientHandshakeImpl extends HandshakeProtocol {
if (engineOwner != null) {
session.setPeer(engineOwner.getPeerHost(), engineOwner.getPeerPort());
} else {
- session.setPeer(socketOwner.getInetAddress().getHostName(), socketOwner.getPort());
+ session.setPeer(socketOwner.getPeerHostName(), socketOwner.getPeerPort());
}
session.protocol = ProtocolVersion.getLatestVersion(parameters.getEnabledProtocols());
recordProtocol.setVersion(session.protocol.version);
@@ -109,7 +110,7 @@ public class ClientHandshakeImpl extends HandshakeProtocol {
if (engineOwner != null) {
session.setPeer(engineOwner.getPeerHost(), engineOwner.getPeerPort());
} else {
- session.setPeer(socketOwner.getInetAddress().getHostName(), socketOwner.getPort());
+ session.setPeer(socketOwner.getPeerHostName(), socketOwner.getPeerPort());
}
session.protocol = ProtocolVersion.getLatestVersion(parameters.getEnabledProtocols());
recordProtocol.setVersion(session.protocol.version);
@@ -527,8 +528,21 @@ public class ClientHandshakeImpl extends HandshakeProtocol {
if (authType == null) {
return;
}
+ String hostname = null;
+ if (engineOwner != null) {
+ hostname = engineOwner.getPeerHost();
+ } else {
+ // we don't want to do an inet address lookup here in case we're talking to a proxy
+ hostname = socketOwner.getWrappedHostName();
+ }
try {
- parameters.getTrustManager().checkServerTrusted(serverCert.certs, authType);
+ X509TrustManager x509tm = parameters.getTrustManager();
+ if (x509tm instanceof TrustManagerImpl) {
+ TrustManagerImpl tm = (TrustManagerImpl) x509tm;
+ tm.checkServerTrusted(serverCert.certs, authType, hostname);
+ } else {
+ x509tm.checkServerTrusted(serverCert.certs, authType);
+ }
} catch (CertificateException e) {
fatalAlert(AlertProtocol.BAD_CERTIFICATE, "Not trusted server certificate", e);
return;
@@ -559,8 +573,8 @@ public class ClientHandshakeImpl extends HandshakeProtocol {
host = engineOwner.getPeerHost();
port = engineOwner.getPeerPort();
} else {
- host = socketOwner.getInetAddress().getHostName();
- port = socketOwner.getPort();
+ host = socketOwner.getPeerHostName();
+ port = socketOwner.getPeerPort();
}
if (host == null || port == -1) {
return null; // starts new session
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java
index 84f33f2..65373ff 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java
@@ -78,6 +78,8 @@ public final class NativeCrypto {
public static native void EVP_PKEY_free(int pkey);
+ public static native int EVP_PKEY_cmp(int pkey1, int pkey2);
+
public static native byte[] i2d_PKCS8_PRIV_KEY_INFO(int pkey);
public static native int d2i_PKCS8_PRIV_KEY_INFO(byte[] data);
@@ -643,7 +645,7 @@ public final class NativeCrypto {
public static native int SSL_read(int sslNativePointer,
FileDescriptor fd,
SSLHandshakeCallbacks shc,
- byte[] b, int off, int len, int timeoutMillis)
+ byte[] b, int off, int len, int readTimeoutMillis)
throws IOException;
/**
@@ -652,7 +654,7 @@ public final class NativeCrypto {
public static native void SSL_write(int sslNativePointer,
FileDescriptor fd,
SSLHandshakeCallbacks shc,
- byte[] b, int off, int len)
+ byte[] b, int off, int len, int writeTimeoutMillis)
throws IOException;
public static native void SSL_interrupt(int sslNativePointer);
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLProvider.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLProvider.java
index e1d0fb0..fd9be17 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLProvider.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLProvider.java
@@ -80,26 +80,26 @@ public final class OpenSSLProvider extends Provider {
put("Alg.Alias.Signature.1.2.840.113549.2.5with1.2.840.113549.1.1.1",
"MD5WithRSAEncryption");
- put("Signature.SHA1WithRSAEncryption", OpenSSLSignature.SHA1RSA.class.getName());
- put("Alg.Alias.Signature.SHA1WithRSA", "SHA1WithRSAEncryption");
- put("Alg.Alias.Signature.SHA1/RSA", "SHA1WithRSAEncryption");
- put("Alg.Alias.Signature.SHA-1/RSA", "SHA1WithRSAEncryption");
- put("Alg.Alias.Signature.1.2.840.113549.1.1.5", "SHA1WithRSAEncryption");
- put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.113549.1.1.1", "SHA1WithRSAEncryption");
- put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.113549.1.1.5", "SHA1WithRSAEncryption");
- put("Alg.Alias.Signature.1.3.14.3.2.29", "SHA1WithRSAEncryption");
-
- put("Signature.SHA256WithRSAEncryption", OpenSSLSignature.SHA256RSA.class.getName());
- put("Alg.Alias.Signature.SHA256WithRSA", "SHA256WithRSAEncryption");
- put("Alg.Alias.Signature.1.2.840.113549.1.1.11", "SHA256WithRSAEncryption");
-
- put("Signature.SHA384WithRSAEncryption", OpenSSLSignature.SHA384RSA.class.getName());
- put("Alg.Alias.Signature.SHA384WithRSA", "SHA384WithRSAEncryption");
- put("Alg.Alias.Signature.1.2.840.113549.1.1.12", "SHA384WithRSAEncryption");
-
- put("Signature.SHA512WithRSAEncryption", OpenSSLSignature.SHA512RSA.class.getName());
- put("Alg.Alias.Signature.SHA512WithRSA", "SHA512WithRSAEncryption");
- put("Alg.Alias.Signature.1.2.840.113549.1.1.13", "SHA512WithRSAEncryption");
+ put("Signature.SHA1WithRSA", OpenSSLSignature.SHA1RSA.class.getName());
+ put("Alg.Alias.Signature.SHA1WithRSA", "SHA1WithRSA");
+ put("Alg.Alias.Signature.SHA1/RSA", "SHA1WithRSA");
+ put("Alg.Alias.Signature.SHA-1/RSA", "SHA1WithRSA");
+ put("Alg.Alias.Signature.1.2.840.113549.1.1.5", "SHA1WithRSA");
+ put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.113549.1.1.1", "SHA1WithRSA");
+ put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.113549.1.1.5", "SHA1WithRSA");
+ put("Alg.Alias.Signature.1.3.14.3.2.29", "SHA1WithRSA");
+
+ put("Signature.SHA256WithRSA", OpenSSLSignature.SHA256RSA.class.getName());
+ put("Alg.Alias.Signature.SHA256WithRSAEncryption", "SHA256WithRSA");
+ put("Alg.Alias.Signature.1.2.840.113549.1.1.11", "SHA256WithRSA");
+
+ put("Signature.SHA384WithRSA", OpenSSLSignature.SHA384RSA.class.getName());
+ put("Alg.Alias.Signature.SHA384WithRSAEncryption", "SHA384WithRSA");
+ put("Alg.Alias.Signature.1.2.840.113549.1.1.12", "SHA384WithRSA");
+
+ put("Signature.SHA512WithRSA", OpenSSLSignature.SHA512RSA.class.getName());
+ put("Alg.Alias.Signature.SHA512WithRSAEncryption", "SHA512WithRSA");
+ put("Alg.Alias.Signature.1.2.840.113549.1.1.13", "SHA512WithRSA");
put("Signature.SHA1withDSA", OpenSSLSignature.SHA1DSA.class.getName());
put("Alg.Alias.Signature.SHA/DSA", "SHA1withDSA");
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAPrivateCrtKey.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAPrivateCrtKey.java
index f1e12c2..0f43bf9 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAPrivateCrtKey.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAPrivateCrtKey.java
@@ -197,8 +197,8 @@ public class OpenSSLRSAPrivateCrtKey extends OpenSSLRSAPrivateKey implements RSA
return true;
}
- if (o instanceof OpenSSLRSAPrivateCrtKey) {
- OpenSSLRSAPrivateCrtKey other = (OpenSSLRSAPrivateCrtKey) o;
+ if (o instanceof OpenSSLRSAPrivateKey) {
+ OpenSSLRSAPrivateKey other = (OpenSSLRSAPrivateKey) o;
/*
* We can shortcut the true case, but it still may be equivalent but
@@ -208,28 +208,35 @@ public class OpenSSLRSAPrivateCrtKey extends OpenSSLRSAPrivateKey implements RSA
return true;
}
- /*
- * If this key is ENGINE-based, it could be equivalent to another
- * ENGINE-based key. The modulus may be equal, but that occurrence
- * should be so improbably low as to never happen.
- */
- if (getOpenSSLKey().isEngineBased() || other.getOpenSSLKey().isEngineBased()) {
- return publicExponent.equals(other.getPublicExponent())
- && getModulus().equals(other.getModulus());
- }
+ return NativeCrypto.EVP_PKEY_cmp(getPkeyContext(), other.getPkeyContext()) == 1;
}
if (o instanceof RSAPrivateCrtKey) {
ensureReadParams();
RSAPrivateCrtKey other = (RSAPrivateCrtKey) o;
- return getModulus().equals(other.getModulus())
- && publicExponent.equals(other.getPublicExponent())
- && getPrivateExponent().equals(other.getPrivateExponent())
- && primeP.equals(other.getPrimeP()) && primeQ.equals(other.getPrimeQ())
- && primeExponentP.equals(other.getPrimeExponentP())
- && primeExponentQ.equals(other.getPrimeExponentQ())
- && crtCoefficient.equals(other.getCrtCoefficient());
+ if (getOpenSSLKey().isEngineBased()) {
+ return getModulus().equals(other.getModulus())
+ && publicExponent.equals(other.getPublicExponent());
+ } else {
+ return getModulus().equals(other.getModulus())
+ && publicExponent.equals(other.getPublicExponent())
+ && getPrivateExponent().equals(other.getPrivateExponent())
+ && primeP.equals(other.getPrimeP()) && primeQ.equals(other.getPrimeQ())
+ && primeExponentP.equals(other.getPrimeExponentP())
+ && primeExponentQ.equals(other.getPrimeExponentQ())
+ && crtCoefficient.equals(other.getCrtCoefficient());
+ }
+ } else if (o instanceof RSAPrivateKey) {
+ ensureReadParams();
+ RSAPrivateKey other = (RSAPrivateKey) o;
+
+ if (getOpenSSLKey().isEngineBased()) {
+ return getModulus().equals(other.getModulus());
+ } else {
+ return getModulus().equals(other.getModulus())
+ && getPrivateExponent().equals(other.getPrivateExponent());
+ }
}
return false;
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAPrivateKey.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAPrivateKey.java
index fa455c7..6ad89b2 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAPrivateKey.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLRSAPrivateKey.java
@@ -205,14 +205,7 @@ public class OpenSSLRSAPrivateKey implements RSAPrivateKey {
return true;
}
- /*
- * If this key is ENGINE-based, it could be equivalent to another
- * ENGINE-based key. The modulus may be equal, but that occurrence
- * should be so improbably low as to never happen.
- */
- if (key.isEngineBased() || other.getOpenSSLKey().isEngineBased()) {
- return modulus.equals(other.getModulus());
- }
+ return NativeCrypto.EVP_PKEY_cmp(getPkeyContext(), other.getPkeyContext()) == 1;
}
if (o instanceof RSAPrivateKey) {
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java
index 3720ba2..4cc16e6 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java
@@ -42,7 +42,11 @@ import javax.net.ssl.SSLProtocolException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.X509TrustManager;
import javax.security.auth.x500.X500Principal;
+import static libcore.io.OsConstants.*;
+import libcore.io.ErrnoException;
+import libcore.io.Libcore;
import libcore.io.Streams;
+import libcore.io.StructTimeval;
import org.apache.harmony.security.provider.cert.X509CertImpl;
/**
@@ -93,7 +97,8 @@ public class OpenSSLSocketImpl
* OpenSSLSocketImplWrapper overrides setSoTimeout and
* getSoTimeout to delegate to the wrapped socket.
*/
- private int timeoutMilliseconds = 0;
+ private int readTimeoutMilliseconds = 0;
+ private int writeTimeoutMilliseconds = 0;
private int handshakeTimeoutMilliseconds = -1; // -1 = same as timeout; 0 = infinite
private String wrappedHost;
@@ -361,9 +366,11 @@ public class OpenSSLSocketImpl
}
// Temporarily use a different timeout for the handshake process
- int savedTimeoutMilliseconds = getSoTimeout();
+ int savedReadTimeoutMilliseconds = getSoTimeout();
+ int savedWriteTimeoutMilliseconds = getSoWriteTimeout();
if (handshakeTimeoutMilliseconds >= 0) {
setSoTimeout(handshakeTimeoutMilliseconds);
+ setSoWriteTimeout(handshakeTimeoutMilliseconds);
}
int sslSessionNativePointer;
@@ -399,7 +406,8 @@ public class OpenSSLSocketImpl
// Restore the original timeout now that the handshake is complete
if (handshakeTimeoutMilliseconds >= 0) {
- setSoTimeout(savedTimeoutMilliseconds);
+ setSoTimeout(savedReadTimeoutMilliseconds);
+ setSoWriteTimeout(savedWriteTimeoutMilliseconds);
}
// if not, notifyHandshakeCompletedListeners later in handshakeCompleted() callback
@@ -418,7 +426,7 @@ public class OpenSSLSocketImpl
}
}
- private String getPeerHostName() {
+ String getPeerHostName() {
if (wrappedHost != null) {
return wrappedHost;
}
@@ -429,7 +437,7 @@ public class OpenSSLSocketImpl
return null;
}
- private int getPeerPort() {
+ int getPeerPort() {
return wrappedHost == null ? super.getPort() : wrappedPort;
}
@@ -570,8 +578,13 @@ public class OpenSSLSocketImpl
}
boolean client = sslParameters.getUseClientMode();
if (client) {
- sslParameters.getTrustManager().checkServerTrusted(peerCertificateChain,
- authMethod);
+ X509TrustManager x509tm = sslParameters.getTrustManager();
+ if (x509tm instanceof TrustManagerImpl) {
+ TrustManagerImpl tm = (TrustManagerImpl) x509tm;
+ tm.checkServerTrusted(peerCertificateChain, authMethod, wrappedHost);
+ } else {
+ x509tm.checkServerTrusted(peerCertificateChain, authMethod);
+ }
} else {
String authType = peerCertificateChain[0].getPublicKey().getAlgorithm();
sslParameters.getTrustManager().checkClientTrusted(peerCertificateChain,
@@ -691,7 +704,7 @@ public class OpenSSLSocketImpl
return;
}
NativeCrypto.SSL_write(sslNativePointer, socket.getFileDescriptor$(),
- OpenSSLSocketImpl.this, buf, offset, byteCount);
+ OpenSSLSocketImpl.this, buf, offset, byteCount, writeTimeoutMilliseconds);
}
}
}
@@ -822,21 +835,42 @@ public class OpenSSLSocketImpl
throw new SocketException("Methods sendUrgentData, setOOBInline are not supported.");
}
- @Override public void setSoTimeout(int timeoutMilliseconds) throws SocketException {
- super.setSoTimeout(timeoutMilliseconds);
- this.timeoutMilliseconds = timeoutMilliseconds;
+ @Override public void setSoTimeout(int readTimeoutMilliseconds) throws SocketException {
+ super.setSoTimeout(readTimeoutMilliseconds);
+ this.readTimeoutMilliseconds = readTimeoutMilliseconds;
}
@Override public int getSoTimeout() throws SocketException {
- return timeoutMilliseconds;
+ return readTimeoutMilliseconds;
+ }
+
+ /**
+ * Note write timeouts are not part of the javax.net.ssl.SSLSocket API
+ */
+ public void setSoWriteTimeout(int writeTimeoutMilliseconds) throws SocketException {
+ this.writeTimeoutMilliseconds = writeTimeoutMilliseconds;
+
+ StructTimeval tv = StructTimeval.fromMillis(writeTimeoutMilliseconds);
+ try {
+ Libcore.os.setsockoptTimeval(getFileDescriptor$(), SOL_SOCKET, SO_SNDTIMEO, tv);
+ } catch (ErrnoException errnoException) {
+ throw errnoException.rethrowAsSocketException();
+ }
+ }
+
+ /**
+ * Note write timeouts are not part of the javax.net.ssl.SSLSocket API
+ */
+ public int getSoWriteTimeout() throws SocketException {
+ return writeTimeoutMilliseconds;
}
/**
* Set the handshake timeout on this socket. This timeout is specified in
* milliseconds and will be used only during the handshake process.
*/
- public void setHandshakeTimeout(int timeoutMilliseconds) throws SocketException {
- this.handshakeTimeoutMilliseconds = timeoutMilliseconds;
+ public void setHandshakeTimeout(int handshakeTimeoutMilliseconds) throws SocketException {
+ this.handshakeTimeoutMilliseconds = handshakeTimeoutMilliseconds;
}
@Override public void close() throws IOException {
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/PinEntryException.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/PinEntryException.java
new file mode 100644
index 0000000..8b74514
--- /dev/null
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/PinEntryException.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2012 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.apache.harmony.xnet.provider.jsse;
+
+// public for testing by CertPinManagerTest
+public class PinEntryException extends Exception {
+
+ PinEntryException() {
+ }
+
+ PinEntryException(String msg) {
+ super(msg);
+ }
+}
+
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/PinFailureLogger.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/PinFailureLogger.java
new file mode 100644
index 0000000..40b1838
--- /dev/null
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/PinFailureLogger.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2012 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.apache.harmony.xnet.provider.jsse;
+
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.List;
+import libcore.io.Base64;
+import libcore.io.DropBox;
+
+public class PinFailureLogger {
+
+ private static final long LOG_INTERVAL_NANOS = 1000 * 1000 * 1000 * 60 * 60;
+
+ private static long lastLoggedNanos = 0;
+
+ public static synchronized void log(String cn, boolean chainContainsUserCert,
+ boolean pinIsEnforcing,
+ List<X509Certificate> chain) {
+ // if we've logged recently, don't do it again
+ if (!timeToLog()) {
+ return;
+ }
+ // otherwise, log the event
+ writeToLog(cn, chainContainsUserCert, pinIsEnforcing, chain);
+ // update the last logged time
+ lastLoggedNanos = System.nanoTime();
+ }
+
+ protected static synchronized void writeToLog(String cn, boolean chainContainsUserCert,
+ boolean pinIsEnforcing,
+ List<X509Certificate> chain) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(cn);
+ sb.append("|");
+ sb.append(chainContainsUserCert);
+ sb.append("|");
+ sb.append(pinIsEnforcing);
+ sb.append("|");
+ for (X509Certificate cert : chain) {
+ try {
+ sb.append(Base64.encode(cert.getEncoded()));
+ } catch (CertificateEncodingException e) {
+ sb.append("Error: could not encode certificate");
+ }
+ sb.append("|");
+ }
+ DropBox.addText("cert_pin_failure", sb.toString());
+ }
+
+ protected static boolean timeToLog() {
+ long currentTimeNanos = System.nanoTime();
+ return ((currentTimeNanos - lastLoggedNanos) > LOG_INTERVAL_NANOS);
+ }
+}
+
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/PinListEntry.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/PinListEntry.java
new file mode 100644
index 0000000..c05a391
--- /dev/null
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/PinListEntry.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2012 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.apache.harmony.xnet.provider.jsse;
+
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import libcore.io.EventLogger;
+
+/**
+ * This class represents a single entry in the pin file.
+ */
+// public for testing by CertPinManagerTest
+public class PinListEntry {
+
+ /** The Common Name (CN) as used on the SSL certificate */
+ private final String cn;
+
+ /**
+ * Determines whether a failed match here will prevent the chain from being accepted. If true,
+ * an unpinned chain will log and cause a match failure. If false, it will merely log.
+ */
+ private final boolean enforcing;
+
+ private final Set<String> pinnedFingerprints = new HashSet<String>();
+
+ private static final boolean DEBUG = false;
+
+ private final TrustedCertificateStore certStore;
+
+ public String getCommonName() {
+ return cn;
+ }
+
+ public boolean getEnforcing() {
+ return enforcing;
+ }
+
+ public PinListEntry(String entry, TrustedCertificateStore store) throws PinEntryException {
+ if (entry == null) {
+ throw new NullPointerException("entry == null");
+ }
+ certStore = store;
+ // Examples:
+ // *.google.com=true|34c8a0d...9e04ca05f,9e04ca05f...34c8a0d
+ // *.android.com=true|ca05f...8a0d34c
+ // clients.google.com=false|9e04ca05f...34c8a0d,34c8a0d...9e04ca05f
+ String[] values = entry.split("[=,|]");
+ // entry must have a CN, an enforcement value, and at least one pin
+ if (values.length < 3) {
+ throw new PinEntryException("Received malformed pin entry");
+ }
+ // get the cn
+ cn = values[0]; // is there more validation we can do here?
+ enforcing = enforcementValueFromString(values[1]);
+ // the remainder should be pins
+ addPins(Arrays.copyOfRange(values, 2, values.length));
+ }
+
+ private static boolean enforcementValueFromString(String val) throws PinEntryException {
+ if (val.equals("true")) {
+ return true;
+ } else if (val.equals("false")) {
+ return false;
+ } else {
+ throw new PinEntryException("Enforcement status is not a valid value");
+ }
+ }
+
+ /**
+ * Checks the given chain against the pin list corresponding to this entry.
+ *
+ * If the pin list does not contain the required certs and the enforcing field is true then
+ * this returns true, indicating a verification error. Otherwise, it returns false and
+ * verification should proceed.
+ */
+ public boolean chainIsNotPinned(List<X509Certificate> chain) {
+ for (X509Certificate cert : chain) {
+ String fingerprint = getFingerprint(cert);
+ if (pinnedFingerprints.contains(fingerprint)) {
+ return false;
+ }
+ }
+ logPinFailure(chain);
+ return enforcing;
+ }
+
+ private static String getFingerprint(X509Certificate cert) {
+ try {
+ MessageDigest dgst = MessageDigest.getInstance("SHA512");
+ byte[] encoded = cert.getPublicKey().getEncoded();
+ byte[] fingerprint = dgst.digest(encoded);
+ return IntegralToString.bytesToHexString(fingerprint, false);
+ } catch (NoSuchAlgorithmException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ private void addPins(String[] pins) {
+ for (String pin : pins) {
+ validatePin(pin);
+ }
+ Collections.addAll(pinnedFingerprints, pins);
+ }
+
+ private static void validatePin(String pin) {
+ // check to make sure the length is correct
+ if (pin.length() != 128) {
+ throw new IllegalArgumentException("Pin is not a valid length");
+ }
+ // check to make sure that it's a valid hex string
+ try {
+ new BigInteger(pin, 16);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Pin is not a valid hex string", e);
+ }
+ }
+
+ private boolean chainContainsUserCert(List<X509Certificate> chain) {
+ if (certStore == null) {
+ return false;
+ }
+ for (X509Certificate cert : chain) {
+ if (certStore.isUserAddedCertificate(cert)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void logPinFailure(List<X509Certificate> chain) {
+ PinFailureLogger.log(cn, chainContainsUserCert(chain), enforcing, chain);
+ }
+}
+
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/PinManagerException.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/PinManagerException.java
new file mode 100644
index 0000000..74b3c65
--- /dev/null
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/PinManagerException.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012 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.apache.harmony.xnet.provider.jsse;
+
+class PinManagerException extends Exception {
+
+ PinManagerException() {
+ }
+
+ PinManagerException(String msg) {
+ super(msg);
+ }
+
+ PinManagerException(String msg, Exception e) {
+ super(msg, e);
+ }
+}
+
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLSocketFactoryImpl.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLSocketFactoryImpl.java
index be9a7fc..93496cf 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLSocketFactoryImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLSocketFactoryImpl.java
@@ -88,7 +88,7 @@ public class SSLSocketFactoryImpl extends SSLSocketFactory {
if (instantiationException != null) {
throw instantiationException;
}
- return new SSLSocketWrapper(s, autoClose, (SSLParametersImpl) sslParameters
+ return new SSLSocketWrapper(s, host, port, autoClose, (SSLParametersImpl) sslParameters
.clone());
}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLSocketImpl.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLSocketImpl.java
index 6e5fddd..2cd2cf5 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLSocketImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLSocketImpl.java
@@ -41,6 +41,10 @@ public class SSLSocketImpl extends SSLSocket {
// indicates if handshake has been started
private boolean handshake_started = false;
+ // used when we're wrapping a socket
+ private final String wrappedHost;
+ private final int wrappedPort;
+
// record protocol to be used
protected SSLRecordProtocol recordProtocol;
// handshake protocol to be used
@@ -83,6 +87,8 @@ public class SSLSocketImpl extends SSLSocket {
*/
protected SSLSocketImpl(SSLParametersImpl sslParameters) {
this.sslParameters = sslParameters;
+ this.wrappedHost = null;
+ this.wrappedPort = -1;
// init should be called after creation!
}
@@ -99,6 +105,8 @@ public class SSLSocketImpl extends SSLSocket {
protected SSLSocketImpl(String host, int port, SSLParametersImpl sslParameters)
throws IOException, UnknownHostException {
super(host, port);
+ this.wrappedHost = host;
+ this.wrappedPort = port;
this.sslParameters = sslParameters;
init();
}
@@ -120,6 +128,8 @@ public class SSLSocketImpl extends SSLSocket {
SSLParametersImpl sslParameters) throws IOException,
UnknownHostException {
super(host, port, localHost, localPort);
+ this.wrappedHost = host;
+ this.wrappedPort = port;
this.sslParameters = sslParameters;
init();
}
@@ -138,6 +148,8 @@ public class SSLSocketImpl extends SSLSocket {
SSLParametersImpl sslParameters) throws IOException {
super(host, port);
this.sslParameters = sslParameters;
+ this.wrappedHost = null;
+ this.wrappedPort = -1;
init();
}
@@ -158,6 +170,8 @@ public class SSLSocketImpl extends SSLSocket {
SSLParametersImpl sslParameters) throws IOException {
super(address, port, localAddress, localPort);
this.sslParameters = sslParameters;
+ this.wrappedHost = null;
+ this.wrappedPort = -1;
init();
}
@@ -193,6 +207,29 @@ public class SSLSocketImpl extends SSLSocket {
}
}
+ String getWrappedHostName() {
+ return wrappedHost;
+ }
+
+ int getWrappedPort() {
+ return wrappedPort;
+ }
+
+ String getPeerHostName() {
+ if (wrappedHost != null) {
+ return wrappedHost;
+ }
+ InetAddress inetAddress = super.getInetAddress();
+ if (inetAddress != null) {
+ return inetAddress.getHostName();
+ }
+ return null;
+ }
+
+ int getPeerPort() {
+ return (wrappedPort == -1) ? super.getPort() : wrappedPort;
+ }
+
// --------------- SSLParameters based methods ---------------------
/**
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLSocketWrapper.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLSocketWrapper.java
index 27bbead..a393e24 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLSocketWrapper.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLSocketWrapper.java
@@ -32,8 +32,9 @@ public class SSLSocketWrapper extends SSLSocketImpl {
private final Socket socket;
private final boolean autoClose;
- protected SSLSocketWrapper(Socket socket, boolean autoClose, SSLParametersImpl sslParameters) throws IOException {
- super(sslParameters);
+ protected SSLSocketWrapper(Socket socket, String host, int port, boolean autoClose,
+ SSLParametersImpl sslParameters) throws IOException {
+ super(host, port, sslParameters);
if (!socket.isConnected()) {
throw new SocketException("Socket is not connected.");
}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustManagerImpl.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustManagerImpl.java
index 3f362c5..0218249 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustManagerImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustManagerImpl.java
@@ -35,6 +35,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.net.ssl.X509TrustManager;
+import libcore.io.EventLogger;
/**
*
@@ -52,6 +53,11 @@ public final class TrustManagerImpl implements X509TrustManager {
private final KeyStore rootKeyStore;
/**
+ * The CertPinManager, which validates the chain against a host-to-pin mapping
+ */
+ private CertPinManager pinManager;
+
+ /**
* The backing store for the AndroidCAStore if non-null. This will
* be null when the rootKeyStore is null, implying we are not
* using the AndroidCAStore.
@@ -83,6 +89,13 @@ public final class TrustManagerImpl implements X509TrustManager {
* @param ks
*/
public TrustManagerImpl(KeyStore keyStore) {
+ this(keyStore, null);
+ }
+
+ /**
+ * For testing only
+ */
+ public TrustManagerImpl(KeyStore keyStore, CertPinManager manager) {
CertPathValidator validatorLocal = null;
CertificateFactory factoryLocal = null;
KeyStore rootKeyStoreLocal = null;
@@ -111,6 +124,17 @@ public final class TrustManagerImpl implements X509TrustManager {
} catch (Exception e) {
errLocal = e;
}
+
+ if (manager != null) {
+ this.pinManager = manager;
+ } else {
+ try {
+ pinManager = new CertPinManager(trustedCertificateStoreLocal);
+ } catch (PinManagerException e) {
+ throw new SecurityException("Could not initialize CertPinManager", e);
+ }
+ }
+
this.rootKeyStore = rootKeyStoreLocal;
this.trustedCertificateStore = trustedCertificateStoreLocal;
this.validator = validatorLocal;
@@ -155,12 +179,22 @@ public final class TrustManagerImpl implements X509TrustManager {
@Override public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
- checkTrusted(chain, authType);
+ checkTrusted(chain, authType, null);
}
@Override public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
- checkTrusted(chain, authType);
+ checkTrusted(chain, authType, null);
+ }
+
+ /**
+ * Validates whether a server is trusted. If hostname is given and non-null it also checks if
+ * chain is pinned appropriately for that host. If null, it does not check for pinned certs.
+ * The return value is a list of the certificates used for making the trust decision.
+ */
+ public List<X509Certificate> checkServerTrusted(X509Certificate[] chain, String authType,
+ String host) throws CertificateException {
+ return checkTrusted(chain, authType, host);
}
public void handleTrustStorageUpdate() {
@@ -168,10 +202,10 @@ public final class TrustManagerImpl implements X509TrustManager {
trustedCertificateIndex.reset();
} else {
trustedCertificateIndex.reset(trustAnchors(acceptedIssuers));
- }
+ }
}
- private void checkTrusted(X509Certificate[] chain, String authType)
+ private List<X509Certificate> checkTrusted(X509Certificate[] chain, String authType, String host)
throws CertificateException {
if (chain == null || chain.length == 0 || authType == null || authType.length() == 0) {
throw new IllegalArgumentException("null or zero-length parameter");
@@ -180,21 +214,71 @@ public final class TrustManagerImpl implements X509TrustManager {
throw new CertificateException(err);
}
- Set<TrustAnchor> trustAnchors = new HashSet<TrustAnchor>();
- X509Certificate[] newChain = cleanupCertChainAndFindTrustAnchors(chain, trustAnchors);
+ // get the cleaned up chain and trust anchor
+ Set<TrustAnchor> trustAnchor = new HashSet<TrustAnchor>(); // there can only be one!
+ X509Certificate[] newChain = cleanupCertChainAndFindTrustAnchors(chain, trustAnchor);
+
+ // add the first trust anchor to the chain, which may be an intermediate
+ List<X509Certificate> wholeChain = new ArrayList<X509Certificate>();
+ wholeChain.addAll(Arrays.asList(newChain));
+ // trustAnchor is actually just a single element
+ for (TrustAnchor trust : trustAnchor) {
+ wholeChain.add(trust.getTrustedCert());
+ }
+
+ // add all the cached certificates from the cert index, avoiding loops
+ // this gives us a full chain from leaf to root, which we use for cert pinning and pass
+ // back out to callers when we return.
+ X509Certificate last = wholeChain.get(wholeChain.size() - 1);
+ while (true) {
+ TrustAnchor cachedTrust = trustedCertificateIndex.findByIssuerAndSignature(last);
+ // the cachedTrust can be null if there isn't anything in the index or if a user has
+ // trusted a non-self-signed cert.
+ if (cachedTrust == null) {
+ break;
+ }
+
+ // at this point we have a cached trust anchor, but don't know if its one we got from
+ // the server. Extract the cert, compare it to the last element in the chain, and add it
+ // if we haven't seen it before.
+ X509Certificate next = cachedTrust.getTrustedCert();
+ if (next != last) {
+ wholeChain.add(next);
+ last = next;
+ } else {
+ // if next == last then we found a self-signed cert and the chain is done
+ break;
+ }
+ }
+
+ // build the cert path from the array of certs sans trust anchors
+ CertPath certPath = factory.generateCertPath(Arrays.asList(newChain));
+
+ if (host != null) {
+ boolean chainIsNotPinned = true;
+ try {
+ chainIsNotPinned = pinManager.chainIsNotPinned(host, wholeChain);
+ } catch (PinManagerException e) {
+ throw new CertificateException(e);
+ }
+ if (chainIsNotPinned) {
+ throw new CertificateException(new CertPathValidatorException(
+ "Certificate path is not properly pinned.", null, certPath, -1));
+ }
+ }
+
if (newChain.length == 0) {
// chain was entirely trusted, skip the validator
- return;
+ return wholeChain;
}
- CertPath certPath = factory.generateCertPath(Arrays.asList(newChain));
- if (trustAnchors.isEmpty()) {
+ if (trustAnchor.isEmpty()) {
throw new CertificateException(new CertPathValidatorException(
"Trust anchor for certification path not found.", null, certPath, -1));
}
try {
- PKIXParameters params = new PKIXParameters(trustAnchors);
+ PKIXParameters params = new PKIXParameters(trustAnchor);
params.setRevocationEnabled(false);
validator.validate(certPath, params);
// Add intermediate CAs to the index to tolerate sites
@@ -211,6 +295,8 @@ public final class TrustManagerImpl implements X509TrustManager {
} catch (CertPathValidatorException e) {
throw new CertificateException(e);
}
+
+ return wholeChain;
}
/**
@@ -232,17 +318,9 @@ public final class TrustManagerImpl implements X509TrustManager {
// Start with the first certificate in the chain, assuming it
// is the leaf certificate (server or client cert).
for (currIndex = 0; currIndex < chain.length; currIndex++) {
- // If the current cert is a TrustAnchor, we can ignore the rest of the chain.
- // This avoids including "bridge" CA certs that added for legacy compatability.
- TrustAnchor trustAnchor = findTrustAnchorBySubjectAndPublicKey(chain[currIndex]);
- if (trustAnchor != null) {
- trustAnchors.add(trustAnchor);
- currIndex--;
- break;
- }
- // Walk the rest of the chain to find a "subject" matching
+ // Walk the chain to find a "subject" matching
// the "issuer" of the current certificate. In a properly
- // order chain this should be the next cert and be fast.
+ // ordered chain this should be the next cert and be fast.
// If not, we reorder things to be as the validator will
// expect.
boolean foundNext = false;
@@ -271,15 +349,27 @@ public final class TrustManagerImpl implements X509TrustManager {
}
}
- // 2. If the chain is now shorter, copy to an appropriately sized array.
- int chainLength = currIndex + 1;
+ // 2. Find the trust anchor in the chain, if any
+ int anchorIndex;
+ for (anchorIndex = 0; anchorIndex < chain.length; anchorIndex++) {
+ // If the current cert is a TrustAnchor, we can ignore the rest of the chain.
+ // This avoids including "bridge" CA certs that added for legacy compatibility.
+ TrustAnchor trustAnchor = findTrustAnchorBySubjectAndPublicKey(chain[anchorIndex]);
+ if (trustAnchor != null) {
+ trustAnchors.add(trustAnchor);
+ break;
+ }
+ }
+
+ // 3. If the chain is now shorter, copy to an appropriately sized array.
+ int chainLength = anchorIndex;
X509Certificate[] newChain = ((chainLength == chain.length)
? chain
: Arrays.copyOf(chain, chainLength));
- // 3. If no TrustAnchor was found in cleanup, look for one now
+ // 4. If we didn't find a trust anchor earlier, look for one now
if (trustAnchors.isEmpty()) {
- TrustAnchor trustAnchor = findTrustAnchorByIssuerAndSignature(newChain[chainLength-1]);
+ TrustAnchor trustAnchor = findTrustAnchorByIssuerAndSignature(newChain[anchorIndex-1]);
if (trustAnchor != null) {
trustAnchors.add(trustAnchor);
}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustedCertificateStore.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustedCertificateStore.java
index abb6e55..e7b1a7c 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustedCertificateStore.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustedCertificateStore.java
@@ -298,6 +298,14 @@ public final class TrustedCertificateStore {
}
/**
+ * Returns true to indicate that the certificate was added by the
+ * user, false otherwise.
+ */
+ public boolean isUserAddedCertificate(X509Certificate cert) {
+ return getCertificateFile(addedDir, cert).exists();
+ }
+
+ /**
* Returns a File for where the certificate is found if it exists
* or where it should be installed if it does not exist. The
* caller can disambiguate these cases by calling {@code
diff --git a/luni/src/main/native/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp b/luni/src/main/native/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp
index a04bebf..83f28d2 100644
--- a/luni/src/main/native/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp
+++ b/luni/src/main/native/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp
@@ -923,6 +923,26 @@ static void NativeCrypto_EVP_PKEY_free(JNIEnv*, jclass, EVP_PKEY* pkey) {
}
}
+static jint NativeCrypto_EVP_PKEY_cmp(JNIEnv* env, jclass, jint pkey1Ref, jint pkey2Ref) {
+ EVP_PKEY* pkey1 = reinterpret_cast<EVP_PKEY*>(pkey1Ref);
+ EVP_PKEY* pkey2 = reinterpret_cast<EVP_PKEY*>(pkey2Ref);
+ JNI_TRACE("EVP_PKEY_cmp(%p, %p)", pkey1, pkey2);
+
+ if (pkey1 == NULL) {
+ JNI_TRACE("EVP_PKEY_cmp(%p, %p) => failed pkey1 == NULL", pkey1, pkey2);
+ jniThrowNullPointerException(env, "pkey1 == NULL");
+ return -1;
+ } else if (pkey2 == NULL) {
+ JNI_TRACE("EVP_PKEY_cmp(%p, %p) => failed pkey2 == NULL", pkey1, pkey2);
+ jniThrowNullPointerException(env, "pkey2 == NULL");
+ return -1;
+ }
+
+ int result = EVP_PKEY_cmp(pkey1, pkey2);
+ JNI_TRACE("EVP_PKEY_cmp(%p, %p) => %d", pkey1, pkey2, result);
+ return result;
+}
+
/*
* static native byte[] i2d_PKCS8_PRIV_KEY_INFO(int, byte[])
*/
@@ -3735,7 +3755,7 @@ static jobjectArray NativeCrypto_SSL_get_peer_cert_chain(JNIEnv* env, jclass, ji
* cleanly shut down, or THROW_SSLEXCEPTION if an exception should be thrown.
*/
static int sslRead(JNIEnv* env, SSL* ssl, jobject fdObject, jobject shc, char* buf, jint len,
- int* sslReturnCode, int* sslErrorCode, int timeout_millis) {
+ int* sslReturnCode, int* sslErrorCode, int read_timeout_millis) {
JNI_TRACE("ssl=%p sslRead buf=%p len=%d", ssl, buf, len);
if (len == 0) {
@@ -3814,7 +3834,7 @@ static int sslRead(JNIEnv* env, SSL* ssl, jobject fdObject, jobject shc, char* b
// Need to wait for availability of underlying layer, then retry.
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE: {
- int selectResult = sslSelect(env, sslError, fdObject, appData, timeout_millis);
+ int selectResult = sslSelect(env, sslError, fdObject, appData, read_timeout_millis);
if (selectResult == THROWN_EXCEPTION) {
return THROWN_EXCEPTION;
}
@@ -3866,11 +3886,11 @@ static int sslRead(JNIEnv* env, SSL* ssl, jobject fdObject, jobject shc, char* b
*/
static jint NativeCrypto_SSL_read(JNIEnv* env, jclass, jint ssl_address, jobject fdObject,
jobject shc, jbyteArray b, jint offset, jint len,
- jint timeout_millis)
+ jint read_timeout_millis)
{
SSL* ssl = to_SSL(env, ssl_address, true);
- JNI_TRACE("ssl=%p NativeCrypto_SSL_read fd=%p shc=%p b=%p offset=%d len=%d timeout_millis=%d",
- ssl, fdObject, shc, b, offset, len, timeout_millis);
+ JNI_TRACE("ssl=%p NativeCrypto_SSL_read fd=%p shc=%p b=%p offset=%d len=%d read_timeout_millis=%d",
+ ssl, fdObject, shc, b, offset, len, read_timeout_millis);
if (ssl == NULL) {
return 0;
}
@@ -3894,7 +3914,7 @@ static jint NativeCrypto_SSL_read(JNIEnv* env, jclass, jint ssl_address, jobject
int sslErrorCode = SSL_ERROR_NONE;;
int ret = sslRead(env, ssl, fdObject, shc, reinterpret_cast<char*>(bytes.get() + offset), len,
- &returnCode, &sslErrorCode, timeout_millis);
+ &returnCode, &sslErrorCode, read_timeout_millis);
int result;
switch (ret) {
@@ -3934,7 +3954,7 @@ static jint NativeCrypto_SSL_read(JNIEnv* env, jclass, jint ssl_address, jobject
* cleanly shut down, or THROW_SSLEXCEPTION if an exception should be thrown.
*/
static int sslWrite(JNIEnv* env, SSL* ssl, jobject fdObject, jobject shc, const char* buf, jint len,
- int* sslReturnCode, int* sslErrorCode) {
+ int* sslReturnCode, int* sslErrorCode, int write_timeout_millis) {
JNI_TRACE("ssl=%p sslWrite buf=%p len=%d", ssl, buf, len);
if (len == 0) {
@@ -4020,7 +4040,7 @@ static int sslWrite(JNIEnv* env, SSL* ssl, jobject fdObject, jobject shc, const
// it's also not standard Java behavior, so we wait forever here.
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE: {
- int selectResult = sslSelect(env, sslError, fdObject, appData, 0);
+ int selectResult = sslSelect(env, sslError, fdObject, appData, write_timeout_millis);
if (selectResult == THROWN_EXCEPTION) {
return THROWN_EXCEPTION;
}
@@ -4071,7 +4091,7 @@ static int sslWrite(JNIEnv* env, SSL* ssl, jobject fdObject, jobject shc, const
* OpenSSL write function (2): write into buffer at offset n chunks.
*/
static void NativeCrypto_SSL_write(JNIEnv* env, jclass, jint ssl_address, jobject fdObject,
- jobject shc, jbyteArray b, jint offset, jint len)
+ jobject shc, jbyteArray b, jint offset, jint len, jint write_timeout_millis)
{
SSL* ssl = to_SSL(env, ssl_address, true);
JNI_TRACE("ssl=%p NativeCrypto_SSL_write fd=%p shc=%p b=%p offset=%d len=%d",
@@ -4098,7 +4118,7 @@ static void NativeCrypto_SSL_write(JNIEnv* env, jclass, jint ssl_address, jobjec
int returnCode = 0;
int sslErrorCode = SSL_ERROR_NONE;
int ret = sslWrite(env, ssl, fdObject, shc, reinterpret_cast<const char*>(bytes.get() + offset),
- len, &returnCode, &sslErrorCode);
+ len, &returnCode, &sslErrorCode, write_timeout_millis);
switch (ret) {
case THROW_SSLEXCEPTION:
@@ -4404,6 +4424,7 @@ static JNINativeMethod sNativeCryptoMethods[] = {
NATIVE_METHOD(NativeCrypto, EVP_PKEY_type, "(I)I"),
NATIVE_METHOD(NativeCrypto, EVP_PKEY_size, "(I)I"),
NATIVE_METHOD(NativeCrypto, EVP_PKEY_free, "(I)V"),
+ NATIVE_METHOD(NativeCrypto, EVP_PKEY_cmp, "(II)I"),
NATIVE_METHOD(NativeCrypto, i2d_PKCS8_PRIV_KEY_INFO, "(I)[B"),
NATIVE_METHOD(NativeCrypto, d2i_PKCS8_PRIV_KEY_INFO, "([B)I"),
NATIVE_METHOD(NativeCrypto, i2d_PUBKEY, "(I)[B"),
@@ -4466,7 +4487,7 @@ static JNINativeMethod sNativeCryptoMethods[] = {
NATIVE_METHOD(NativeCrypto, SSL_get_certificate, "(I)[[B"),
NATIVE_METHOD(NativeCrypto, SSL_get_peer_cert_chain, "(I)[[B"),
NATIVE_METHOD(NativeCrypto, SSL_read, "(I" FILE_DESCRIPTOR SSL_CALLBACKS "[BIII)I"),
- NATIVE_METHOD(NativeCrypto, SSL_write, "(I" FILE_DESCRIPTOR SSL_CALLBACKS "[BII)V"),
+ NATIVE_METHOD(NativeCrypto, SSL_write, "(I" FILE_DESCRIPTOR SSL_CALLBACKS "[BIII)V"),
NATIVE_METHOD(NativeCrypto, SSL_interrupt, "(I)V"),
NATIVE_METHOD(NativeCrypto, SSL_shutdown, "(I" FILE_DESCRIPTOR SSL_CALLBACKS ")V"),
NATIVE_METHOD(NativeCrypto, SSL_free, "(I)V"),
diff --git a/luni/src/main/native/zip.h b/luni/src/main/native/zip.h
index 0f3c0c1..303c940 100644
--- a/luni/src/main/native/zip.h
+++ b/luni/src/main/native/zip.h
@@ -23,7 +23,7 @@
#include "UniquePtr.h"
#include "jni.h"
#include "zlib.h"
-#include "zutil.h"
+#include "zutil.h" // For DEF_WBITS and DEF_MEM_LEVEL.
static void throwExceptionForZlibError(JNIEnv* env, const char* exceptionClassName, int error) {
if (error == Z_MEM_ERROR) {
diff --git a/luni/src/test/java/libcore/java/lang/OldObjectTest.java b/luni/src/test/java/libcore/java/lang/OldObjectTest.java
index 08471b2..3ab0327 100644
--- a/luni/src/test/java/libcore/java/lang/OldObjectTest.java
+++ b/luni/src/test/java/libcore/java/lang/OldObjectTest.java
@@ -16,8 +16,6 @@
*/
package libcore.java.lang;
-import dalvik.annotation.SideEffect;
-import java.util.Vector;
import junit.framework.TestCase;
public class OldObjectTest extends TestCase {
@@ -187,7 +185,36 @@ public class OldObjectTest extends TestCase {
fail("InterruptedException was thrown.");
}
assertEquals(3, status);
+ }
+
+ public void test_waitJI_invalid() throws Exception {
+ Object o = new Object();
+ synchronized (o) {
+ try {
+ o.wait(-1, 0);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+
+ try {
+ o.wait(0, -1);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ try {
+ o.wait(-1, -1);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+
+ // The ms timeout must fit in 32 bits.
+ try {
+ o.wait(Integer.MAX_VALUE + 1, 0);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
}
public void test_waitJ() {
diff --git a/luni/src/test/java/libcore/java/security/KeyStoreTest.java b/luni/src/test/java/libcore/java/security/KeyStoreTest.java
index 15314c9..ddee6ce 100644
--- a/luni/src/test/java/libcore/java/security/KeyStoreTest.java
+++ b/luni/src/test/java/libcore/java/security/KeyStoreTest.java
@@ -45,6 +45,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
+import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -65,10 +66,12 @@ public class KeyStoreTest extends TestCase {
private static final String ALIAS_SECRET = "secret";
private static final String ALIAS_ALT_CASE_PRIVATE = "pRiVaTe";
+ private static final String ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE = "PrIvAtE-no-password";
private static final String ALIAS_ALT_CASE_CERTIFICATE = "cErTiFiCaTe";
private static final String ALIAS_ALT_CASE_SECRET = "sEcRet";
private static final String ALIAS_UNICODE_PRIVATE = "\u6400\u7902\u3101\u8c02\u5002\u8702\udd01";
+ private static final String ALIAS_UNICODE_NO_PASSWORD_PRIVATE = "\u926c\u0967\uc65b\ubc78";
private static final String ALIAS_UNICODE_CERTIFICATE = "\u5402\udd01\u7902\u8702\u3101\u5f02\u3101\u5402\u5002\u8702\udd01";
private static final String ALIAS_UNICODE_SECRET = "\ue224\ud424\ud224\ue124\ud424\ue324";
@@ -146,7 +149,8 @@ public class KeyStoreTest extends TestCase {
// JKS key stores cannot store secret keys, neither can the RI's PKCS12
return (!(ks.getType().equals("JKS")
|| ks.getType().equals("CaseExactJKS")
- || (ks.getType().equals("PKCS12"))));
+ || (ks.getType().equals("PKCS12"))
+ || (ks.getType().equals("AndroidKeyStore"))));
}
private static boolean isCertificateEnabled(KeyStore ks) {
@@ -157,13 +161,16 @@ public class KeyStoreTest extends TestCase {
private static boolean isCaseSensitive(KeyStore ks) {
return (ks.getType().equals("CaseExactJKS")
|| ks.getType().equals("BKS")
- || ks.getType().equals("BouncyCastle"));
+ || ks.getType().equals("BouncyCastle")
+ || ks.getType().equals("AndroidKeyStore"));
}
private static boolean isUnsupported(KeyStore ks) {
// Don't bother testing BC on RI
- return (StandardNames.IS_RI && ks.getProvider().getName().equals("BC"));
+ // TODO enable AndroidKeyStore when CTS can set up the keystore
+ return (StandardNames.IS_RI && ks.getProvider().getName().equals("BC"))
+ || "AndroidKeyStore".equalsIgnoreCase(ks.getType());
}
private static boolean isNullPasswordAllowed(KeyStore ks) {
@@ -172,7 +179,9 @@ public class KeyStoreTest extends TestCase {
|| ks.getType().equals("JCEKS")
|| ks.getType().equals("PKCS12")));
}
-
+ private static boolean isKeyPasswordSupported(KeyStore ks) {
+ return !ks.getType().equals("AndroidKeyStore");
+ }
private static boolean isKeyPasswordIgnored(KeyStore ks) {
// BouncyCastle's PKCS12 ignores the key password unlike the RI which requires it
return (ks.getType().equals("PKCS12") && ks.getProvider().getName().equals("BC"));
@@ -183,6 +192,14 @@ public class KeyStoreTest extends TestCase {
return (ks.getType().equals("PKCS12") && ks.getProvider().getName().equals("BC"));
}
+ private static boolean isPersistentStorage(KeyStore ks) {
+ return ks.getType().equalsIgnoreCase("AndroidKeyStore");
+ }
+
+ private static boolean isLoadStoreUnsupported(KeyStore ks) {
+ return ks.getType().equalsIgnoreCase("AndroidKeyStore");
+ }
+
private static boolean isSetKeyByteArrayUnimplemented(KeyStore ks) {
// All of BouncyCastle's
// KeyStore.setKeyEntry(String,byte[],char[]) implementations
@@ -203,16 +220,13 @@ public class KeyStoreTest extends TestCase {
}
public static void populate(KeyStore ks) throws Exception {
- ks.load(null, null);
- if (isReadOnly(ks)) {
- try {
- setPrivateKey(ks);
- fail(ks.toString());
- } catch (UnsupportedOperationException e) {
- }
+ boolean readOnly = clearKeyStore(ks);
+ if (readOnly) {
return;
}
- setPrivateKey(ks);
+ if (isKeyPasswordSupported(ks)) {
+ setPrivateKey(ks);
+ }
if (isNullPasswordAllowed(ks)) {
ks.setKeyEntry(ALIAS_NO_PASSWORD_PRIVATE,
getPrivateKey().getPrivateKey(),
@@ -234,6 +248,30 @@ public class KeyStoreTest extends TestCase {
}
}
+ private static boolean clearKeyStore(KeyStore ks) throws Exception {
+ ks.load(null, null);
+ if (isReadOnly(ks)) {
+ try {
+ setPrivateKey(ks);
+ fail(ks.toString());
+ } catch (UnsupportedOperationException e) {
+ }
+ return true;
+ }
+ if (isPersistentStorage(ks)) {
+ Enumeration<String> aliases = ks.aliases();
+ while (aliases.hasMoreElements()) {
+ String alias = aliases.nextElement();
+ ks.deleteEntry(alias);
+ }
+ }
+ return false;
+ }
+
+ public static void setPrivateKeyNoPassword(KeyStore ks, String alias, PrivateKeyEntry privateKey)
+ throws Exception {
+ ks.setKeyEntry(alias, privateKey.getPrivateKey(), null, privateKey.getCertificateChain());
+ }
public static void setPrivateKey(KeyStore ks) throws Exception {
setPrivateKey(ks, ALIAS_PRIVATE);
}
@@ -492,7 +530,12 @@ public class KeyStoreTest extends TestCase {
if (isReadOnly(keyStore)) {
assertNull(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
} else {
- assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ if (isKeyPasswordSupported(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ }
+ if (isNullPasswordAllowed(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ }
if (isSecretKeyEnabled(keyStore)) {
assertSecretKey(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
} else {
@@ -503,21 +546,27 @@ public class KeyStoreTest extends TestCase {
// test case insensitive
if (isCaseSensitive(keyStore) || isReadOnly(keyStore)) {
assertNull(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ assertNull(keyStore.getKey(ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE, PASSWORD_KEY));
assertNull(keyStore.getKey(ALIAS_ALT_CASE_SECRET, PASSWORD_KEY));
} else {
- assertPrivateKey(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ if (isKeyPasswordSupported(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ }
+ if (isNullPasswordAllowed(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE, null));
+ }
if (isSecretKeyEnabled(keyStore)) {
assertSecretKey(keyStore.getKey(ALIAS_ALT_CASE_SECRET, PASSWORD_KEY));
}
}
// test with null passwords
- if (isKeyPasswordIgnored(keyStore)) {
+ if (isKeyPasswordSupported(keyStore) && isKeyPasswordIgnored(keyStore)) {
assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, null));
} else {
if (isReadOnly(keyStore)) {
assertNull(keyStore.getKey(ALIAS_PRIVATE, null));
- } else {
+ } else if (isKeyPasswordSupported(keyStore)) {
try {
keyStore.getKey(ALIAS_PRIVATE, null);
fail(keyStore.getType());
@@ -546,9 +595,9 @@ public class KeyStoreTest extends TestCase {
// test with bad passwords
if (isReadOnly(keyStore)) {
assertNull(keyStore.getKey(ALIAS_PRIVATE, null));
- } else if (isKeyPasswordIgnored(keyStore)) {
+ } else if (isKeyPasswordSupported(keyStore) && isKeyPasswordIgnored(keyStore)) {
assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, null));
- } else {
+ } else if (isKeyPasswordSupported(keyStore)) {
try {
keyStore.getKey(ALIAS_PRIVATE, PASSWORD_BAD);
fail(keyStore.getType());
@@ -593,8 +642,10 @@ public class KeyStoreTest extends TestCase {
// test case sensitive
if (isReadOnly(keyStore)) {
assertNull(keyStore.getCertificateChain(ALIAS_PRIVATE));
- } else {
+ } else if (isKeyPasswordSupported(keyStore)) {
assertCertificateChain(keyStore.getCertificateChain(ALIAS_PRIVATE));
+ } else if (isNullPasswordAllowed(keyStore)) {
+ assertCertificateChain(keyStore.getCertificateChain(ALIAS_NO_PASSWORD_PRIVATE));
}
// test case insensitive
@@ -657,9 +708,10 @@ public class KeyStoreTest extends TestCase {
}
long before = System.currentTimeMillis();
for (KeyStore keyStore : keyStores()) {
+ populate(keyStore);
+
// add 1000 since some key stores round of time to nearest second
long after = System.currentTimeMillis() + 1000;
- populate(keyStore);
// test odd inputs
try {
@@ -673,8 +725,10 @@ public class KeyStoreTest extends TestCase {
if (!isReadOnly(keyStore) && isCertificateEnabled(keyStore)) {
Date date = keyStore.getCreationDate(ALIAS_CERTIFICATE);
assertNotNull(date);
- assertTrue(before <= date.getTime());
- assertTrue(date.getTime() <= after);
+ assertTrue("date should be after start time: " + date.getTime() + " >= " + before,
+ before <= date.getTime());
+ assertTrue("date should be before expiry time: " + date.getTime() + " <= " + after,
+ date.getTime() <= after);
} else {
assertNull(keyStore.getCreationDate(ALIAS_CERTIFICATE));
}
@@ -737,15 +791,24 @@ public class KeyStoreTest extends TestCase {
PASSWORD_KEY,
null);
fail(keyStore.getType());
- } catch (IllegalArgumentException expected) {
+ } catch (Exception e) {
+ if (e.getClass() != IllegalArgumentException.class
+ && e.getClass() != KeyStoreException.class) {
+ throw e;
+ }
}
}
for (KeyStore keyStore : keyStores()) {
- keyStore.load(null, null);
+ clearKeyStore(keyStore);
// test case sensitive
- assertNull(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ if (isKeyPasswordSupported(keyStore)) {
+ assertNull(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ }
+ if (isNullPasswordAllowed(keyStore)) {
+ assertNull(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ }
if (isReadOnly(keyStore)) {
try {
keyStore.setKeyEntry(ALIAS_SECRET, getSecretKey(), PASSWORD_KEY, null);
@@ -754,9 +817,16 @@ public class KeyStoreTest extends TestCase {
}
continue;
}
- setPrivateKey(keyStore);
- assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
- assertCertificateChain(keyStore.getCertificateChain(ALIAS_PRIVATE));
+ if (isKeyPasswordSupported(keyStore)) {
+ setPrivateKey(keyStore);
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertCertificateChain(keyStore.getCertificateChain(ALIAS_PRIVATE));
+ }
+ if (isNullPasswordAllowed(keyStore)) {
+ setPrivateKeyNoPassword(keyStore, ALIAS_NO_PASSWORD_PRIVATE, getPrivateKey());
+ assertPrivateKey(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ assertCertificateChain(keyStore.getCertificateChain(ALIAS_NO_PASSWORD_PRIVATE));
+ }
if (isSecretKeyEnabled(keyStore)) {
assertNull(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
setSecretKey(keyStore);
@@ -783,11 +853,22 @@ public class KeyStoreTest extends TestCase {
assertNull(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
assertNull(keyStore.getKey(ALIAS_ALT_CASE_SECRET, PASSWORD_KEY));
} else if (isCaseSensitive(keyStore)) {
- assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
- assertNull(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
- setPrivateKey(keyStore, ALIAS_ALT_CASE_PRIVATE, getPrivateKey2());
- assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
- assertPrivateKey2(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ if (isKeyPasswordSupported(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertNull(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ setPrivateKey(keyStore, ALIAS_ALT_CASE_PRIVATE, getPrivateKey2());
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertPrivateKey2(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ }
+
+ if (isNullPasswordAllowed(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ assertNull(keyStore.getKey(ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE, null));
+ setPrivateKeyNoPassword(keyStore, ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE,
+ getPrivateKey2());
+ assertPrivateKey(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ assertPrivateKey2(keyStore.getKey(ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE, null));
+ }
if (isSecretKeyEnabled(keyStore)) {
assertSecretKey(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
@@ -797,11 +878,22 @@ public class KeyStoreTest extends TestCase {
assertSecretKey2(keyStore.getKey(ALIAS_ALT_CASE_SECRET, PASSWORD_KEY));
}
} else {
- assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
- assertPrivateKey(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
- setPrivateKey(keyStore, ALIAS_ALT_CASE_PRIVATE, getPrivateKey2());
- assertPrivateKey2(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
- assertPrivateKey2(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ if (isKeyPasswordSupported(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertPrivateKey(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ setPrivateKey(keyStore, ALIAS_ALT_CASE_PRIVATE, getPrivateKey2());
+ assertPrivateKey2(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertPrivateKey2(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ }
+
+ if (isNullPasswordAllowed(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, null));
+ assertPrivateKey(keyStore.getKey(ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE, null));
+ setPrivateKey(keyStore, ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE, getPrivateKey2());
+ assertPrivateKey2(keyStore.getKey(ALIAS_PRIVATE, null));
+ assertPrivateKey2(keyStore.getKey(ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE, null));
+ }
+
if (isSecretKeyEnabled(keyStore)) {
assertSecretKey(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
assertSecretKey(keyStore.getKey(ALIAS_ALT_CASE_SECRET, PASSWORD_KEY));
@@ -913,10 +1005,15 @@ public class KeyStoreTest extends TestCase {
continue;
}
- keyStore.load(null, null);
+ clearKeyStore(keyStore);
// test case sensitive
- assertNull(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ if (isKeyPasswordSupported(keyStore)) {
+ assertNull(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ }
+ if (isNullPasswordAllowed(keyStore)) {
+ assertNull(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ }
if (isReadOnly(keyStore)) {
try {
setPrivateKeyBytes(keyStore);
@@ -925,9 +1022,16 @@ public class KeyStoreTest extends TestCase {
}
continue;
}
- setPrivateKeyBytes(keyStore);
- assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
- assertCertificateChain(keyStore.getCertificateChain(ALIAS_PRIVATE));
+ if (isKeyPasswordSupported(keyStore)) {
+ setPrivateKeyBytes(keyStore);
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertCertificateChain(keyStore.getCertificateChain(ALIAS_PRIVATE));
+ }
+ if (isNullPasswordAllowed(keyStore)) {
+ setPrivateKeyNoPassword(keyStore, ALIAS_NO_PASSWORD_PRIVATE, getPrivateKey());
+ assertPrivateKey(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ assertCertificateChain(keyStore.getCertificateChain(ALIAS_NO_PASSWORD_PRIVATE));
+ }
if (isSecretKeyEnabled(keyStore)) {
assertNull(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
setSecretKeyBytes(keyStore);
@@ -959,11 +1063,21 @@ public class KeyStoreTest extends TestCase {
assertNull(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
assertNull(keyStore.getKey(ALIAS_ALT_CASE_SECRET, PASSWORD_KEY));
} else if (isCaseSensitive(keyStore)) {
- assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
- assertNull(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
- setPrivateKeyBytes(keyStore, ALIAS_ALT_CASE_PRIVATE, getPrivateKey2());
- assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
- assertPrivateKey2(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ if (isKeyPasswordSupported(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertNull(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ setPrivateKeyBytes(keyStore, ALIAS_ALT_CASE_PRIVATE, getPrivateKey2());
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertPrivateKey2(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ }
+ if (isNullPasswordAllowed(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ assertNull(keyStore.getKey(ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE, null));
+ setPrivateKeyNoPassword(keyStore, ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE,
+ getPrivateKey2());
+ assertPrivateKey(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ assertPrivateKey2(keyStore.getKey(ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE, null));
+ }
if (isSecretKeyEnabled(keyStore)) {
assertSecretKey(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
@@ -973,11 +1087,21 @@ public class KeyStoreTest extends TestCase {
assertSecretKey2(keyStore.getKey(ALIAS_ALT_CASE_SECRET, PASSWORD_KEY));
}
} else {
- assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
- assertPrivateKey(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
- setPrivateKeyBytes(keyStore, ALIAS_ALT_CASE_PRIVATE, getPrivateKey2());
- assertPrivateKey2(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
- assertPrivateKey2(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ if (isKeyPasswordSupported(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertPrivateKey(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ setPrivateKeyBytes(keyStore, ALIAS_ALT_CASE_PRIVATE, getPrivateKey2());
+ assertPrivateKey2(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertPrivateKey2(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ }
+ if (isNullPasswordAllowed(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ assertPrivateKey(keyStore.getKey(ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE, null));
+ setPrivateKeyNoPassword(keyStore, ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE,
+ getPrivateKey2());
+ assertPrivateKey2(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ assertPrivateKey2(keyStore.getKey(ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE, null));
+ }
if (isSecretKeyEnabled(keyStore)) {
assertSecretKey(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
@@ -1031,13 +1155,17 @@ public class KeyStoreTest extends TestCase {
try {
int size = keyStore.size();
keyStore.setCertificateEntry(ALIAS_CERTIFICATE, null);
- assertNull(keyStore.getCertificate(ALIAS_CERTIFICATE));
- assertEquals(size, keyStore.size());
- assertTrue(keyStore.isCertificateEntry(ALIAS_CERTIFICATE));
- assertTrue(Collections.list(keyStore.aliases()).contains(ALIAS_CERTIFICATE));
+ assertNull(keyStore.getType(), keyStore.getCertificate(ALIAS_CERTIFICATE));
+ assertEquals(keyStore.getType(), size, keyStore.size());
+ assertTrue(keyStore.getType(), keyStore.isCertificateEntry(ALIAS_CERTIFICATE));
+ assertTrue(keyStore.getType(),
+ Collections.list(keyStore.aliases()).contains(ALIAS_CERTIFICATE));
} catch (NullPointerException expectedSometimes) {
- assertEquals("PKCS12", keyStore.getType());
- assertEquals("BC", keyStore.getProvider().getName());
+ if (!("PKCS12".equalsIgnoreCase(keyStore.getType()) &&
+ "BC".equalsIgnoreCase(keyStore.getProvider().getName()))
+ && !"AndroidKeyStore".equalsIgnoreCase(keyStore.getType())) {
+ throw expectedSometimes;
+ }
}
} else {
try {
@@ -1053,9 +1181,8 @@ public class KeyStoreTest extends TestCase {
continue;
}
- keyStore.load(null, null);
+ clearKeyStore(keyStore);
- // test case sensitive
assertNull(keyStore.getCertificate(ALIAS_CERTIFICATE));
if (isReadOnly(keyStore)) {
try {
@@ -1077,10 +1204,8 @@ public class KeyStoreTest extends TestCase {
populate(keyStore);
if (isReadOnly(keyStore)) {
- assertNull(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
- assertNull(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
- assertNull(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
- assertNull(keyStore.getKey(ALIAS_ALT_CASE_SECRET, PASSWORD_KEY));
+ assertNull(keyStore.getCertificate(ALIAS_CERTIFICATE));
+ assertNull(keyStore.getCertificate(ALIAS_ALT_CASE_CERTIFICATE));
} else if (isCaseSensitive(keyStore)) {
assertCertificate(keyStore.getCertificate(ALIAS_CERTIFICATE));
assertNull(keyStore.getCertificate(ALIAS_ALT_CASE_CERTIFICATE));
@@ -1146,10 +1271,18 @@ public class KeyStoreTest extends TestCase {
}
// test case sensitive
- assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
- assertCertificateChain(keyStore.getCertificateChain(ALIAS_PRIVATE));
- keyStore.deleteEntry(ALIAS_PRIVATE);
- assertNull(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ if (isKeyPasswordSupported(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertCertificateChain(keyStore.getCertificateChain(ALIAS_PRIVATE));
+ keyStore.deleteEntry(ALIAS_PRIVATE);
+ assertNull(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ }
+ if (isNullPasswordAllowed(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ assertCertificateChain(keyStore.getCertificateChain(ALIAS_NO_PASSWORD_PRIVATE));
+ keyStore.deleteEntry(ALIAS_NO_PASSWORD_PRIVATE);
+ assertNull(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ }
if (isSecretKeyEnabled(keyStore)) {
assertSecretKey(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
@@ -1174,9 +1307,16 @@ public class KeyStoreTest extends TestCase {
// test case insensitive
if (isCaseSensitive(keyStore)) {
- assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
- keyStore.deleteEntry(ALIAS_ALT_CASE_PRIVATE);
- assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ if (isKeyPasswordSupported(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ keyStore.deleteEntry(ALIAS_ALT_CASE_PRIVATE);
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ }
+ if (isNullPasswordAllowed(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ keyStore.deleteEntry(ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE);
+ assertPrivateKey(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ }
if (isSecretKeyEnabled(keyStore)) {
assertSecretKey(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
@@ -1208,10 +1348,14 @@ public class KeyStoreTest extends TestCase {
for (KeyStore keyStore : keyStores()) {
keyStore.load(null, null);
- if (hasDefaultContents(keyStore)) {
- assertTrue(keyStore.aliases().hasMoreElements());
+ if (isPersistentStorage(keyStore)) {
+ assertNotNull("Should be able to query size: " + keyStore.getType(),
+ keyStore.aliases());
+ } else if (hasDefaultContents(keyStore)) {
+ assertTrue("Should have more than one alias already: " + keyStore.getType(),
+ keyStore.aliases().hasMoreElements());
} else {
- assertEquals(Collections.EMPTY_SET,
+ assertEquals("Should have no aliases:" + keyStore.getType(), Collections.EMPTY_SET,
new HashSet(Collections.list(keyStore.aliases())));
}
}
@@ -1220,7 +1364,9 @@ public class KeyStoreTest extends TestCase {
populate(keyStore);
Set<String> expected = new HashSet<String>();
- expected.add(ALIAS_PRIVATE);
+ if (isKeyPasswordSupported(keyStore)) {
+ expected.add(ALIAS_PRIVATE);
+ }
if (isNullPasswordAllowed(keyStore)) {
expected.add(ALIAS_NO_PASSWORD_PRIVATE);
}
@@ -1233,7 +1379,10 @@ public class KeyStoreTest extends TestCase {
if (isCertificateEnabled(keyStore)) {
expected.add(ALIAS_CERTIFICATE);
}
- if (hasDefaultContents(keyStore)) {
+ if (isPersistentStorage(keyStore)) {
+ assertNotNull("Should be able to query size: " + keyStore.getType(),
+ keyStore.aliases());
+ } else if (hasDefaultContents(keyStore)) {
assertTrue(keyStore.aliases().hasMoreElements());
} else {
assertEquals(expected, new HashSet<String>(Collections.list(keyStore.aliases())));
@@ -1271,7 +1420,11 @@ public class KeyStoreTest extends TestCase {
assertFalse(keyStore.containsAlias(ALIAS_PRIVATE));
continue;
}
- assertTrue(keyStore.containsAlias(ALIAS_PRIVATE));
+ if (isKeyPasswordSupported(keyStore)) {
+ assertTrue(keyStore.containsAlias(ALIAS_PRIVATE));
+ } else if (isNullPasswordAllowed(keyStore)) {
+ assertTrue(keyStore.containsAlias(ALIAS_NO_PASSWORD_PRIVATE));
+ }
assertEquals(isSecretKeyEnabled(keyStore), keyStore.containsAlias(ALIAS_SECRET));
assertEquals(isCertificateEnabled(keyStore), keyStore.containsAlias(ALIAS_CERTIFICATE));
@@ -1295,21 +1448,29 @@ public class KeyStoreTest extends TestCase {
for (KeyStore keyStore : keyStores()) {
keyStore.load(null, null);
- if (hasDefaultContents(keyStore)) {
- assertTrue(keyStore.size() > 0);
+ if (isPersistentStorage(keyStore)) {
+ assertTrue("Should successfully query size: " + keyStore.getType(),
+ keyStore.size() >= 0);
+ } else if (hasDefaultContents(keyStore)) {
+ assertTrue("Should have non-empty store: " + keyStore.getType(),
+ keyStore.size() > 0);
} else {
- assertEquals(0, keyStore.size());
+ assertEquals("Should have empty store: " + keyStore.getType(), 0, keyStore.size());
}
}
for (KeyStore keyStore : keyStores()) {
populate(keyStore);
if (hasDefaultContents(keyStore)) {
- assertTrue(keyStore.size() > 0);
+ assertTrue("Should have non-empty store: " + keyStore.getType(),
+ keyStore.size() > 0);
continue;
}
- int expected = 1;
+ int expected = 0;
+ if (isKeyPasswordSupported(keyStore)) {
+ expected++;
+ }
if (isNullPasswordAllowed(keyStore)) {
expected++;
}
@@ -1355,7 +1516,12 @@ public class KeyStoreTest extends TestCase {
assertFalse(keyStore.isKeyEntry(ALIAS_PRIVATE));
continue;
}
- assertTrue(keyStore.isKeyEntry(ALIAS_PRIVATE));
+ if (isKeyPasswordSupported(keyStore)) {
+ assertTrue(keyStore.isKeyEntry(ALIAS_PRIVATE));
+ }
+ if (isNullPasswordAllowed(keyStore)) {
+ assertTrue(keyStore.isKeyEntry(ALIAS_NO_PASSWORD_PRIVATE));
+ }
assertEquals(isSecretKeyEnabled(keyStore), keyStore.isKeyEntry(ALIAS_SECRET));
assertFalse(keyStore.isKeyEntry(ALIAS_CERTIFICATE));
@@ -1397,7 +1563,12 @@ public class KeyStoreTest extends TestCase {
assertFalse(keyStore.isCertificateEntry(""));
- assertFalse(keyStore.isCertificateEntry(ALIAS_PRIVATE));
+ if (isKeyPasswordSupported(keyStore)) {
+ assertFalse(keyStore.isCertificateEntry(ALIAS_PRIVATE));
+ }
+ if (isNullPasswordAllowed(keyStore)) {
+ assertFalse(keyStore.isCertificateEntry(ALIAS_NO_PASSWORD_PRIVATE));
+ }
assertFalse(keyStore.isCertificateEntry(ALIAS_SECRET));
assertEquals(isCertificateEnabled(keyStore) && !isReadOnly(keyStore),
keyStore.isCertificateEntry(ALIAS_CERTIFICATE));
@@ -1429,7 +1600,9 @@ public class KeyStoreTest extends TestCase {
populate(keyStore);
Set<String> expected = new HashSet<String>();
- expected.add(ALIAS_PRIVATE);
+ if (isKeyPasswordSupported(keyStore)) {
+ expected.add(ALIAS_PRIVATE);
+ }
if (isNullPasswordAllowed(keyStore)) {
expected.add(ALIAS_NO_PASSWORD_PRIVATE);
}
@@ -1487,7 +1660,7 @@ public class KeyStoreTest extends TestCase {
for (KeyStore keyStore : keyStores()) {
keyStore.load(null, null);
ByteArrayOutputStream out = new ByteArrayOutputStream();
- if (isReadOnly(keyStore)) {
+ if (isLoadStoreUnsupported(keyStore) || isReadOnly(keyStore)) {
try {
keyStore.store(out, null);
fail(keyStore.getType());
@@ -1517,11 +1690,11 @@ public class KeyStoreTest extends TestCase {
populate(keyStore);
ByteArrayOutputStream out = new ByteArrayOutputStream();
- if (isReadOnly(keyStore)) {
+ if (isLoadStoreUnsupported(keyStore) || isReadOnly(keyStore)) {
try {
keyStore.store(out, null);
fail(keyStore.getType());
- } catch (UnsupportedOperationException e) {
+ } catch (UnsupportedOperationException expected) {
}
} else if (isNullPasswordAllowed(keyStore)) {
keyStore.store(out, null);
@@ -1542,7 +1715,7 @@ public class KeyStoreTest extends TestCase {
for (KeyStore keyStore : keyStores()) {
keyStore.load(null, null);
ByteArrayOutputStream out = new ByteArrayOutputStream();
- if (isReadOnly(keyStore)) {
+ if (isLoadStoreUnsupported(keyStore) || isReadOnly(keyStore)) {
try {
keyStore.store(out, PASSWORD_STORE);
fail(keyStore.getType());
@@ -1557,7 +1730,7 @@ public class KeyStoreTest extends TestCase {
for (KeyStore keyStore : keyStores()) {
populate(keyStore);
ByteArrayOutputStream out = new ByteArrayOutputStream();
- if (isReadOnly(keyStore)) {
+ if (isLoadStoreUnsupported(keyStore) || isReadOnly(keyStore)) {
try {
keyStore.store(out, PASSWORD_STORE);
fail(keyStore.getType());
@@ -1596,19 +1769,30 @@ public class KeyStoreTest extends TestCase {
public void test_KeyStore_load_InputStream() throws Exception {
for (KeyStore keyStore : keyStores()) {
keyStore.load(null, null);
- if (hasDefaultContents(keyStore)) {
- assertTrue(keyStore.size() > 0);
+ if (isPersistentStorage(keyStore)) {
+ assertTrue("Should be able to query size: " + keyStore.getType(),
+ keyStore.size() >= 0);
+ } else if (hasDefaultContents(keyStore)) {
+ assertTrue("Should have non-empty store: " + keyStore.getType(),
+ keyStore.size() > 0);
} else {
- assertEquals(0, keyStore.size());
+ assertEquals("Should have empty store: " + keyStore.getType(), 0, keyStore.size());
}
}
for (KeyStore keyStore : keyStores()) {
+ if (isLoadStoreUnsupported(keyStore)) {
+ continue;
+ }
keyStore.load(null, PASSWORD_STORE);
- if (hasDefaultContents(keyStore)) {
- assertTrue(keyStore.size() > 0);
+ if (isPersistentStorage(keyStore)) {
+ assertTrue("Should be able to query size: " + keyStore.getType(),
+ keyStore.size() >= 0);
+ } else if (hasDefaultContents(keyStore)) {
+ assertTrue("Should have non-empty store: " + keyStore.getType(),
+ keyStore.size() > 0);
} else {
- assertEquals(0, keyStore.size());
+ assertEquals("Should have empty store: " + keyStore.getType(), 0, keyStore.size());
}
}
@@ -1618,10 +1802,14 @@ public class KeyStoreTest extends TestCase {
public void test_KeyStore_load_LoadStoreParameter() throws Exception {
for (KeyStore keyStore : keyStores()) {
keyStore.load(null);
- if (hasDefaultContents(keyStore)) {
- assertTrue(keyStore.size() > 0);
+ if (isPersistentStorage(keyStore)) {
+ assertTrue("Should be able to query size: " + keyStore.getType(),
+ keyStore.size() >= 0);
+ } else if (hasDefaultContents(keyStore)) {
+ assertTrue("Should have non-empty store: " + keyStore.getType(),
+ keyStore.size() > 0);
} else {
- assertEquals(0, keyStore.size());
+ assertEquals("Should have empty store: " + keyStore.getType(), 0, keyStore.size());
}
}
@@ -1668,7 +1856,11 @@ public class KeyStoreTest extends TestCase {
if (isReadOnly(keyStore)) {
assertNull(keyStore.getEntry(ALIAS_PRIVATE, PARAM_KEY));
} else {
- assertPrivateKey(keyStore.getEntry(ALIAS_PRIVATE, PARAM_KEY));
+ if (isKeyPasswordSupported(keyStore)) {
+ assertPrivateKey(keyStore.getEntry(ALIAS_PRIVATE, PARAM_KEY));
+ } else if (isNullPasswordAllowed(keyStore)) {
+ assertPrivateKey(keyStore.getEntry(ALIAS_NO_PASSWORD_PRIVATE, null));
+ }
if (isSecretKeyEnabled(keyStore)) {
assertSecretKey(keyStore.getEntry(ALIAS_SECRET, PARAM_KEY));
} else {
@@ -1704,9 +1896,9 @@ public class KeyStoreTest extends TestCase {
assertNull(keyStore.getEntry(ALIAS_NO_PASSWORD_PRIVATE, null));
} else if (isNullPasswordAllowed(keyStore)) {
assertPrivateKey(keyStore.getEntry(ALIAS_NO_PASSWORD_PRIVATE, null));
- } else if (isKeyPasswordIgnored(keyStore)) {
+ } else if (isKeyPasswordSupported(keyStore) && isKeyPasswordIgnored(keyStore)) {
assertPrivateKey(keyStore.getEntry(ALIAS_PRIVATE, null));
- } else {
+ } else if (isKeyPasswordIgnored(keyStore)) {
try {
keyStore.getEntry(ALIAS_PRIVATE, null);
fail(keyStore.getType());
@@ -1734,9 +1926,9 @@ public class KeyStoreTest extends TestCase {
// test with bad passwords
if (isReadOnly(keyStore)) {
assertNull(keyStore.getEntry(ALIAS_PRIVATE, PARAM_BAD));
- } else if (isKeyPasswordIgnored(keyStore)) {
+ } else if (isKeyPasswordSupported(keyStore) && isKeyPasswordIgnored(keyStore)) {
assertPrivateKey(keyStore.getEntry(ALIAS_PRIVATE, PARAM_BAD));
- } else {
+ } else if (isKeyPasswordSupported(keyStore)) {
try {
keyStore.getEntry(ALIAS_PRIVATE, PARAM_BAD);
fail(keyStore.getType());
@@ -1773,7 +1965,7 @@ public class KeyStoreTest extends TestCase {
try {
keyStore.setEntry(ALIAS_PRIVATE, getPrivateKey(), new FakeProtectionParameter());
- fail("Should not accept unknown ProtectionParameter");
+ fail("Should not accept unknown ProtectionParameter: " + keyStore.getProvider());
} catch (KeyStoreException expected) {
}
}
@@ -1808,7 +2000,7 @@ public class KeyStoreTest extends TestCase {
}
for (KeyStore keyStore : keyStores()) {
- keyStore.load(null, null);
+ clearKeyStore(keyStore);
// test case sensitive
assertNull(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
@@ -1820,9 +2012,16 @@ public class KeyStoreTest extends TestCase {
}
continue;
}
- keyStore.setEntry(ALIAS_PRIVATE, getPrivateKey(), PARAM_KEY);
- assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
- assertCertificateChain(keyStore.getCertificateChain(ALIAS_PRIVATE));
+ if (isKeyPasswordSupported(keyStore)) {
+ keyStore.setEntry(ALIAS_PRIVATE, getPrivateKey(), PARAM_KEY);
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertCertificateChain(keyStore.getCertificateChain(ALIAS_PRIVATE));
+ }
+ if (isNullPasswordAllowed(keyStore)) {
+ keyStore.setEntry(ALIAS_NO_PASSWORD_PRIVATE, getPrivateKey(), null);
+ assertPrivateKey(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ assertCertificateChain(keyStore.getCertificateChain(ALIAS_NO_PASSWORD_PRIVATE));
+ }
if (isSecretKeyEnabled(keyStore)) {
assertNull(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
keyStore.setEntry(ALIAS_SECRET, new SecretKeyEntry(getSecretKey()), PARAM_KEY);
@@ -1849,9 +2048,17 @@ public class KeyStoreTest extends TestCase {
} catch (KeyStoreException expected) {
}
}
- keyStore.setEntry(ALIAS_UNICODE_PRIVATE, getPrivateKey(), PARAM_KEY);
- assertPrivateKey(keyStore.getKey(ALIAS_UNICODE_PRIVATE, PASSWORD_KEY));
- assertCertificateChain(keyStore.getCertificateChain(ALIAS_UNICODE_PRIVATE));
+ if (isKeyPasswordSupported(keyStore)) {
+ keyStore.setEntry(ALIAS_UNICODE_PRIVATE, getPrivateKey(), PARAM_KEY);
+ assertPrivateKey(keyStore.getKey(ALIAS_UNICODE_PRIVATE, PASSWORD_KEY));
+ assertCertificateChain(keyStore.getCertificateChain(ALIAS_UNICODE_PRIVATE));
+ }
+ if (isNullPasswordAllowed(keyStore)) {
+ keyStore.setEntry(ALIAS_UNICODE_NO_PASSWORD_PRIVATE, getPrivateKey(), null);
+ assertPrivateKey(keyStore.getKey(ALIAS_UNICODE_NO_PASSWORD_PRIVATE, null));
+ assertCertificateChain(keyStore
+ .getCertificateChain(ALIAS_UNICODE_NO_PASSWORD_PRIVATE));
+ }
if (isSecretKeyEnabled(keyStore)) {
assertNull(keyStore.getKey(ALIAS_UNICODE_SECRET, PASSWORD_KEY));
keyStore.setEntry(ALIAS_UNICODE_SECRET, new SecretKeyEntry(getSecretKey()), PARAM_KEY);
@@ -1874,11 +2081,21 @@ public class KeyStoreTest extends TestCase {
assertNull(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
assertNull(keyStore.getKey(ALIAS_ALT_CASE_SECRET, PASSWORD_KEY));
} else if (isCaseSensitive(keyStore)) {
- assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
- assertNull(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
- keyStore.setEntry(ALIAS_ALT_CASE_PRIVATE, getPrivateKey2(), PARAM_KEY);
- assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
- assertPrivateKey2(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ if (isKeyPasswordSupported(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertNull(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ keyStore.setEntry(ALIAS_ALT_CASE_PRIVATE, getPrivateKey2(), PARAM_KEY);
+ assertPrivateKey(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
+ assertPrivateKey2(keyStore.getKey(ALIAS_ALT_CASE_PRIVATE, PASSWORD_KEY));
+ }
+
+ if (isNullPasswordAllowed(keyStore)) {
+ assertPrivateKey(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ assertNull(keyStore.getKey(ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE, null));
+ keyStore.setEntry(ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE, getPrivateKey2(), null);
+ assertPrivateKey(keyStore.getKey(ALIAS_NO_PASSWORD_PRIVATE, null));
+ assertPrivateKey2(keyStore.getKey(ALIAS_ALT_CASE_NO_PASSWORD_PRIVATE, null));
+ }
if (isSecretKeyEnabled(keyStore)) {
assertSecretKey(keyStore.getKey(ALIAS_SECRET, PASSWORD_KEY));
@@ -2073,10 +2290,17 @@ public class KeyStoreTest extends TestCase {
}
// test case sensitive
- assertTrue(keyStore.entryInstanceOf(ALIAS_PRIVATE, PrivateKeyEntry.class));
+ assertEquals(isKeyPasswordSupported(keyStore),
+ keyStore.entryInstanceOf(ALIAS_PRIVATE, PrivateKeyEntry.class));
assertFalse(keyStore.entryInstanceOf(ALIAS_PRIVATE, SecretKeyEntry.class));
assertFalse(keyStore.entryInstanceOf(ALIAS_PRIVATE, TrustedCertificateEntry.class));
+ assertEquals(isNullPasswordAllowed(keyStore),
+ keyStore.entryInstanceOf(ALIAS_NO_PASSWORD_PRIVATE, PrivateKeyEntry.class));
+ assertFalse(keyStore.entryInstanceOf(ALIAS_NO_PASSWORD_PRIVATE, SecretKeyEntry.class));
+ assertFalse(keyStore.entryInstanceOf(ALIAS_NO_PASSWORD_PRIVATE,
+ TrustedCertificateEntry.class));
+
assertEquals(isSecretKeyEnabled(keyStore),
keyStore.entryInstanceOf(ALIAS_SECRET, SecretKeyEntry.class));
assertFalse(keyStore.entryInstanceOf(ALIAS_SECRET, PrivateKeyEntry.class));
@@ -2173,7 +2397,7 @@ public class KeyStoreTest extends TestCase {
OutputStream os = null;
try {
os = new FileOutputStream(file);
- if (isReadOnly(keyStore)) {
+ if (isLoadStoreUnsupported(keyStore) || isReadOnly(keyStore)) {
try {
keyStore.store(os, PASSWORD_STORE);
fail(keyStore.getType());
@@ -2204,6 +2428,9 @@ public class KeyStoreTest extends TestCase {
}
for (KeyStore keyStore : keyStores()) {
+ if (isLoadStoreUnsupported(keyStore)) {
+ continue;
+ }
Builder builder = Builder.newInstance(keyStore.getType(),
keyStore.getProvider(),
PARAM_STORE);
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
index 8c9239e..4095081 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
@@ -19,6 +19,7 @@ package libcore.javax.net.ssl;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
@@ -1012,7 +1013,7 @@ public class SSLSocketTest extends TestCase {
assertEquals(0, wrapping.getSoTimeout());
// setting wrapper sets underlying and ...
- int expectedTimeoutMillis = 1000; // Using a small value such as 10 was affected by rounding
+ int expectedTimeoutMillis = 1000; // 10 was too small because it was affected by rounding
wrapping.setSoTimeout(expectedTimeoutMillis);
assertEquals(expectedTimeoutMillis, wrapping.getSoTimeout());
assertEquals(expectedTimeoutMillis, underlying.getSoTimeout());
@@ -1050,6 +1051,52 @@ public class SSLSocketTest extends TestCase {
listening.close();
}
+ public void test_SSLSocket_setSoWriteTimeout() throws Exception {
+ if (StandardNames.IS_RI) {
+ // RI does not support write timeout on sockets
+ return;
+ }
+
+ final TestSSLContext c = TestSSLContext.create();
+ SSLSocket client = (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host,
+ c.port);
+ final SSLSocket server = (SSLSocket) c.serverSocket.accept();
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ Future<Void> future = executor.submit(new Callable<Void>() {
+ @Override public Void call() throws Exception {
+ server.startHandshake();
+ return null;
+ }
+ });
+ executor.shutdown();
+ client.startHandshake();
+
+ // Reflection is used so this can compile on the RI
+ String expectedClassName = "org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl";
+ Class actualClass = client.getClass();
+ assertEquals(expectedClassName, actualClass.getName());
+ Method setSoWriteTimeout = actualClass.getMethod("setSoWriteTimeout",
+ new Class[] { Integer.TYPE });
+ setSoWriteTimeout.invoke(client, 1);
+
+ // Try to make the size smaller (it can be 512k or even megabytes).
+ // Note that it may not respect your request, so read back the actual value.
+ int sendBufferSize = 1024;
+ client.setSendBufferSize(sendBufferSize);
+ sendBufferSize = client.getSendBufferSize();
+
+ try {
+ client.getOutputStream().write(new byte[sendBufferSize + 1]);
+ fail();
+ } catch (SocketTimeoutException expected) {
+ }
+
+ future.get();
+ client.close();
+ server.close();
+ c.close();
+ }
+
public void test_SSLSocket_interrupt() throws Exception {
ServerSocket listening = new ServerSocket(0);
diff --git a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/CipherTest.java b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/CipherTest.java
index 7442210..c07b180 100644
--- a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/CipherTest.java
+++ b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/CipherTest.java
@@ -47,6 +47,7 @@ import javax.crypto.ShortBufferException;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
+import libcore.java.security.StandardNames;
import org.apache.harmony.crypto.tests.support.MyCipher;
import tests.support.resource.Support_Resources;
@@ -545,7 +546,10 @@ public class CipherTest extends junit.framework.TestCase {
try {
c.doFinal(b, 3, 6, b1, 5);
fail();
- } catch (ShortBufferException expected) {
+ } catch (IllegalBlockSizeException maybeExpected) {
+ assertTrue(StandardNames.IS_RI);
+ } catch (ShortBufferException maybeExpected) {
+ assertFalse(StandardNames.IS_RI);
}
}
diff --git a/luni/src/test/java/org/apache/harmony/security/tests/java/security/KeyRepTest.java b/luni/src/test/java/org/apache/harmony/security/tests/java/security/KeyRepTest.java
index 0dad827..a6529e8 100644
--- a/luni/src/test/java/org/apache/harmony/security/tests/java/security/KeyRepTest.java
+++ b/luni/src/test/java/org/apache/harmony/security/tests/java/security/KeyRepTest.java
@@ -26,199 +26,146 @@ import java.io.NotSerializableException;
import java.io.ObjectStreamException;
import java.security.KeyRep;
import java.security.Security;
-import java.util.Iterator;
import java.util.Set;
-
import junit.framework.TestCase;
-/**
- *
- *
- */
public class KeyRepTest extends TestCase {
- private static final Set<String> keyFactoryAlgorithm;
+ private static final Set<String> keyFactoryAlgorithms = Security.getAlgorithms("KeyFactory");
static {
- keyFactoryAlgorithm = Security.getAlgorithms("KeyFactory");
+ assertFalse(keyFactoryAlgorithms.isEmpty());
}
public final void testKeyRep01() {
- try {
- assertNotNull(new KeyRep(KeyRep.Type.SECRET, "", "", new byte[] {}));
- } catch (Exception e) {
- fail("Unexpected exception " + e.getMessage());
- }
-
- try {
- assertNotNull(new KeyRep(KeyRep.Type.PUBLIC, "", "", new byte[] {}));
- } catch (Exception e) {
- fail("Unexpected exception " + e.getMessage());
- }
-
- try {
- assertNotNull(new KeyRep(KeyRep.Type.PRIVATE, "", "", new byte[] {}));
- } catch (Exception e) {
- fail("Unexpected exception " + e.getMessage());
- }
+ assertNotNull(new KeyRep(KeyRep.Type.SECRET, "", "", new byte[] {}));
+ assertNotNull(new KeyRep(KeyRep.Type.PUBLIC, "", "", new byte[] {}));
+ assertNotNull(new KeyRep(KeyRep.Type.PRIVATE, "", "", new byte[] {}));
}
public final void testKeyRep02() {
try {
new KeyRep(null, "", "", new byte[] {});
fail("NullPointerException has not been thrown (type)");
- } catch (NullPointerException ok) {
-
+ } catch (NullPointerException expected) {
}
try {
new KeyRep(KeyRep.Type.SECRET, null, "", new byte[] {});
fail("NullPointerException has not been thrown (alg)");
- } catch (NullPointerException ok) {
-
+ } catch (NullPointerException expected) {
}
try {
new KeyRep(KeyRep.Type.PRIVATE, "", null, new byte[] {});
fail("NullPointerException has not been thrown (format)");
- } catch (NullPointerException ok) {
-
+ } catch (NullPointerException expected) {
}
try {
new KeyRep(KeyRep.Type.PUBLIC, "", "", null);
fail("NullPointerException has not been thrown (encoding)");
- } catch (NullPointerException ok) {
-
+ } catch (NullPointerException expected) {
}
}
- public final void testReadResolve01() throws ObjectStreamException {
- KeyRepChild kr = new KeyRepChild(KeyRep.Type.SECRET, "", "",
- new byte[] {});
+ public final void testReadResolve01() throws Exception {
+ KeyRepChild kr = new KeyRepChild(KeyRep.Type.SECRET, "", "", new byte[] {});
try {
kr.readResolve();
fail("NotSerializableException has not been thrown (no format)");
- } catch (NotSerializableException ok) {
-
+ } catch (NotSerializableException expected) {
}
kr = new KeyRepChild(KeyRep.Type.SECRET, "", "X.509", new byte[] {});
try {
kr.readResolve();
fail("NotSerializableException has not been thrown (unacceptable format)");
- } catch (NotSerializableException ok) {
-
+ } catch (NotSerializableException expected) {
}
kr = new KeyRepChild(KeyRep.Type.SECRET, "", "RAW", new byte[] {});
try {
kr.readResolve();
fail("NotSerializableException has not been thrown (empty key)");
- } catch (NotSerializableException ok) {
-
+ } catch (NotSerializableException expected) {
}
}
- public final void testReadResolve02() throws ObjectStreamException {
- KeyRepChild kr = new KeyRepChild(KeyRep.Type.PUBLIC, "", "",
- new byte[] {});
+ public final void testReadResolve02() throws Exception {
+ KeyRepChild kr = new KeyRepChild(KeyRep.Type.PUBLIC, "", "", new byte[] {});
try {
kr.readResolve();
fail("NotSerializableException has not been thrown (no format)");
- } catch (NotSerializableException ok) {
-
+ } catch (NotSerializableException expected) {
}
kr = new KeyRepChild(KeyRep.Type.PUBLIC, "", "RAW", new byte[] {});
try {
kr.readResolve();
fail("NotSerializableException has not been thrown (unacceptable format)");
- } catch (NotSerializableException ok) {
-
+ } catch (NotSerializableException expected) {
}
- kr = new KeyRepChild(KeyRep.Type.PUBLIC, "bla-bla", "X.509",
- new byte[] {});
+ kr = new KeyRepChild(KeyRep.Type.PUBLIC, "bla-bla", "X.509", new byte[] {});
try {
kr.readResolve();
fail("NotSerializableException has not been thrown (unknown KeyFactory algorithm)");
- } catch (NotSerializableException ok) {
-
+ } catch (NotSerializableException expected) {
}
}
- public final void testReadResolve03() throws ObjectStreamException {
- KeyRepChild kr = new KeyRepChild(KeyRep.Type.PRIVATE, "", "",
- new byte[] {});
+ public final void testReadResolve03() throws Exception {
+ KeyRepChild kr = new KeyRepChild(KeyRep.Type.PRIVATE, "", "", new byte[] {});
try {
kr.readResolve();
fail("NotSerializableException has not been thrown (no format)");
- } catch (NotSerializableException ok) {
-
+ } catch (NotSerializableException expected) {
}
kr = new KeyRepChild(KeyRep.Type.PRIVATE, "", "RAW", new byte[] {});
try {
kr.readResolve();
fail("NotSerializableException has not been thrown (unacceptable format)");
- } catch (NotSerializableException ok) {
-
+ } catch (NotSerializableException expected) {
}
- kr = new KeyRepChild(KeyRep.Type.PRIVATE, "bla-bla", "PKCS#8",
- new byte[] {});
+ kr = new KeyRepChild(KeyRep.Type.PRIVATE, "bla-bla", "PKCS#8", new byte[] {});
try {
kr.readResolve();
fail("NotSerializableException has not been thrown (unknown KeyFactory algorithm)");
- } catch (NotSerializableException ok) {
-
+ } catch (NotSerializableException expected) {
}
}
- public final void testReadResolve04() throws ObjectStreamException {
- if (keyFactoryAlgorithm.isEmpty()) {
- System.err.println(getName()
- + ": skipped - no KeyFactory algorithms available");
- return;
- } else {
- }
- for (Iterator<String> i = keyFactoryAlgorithm.iterator(); i.hasNext();) {
- KeyRepChild kr = new KeyRepChild(KeyRep.Type.PUBLIC, i.next(),
- "X.509", new byte[] { 1, 2, 3 });
+ public final void testReadResolve04() throws Exception {
+ for (String algorithm : keyFactoryAlgorithms) {
+ KeyRepChild kr = new KeyRepChild(KeyRep.Type.PUBLIC, algorithm, "X.509",
+ new byte[] { 1, 2, 3 });
try {
kr.readResolve();
- fail("NotSerializableException has not been thrown (no format)");
- } catch (NotSerializableException ok) {
-
+ fail("NotSerializableException has not been thrown (no format) " + algorithm);
+ } catch (NotSerializableException expected) {
}
}
}
- public final void testReadResolve05() throws ObjectStreamException {
- if (keyFactoryAlgorithm.isEmpty()) {
- System.err.println(getName()
- + ": skipped - no KeyFactory algorithms available");
- return;
- } else {
- }
- for (Iterator<String> i = keyFactoryAlgorithm.iterator(); i.hasNext();) {
- KeyRepChild kr = new KeyRepChild(KeyRep.Type.PRIVATE, i.next(),
- "PKCS#8", new byte[] { 1, 2, 3 });
+ public final void testReadResolve05() throws Exception {
+ for (String algorithm : keyFactoryAlgorithms) {
+ KeyRepChild kr = new KeyRepChild(KeyRep.Type.PRIVATE, algorithm, "PKCS#8",
+ new byte[] { 1, 2, 3 });
try {
kr.readResolve();
- fail("NotSerializableException has not been thrown (no format)");
- } catch (NotSerializableException ok) {
-
+ fail("NotSerializableException has not been thrown (no format) " + algorithm);
+ } catch (NotSerializableException expected) {
}
}
}
class KeyRepChild extends KeyRep {
- public KeyRepChild(KeyRep.Type type, String algorithm, String format,
- byte[] encoded) {
+ public KeyRepChild(KeyRep.Type type, String algorithm, String format, byte[] encoded) {
super(type, algorithm, format, encoded);
}
- public Object readResolve() throws ObjectStreamException {
+ // Overriden to make public for testing
+ @Override public Object readResolve() throws ObjectStreamException {
return super.readResolve();
}
-
}
}
diff --git a/luni/src/test/java/org/apache/harmony/security/tests/java/security/KeyStoreLoadStoreParameterTest.java b/luni/src/test/java/org/apache/harmony/security/tests/java/security/KeyStoreLoadStoreParameterTest.java
deleted file mode 100644
index 81ec30d..0000000
--- a/luni/src/test/java/org/apache/harmony/security/tests/java/security/KeyStoreLoadStoreParameterTest.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package org.apache.harmony.security.tests.java.security;
-
-import java.security.KeyStore;
-
-public class KeyStoreLoadStoreParameterTest {
-
- class MyLoadStoreParameter implements KeyStore.LoadStoreParameter {
- public KeyStore.ProtectionParameter getProtectionParameter() {
- return null;
- }
- }
-
-
-
-}
diff --git a/luni/src/test/java/org/apache/harmony/security/tests/java/security/Security2Test.java b/luni/src/test/java/org/apache/harmony/security/tests/java/security/Security2Test.java
index d9f4dd7..68e7cbc 100644
--- a/luni/src/test/java/org/apache/harmony/security/tests/java/security/Security2Test.java
+++ b/luni/src/test/java/org/apache/harmony/security/tests/java/security/Security2Test.java
@@ -20,14 +20,14 @@ package org.apache.harmony.security.tests.java.security;
import java.security.InvalidParameterException;
import java.security.Provider;
import java.security.Security;
-import java.util.Hashtable;
-import java.util.Iterator;
+import java.util.HashMap;
import java.util.Map;
import java.util.Set;
+import junit.framework.TestCase;
import tests.support.Support_ProviderTrust;
import tests.support.Support_TestProvider;
-public class Security2Test extends junit.framework.TestCase {
+public class Security2Test extends TestCase {
/**
* java.security.Security#getProviders(java.lang.String)
@@ -36,16 +36,13 @@ public class Security2Test extends junit.framework.TestCase {
// Test for method void
// java.security.Security.getProviders(java.lang.String)
- Hashtable<String, Integer> allSupported = new Hashtable<String, Integer>();
+ Map<String, Integer> allSupported = new HashMap<String, Integer>();
Provider[] allProviders = Security.getProviders();
// Add all non-alias entries to allSupported
- for (int i = 0; i < allProviders.length; i++) {
- Provider provider = allProviders[i];
- Iterator it = provider.entrySet().iterator();
- while (it.hasNext()) {
- Map.Entry entry = (Map.Entry) it.next();
- String key = (String) entry.getKey();
+ for (Provider provider : allProviders) {
+ for (Object k : provider.keySet()) {
+ String key = (String) k;
// No aliases and no provider data
if (!isAlias(key) && !isProviderData(key)) {
addOrIncrementTable(allSupported, key);
@@ -56,22 +53,18 @@ public class Security2Test extends junit.framework.TestCase {
// Now walk through aliases. If an alias has actually been added
// to the allSupported table then increment the count of the
// entry that is being aliased.
- for (int i = 0; i < allProviders.length; i++) {
- Provider provider = allProviders[i];
- Iterator it = provider.entrySet().iterator();
- while (it.hasNext()) {
- Map.Entry entry = (Map.Entry) it.next();
+ for (Provider provider : allProviders) {
+ for (Map.Entry entry : provider.entrySet()) {
String key = (String) entry.getKey();
if (isAlias(key)) {
String aliasVal = key.substring("ALG.ALIAS.".length());
- String aliasKey = aliasVal.substring(0, aliasVal
- .indexOf(".") + 1)
+ String aliasKey = aliasVal.substring(0, aliasVal.indexOf(".") + 1)
+ entry.getValue();
// Skip over nonsense alias declarations where alias and
// aliased are identical. Such entries can occur.
- if (!aliasVal.equals(aliasKey)) {
+ if (!aliasVal.equalsIgnoreCase(aliasKey)) {
// Has a real entry been added for aliasValue ?
- if (allSupported.containsKey(aliasVal)) {
+ if (allSupported.containsKey(aliasVal.toUpperCase())) {
// Add 1 to the provider count of the thing being
// aliased
addOrIncrementTable(allSupported, aliasKey);
@@ -81,17 +74,13 @@ public class Security2Test extends junit.framework.TestCase {
}// end while more entries
}// end for all providers
- Provider provTest[] = null;
- Iterator it = allSupported.keySet().iterator();
- while (it.hasNext()) {
- String filterString = (String) it.next();
+ for (String filterString : allSupported.keySet()) {
try {
- provTest = Security.getProviders(filterString);
- int expected = ((Integer) allSupported.get(filterString))
- .intValue();
- assertEquals(
- "Unexpected number of providers returned for filter "
- + filterString, expected, provTest.length);
+ Provider[] provTest = Security.getProviders(filterString);
+ int expected = allSupported.get(filterString);
+ assertEquals("Unexpected number of providers returned for filter " + filterString
+ + ":\n" + allSupported,
+ expected, provTest.length);
} catch (InvalidParameterException e) {
// NO OP
}
@@ -99,62 +88,43 @@ public class Security2Test extends junit.framework.TestCase {
// exception
try {
- provTest = Security.getProviders("Signature.SHA1withDSA :512");
+ Security.getProviders("Signature.SHA1withDSA :512");
fail("InvalidParameterException should be thrown <Signature.SHA1withDSA :512>");
} catch (InvalidParameterException e) {
// Expected
}
}
- /**
- * @param key
- * @return
- */
private boolean isProviderData(String key) {
return key.toUpperCase().startsWith("PROVIDER.");
}
- /**
- * @param key
- * @return
- */
private boolean isAlias(String key) {
return key.toUpperCase().startsWith("ALG.ALIAS.");
}
- /**
- * @param table
- * @param key
- */
- private void addOrIncrementTable(Hashtable<String, Integer> table, String key) {
+ private void addOrIncrementTable(Map<String, Integer> table, String k) {
+ String key = k.toUpperCase();
if (table.containsKey(key)) {
- Integer before = (Integer) table.get(key);
- table.put(key, new Integer(before.intValue() + 1));
+ int before = table.get(key);
+ table.put(key, before + 1);
} else {
- table.put(key, new Integer(1));
+ table.put(key, 1);
}
}
- /**
- * @param filterMap
- * @return
- */
private int getProvidersCount(Map filterMap) {
int result = 0;
Provider[] allProviders = Security.getProviders();
// for each provider
- for (int i = 0; i < allProviders.length; i++) {
- Provider provider = allProviders[i];
+ for (Provider provider : allProviders) {
Set allProviderKeys = provider.keySet();
boolean noMatchFoundForFilterEntry = false;
// for each filter item
- Set allFilterKeys = filterMap.keySet();
- Iterator fkIter = allFilterKeys.iterator();
- while (fkIter.hasNext()) {
- String filterString = ((String) fkIter.next()).trim();
-
+ for (Object filter : filterMap.keySet()) {
+ String filterString = (String) filter;
// Remove any "=" characters that may be on the end of the
// map keys (no, I don't know why they might be there either
// but I have seen them)
@@ -211,10 +181,10 @@ public class Security2Test extends junit.framework.TestCase {
// Test for method void
// java.security.Security.getProviders(java.util.Map)
- Map<String, String> filter = new Hashtable<String, String>();
+ Map<String, String> filter = new HashMap<String, String>();
filter.put("KeyStore.BKS", "");
filter.put("Signature.SHA1withDSA", "");
- Provider provTest[] = Security.getProviders(filter);
+ Provider[] provTest = Security.getProviders(filter);
if (provTest == null) {
assertEquals("Filter : <KeyStore.BKS>,<Signature.SHA1withDSA>",
0, getProvidersCount(filter));
@@ -223,7 +193,7 @@ public class Security2Test extends junit.framework.TestCase {
getProvidersCount(filter), provTest.length);
}
- filter = new Hashtable<String, String>();
+ filter = new HashMap<String, String>();
filter.put("MessageDigest.SHA-384", "");
filter.put("CertificateFactory.X.509", "");
filter.put("KeyFactory.RSA", "");
@@ -237,7 +207,7 @@ public class Security2Test extends junit.framework.TestCase {
getProvidersCount(filter), provTest.length);
}
- filter = new Hashtable<String, String>();
+ filter = new HashMap<String, String>();
filter.put("MessageDigest.SHA1", "");
filter.put("TrustManagerFactory.X509", "");
provTest = Security.getProviders(filter);
@@ -250,7 +220,7 @@ public class Security2Test extends junit.framework.TestCase {
getProvidersCount(filter), provTest.length);
}
- filter = new Hashtable<String, String>();
+ filter = new HashMap<String, String>();
filter.put("CertificateFactory.X509", "");
provTest = Security.getProviders(filter);
if (provTest == null) {
@@ -261,7 +231,7 @@ public class Security2Test extends junit.framework.TestCase {
getProvidersCount(filter), provTest.length);
}
- filter = new Hashtable<String, String>();
+ filter = new HashMap<String, String>();
filter.put("Provider.id name", "DRLCertFactory");
provTest = Security.getProviders(filter);
assertNull("Filter : <Provider.id name, DRLCertFactory >",
@@ -270,7 +240,7 @@ public class Security2Test extends junit.framework.TestCase {
// exception - no attribute name after the service.algorithm yet we
// still supply an expected value. This is not valid.
try {
- filter = new Hashtable<String, String>();
+ filter = new HashMap<String, String>();
filter.put("Signature.SHA1withDSA", "512");
provTest = Security.getProviders(filter);
fail("InvalidParameterException should be thrown <Signature.SHA1withDSA><512>");
@@ -280,7 +250,7 @@ public class Security2Test extends junit.framework.TestCase {
// exception - space character in the service.algorithm pair. Not valid.
try {
- filter = new Hashtable<String, String>();
+ filter = new HashMap<String, String>();
filter.put("Signature. KeySize", "512");
provTest = Security.getProviders(filter);
fail("InvalidParameterException should be thrown <Signature. KeySize><512>");
@@ -320,11 +290,9 @@ public class Security2Test extends junit.framework.TestCase {
assertTrue("Failed to add provider", addResult != -1);
Security.removeProvider(entrust.getName());
- Provider provTest[] = Security.getProviders();
- for (int i = 0; i < provTest.length; i++) {
- assertTrue(
- "the provider entrust is found after it was removed",
- provTest[i].getName() != entrust.getName());
+ for (Provider provider : Security.getProviders()) {
+ assertTrue("the provider entrust is found after it was removed",
+ provider.getName() != entrust.getName());
}
} finally {
// Tidy up - the following calls do nothing if the providers were
diff --git a/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/CertPinManagerTest.java b/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/CertPinManagerTest.java
new file mode 100644
index 0000000..8359c99
--- /dev/null
+++ b/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/CertPinManagerTest.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2012 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.apache.harmony.xnet.provider.jsse;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.security.cert.X509Certificate;
+import java.security.KeyStore;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
+import junit.framework.TestCase;
+import libcore.java.security.TestKeyStore;
+
+public class CertPinManagerTest extends TestCase {
+
+ private X509Certificate[] chain;
+ private List<X509Certificate> shortChain;
+ private List<X509Certificate> longChain;
+ private String shortPin;
+ private String longPin;
+ private List<File> tmpFiles = new ArrayList<File>();
+
+ private String writeTmpPinFile(String text) throws Exception {
+ File tmp = File.createTempFile("pins", null);
+ FileWriter fstream = new FileWriter(tmp);
+ fstream.write(text);
+ fstream.close();
+ tmpFiles.add(tmp);
+ return tmp.getPath();
+ }
+
+ private static String getFingerprint(X509Certificate cert) throws NoSuchAlgorithmException {
+ MessageDigest dgst = MessageDigest.getInstance("SHA512");
+ byte[] encoded = cert.getPublicKey().getEncoded();
+ byte[] fingerprint = dgst.digest(encoded);
+ return IntegralToString.bytesToHexString(fingerprint, false);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ // build some valid chains
+ KeyStore.PrivateKeyEntry pke = TestKeyStore.getServer().getPrivateKey("RSA", "RSA");
+ chain = (X509Certificate[]) pke.getCertificateChain();
+ X509Certificate root = chain[2];
+ X509Certificate server = chain[0];
+
+ // build the short and long chains
+ shortChain = new ArrayList<X509Certificate>();
+ shortChain.add(root);
+ longChain = new ArrayList<X509Certificate>();
+ longChain.add(server);
+
+ // we'll use the root as the pin for the short entry and the server as the pin for the long
+ shortPin = getFingerprint(root);
+ longPin = getFingerprint(server);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ try {
+ for (File f : tmpFiles) {
+ f.delete();
+ }
+ tmpFiles.clear();
+ } finally {
+ super.tearDown();
+ }
+ }
+
+ public void testPinFileMaximumLookup() throws Exception {
+
+ // write a pinfile with two entries, one longer than the other
+ String shortEntry = "*.google.com=true|" + shortPin;
+ String longEntry = "*.clients.google.com=true|" + longPin;
+
+ // create the pinFile
+ String path = writeTmpPinFile(shortEntry + "\n" + longEntry);
+ CertPinManager pf = new CertPinManager(path, new TrustedCertificateStore());
+
+ // verify that the shorter chain doesn't work for a name matching the longer
+ assertTrue("short chain long uri failed",
+ pf.chainIsNotPinned("android.clients.google.com", shortChain));
+ // verify that the longer chain doesn't work for a name matching the shorter
+ assertTrue("long chain short uri failed",
+ pf.chainIsNotPinned("android.google.com", longChain));
+ // verify that the shorter chain works for the shorter domain
+ assertTrue("short chain short uri failed",
+ !pf.chainIsNotPinned("android.google.com", shortChain));
+ // and the same for the longer
+ assertTrue("long chain long uri failed",
+ !pf.chainIsNotPinned("android.clients.google.com", longChain));
+ }
+
+ public void testPinEntryMalformedEntry() throws Exception {
+ // set up the pinEntry with a bogus entry
+ String entry = "*.google.com=";
+ try {
+ new PinListEntry(entry, new TrustedCertificateStore());
+ fail("Accepted an empty pin list entry.");
+ } catch (PinEntryException expected) {
+ }
+ }
+
+ public void testPinEntryNull() throws Exception {
+ // set up the pinEntry with a bogus entry
+ String entry = null;
+ try {
+ new PinListEntry(entry, new TrustedCertificateStore());
+ fail("Accepted a basically wholly bogus entry.");
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ public void testPinEntryEmpty() throws Exception {
+ // set up the pinEntry with a bogus entry
+ try {
+ new PinListEntry("", new TrustedCertificateStore());
+ fail("Accepted an empty entry.");
+ } catch (PinEntryException expected) {
+ }
+ }
+
+ public void testPinEntryPinFailure() throws Exception {
+ // write a pinfile with two entries, one longer than the other
+ String shortEntry = "*.google.com=true|" + shortPin;
+
+ // set up the pinEntry with a pinlist that doesn't match what we'll give it
+ PinListEntry e = new PinListEntry(shortEntry, new TrustedCertificateStore());
+ assertTrue("Not enforcing!", e.getEnforcing());
+ // verify that it doesn't accept
+ boolean retval = e.chainIsNotPinned(longChain);
+ assertTrue("Accepted an incorrect pinning, this is very bad", retval);
+ }
+
+ public void testPinEntryPinSuccess() throws Exception {
+ // write a pinfile with two entries, one longer than the other
+ String shortEntry = "*.google.com=true|" + shortPin;
+
+ // set up the pinEntry with a pinlist that matches what we'll give it
+ PinListEntry e = new PinListEntry(shortEntry, new TrustedCertificateStore());
+ assertTrue("Not enforcing!", e.getEnforcing());
+ // verify that it accepts
+ boolean retval = e.chainIsNotPinned(shortChain);
+ assertTrue("Failed on a correct pinning, this is very bad", !retval);
+ }
+
+ public void testPinEntryNonEnforcing() throws Exception {
+ // write a pinfile with two entries, one longer than the other
+ String shortEntry = "*.google.com=false|" + shortPin;
+
+ // set up the pinEntry with a pinlist that matches what we'll give it
+ PinListEntry e = new PinListEntry(shortEntry, new TrustedCertificateStore());
+ assertFalse("Enforcing!", e.getEnforcing());
+ // verify that it accepts
+ boolean retval = e.chainIsNotPinned(shortChain);
+ assertTrue("Failed on an unenforced pinning, this is bad-ish", !retval);
+ }
+}
diff --git a/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/NativeCryptoTest.java b/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/NativeCryptoTest.java
index 15b175c..a215445 100644
--- a/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/NativeCryptoTest.java
+++ b/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/NativeCryptoTest.java
@@ -21,10 +21,14 @@ import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStore.PrivateKeyEntry;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPrivateKey;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -131,6 +135,93 @@ public class NativeCryptoTest extends TestCase {
assertEquals(Arrays.deepToString(expected), Arrays.deepToString(actual));
}
+ public void test_EVP_PKEY_cmp() throws Exception {
+ try {
+ NativeCrypto.EVP_PKEY_cmp(NULL, NULL);
+ fail("Should throw NullPointerException when arguments are NULL");
+ } catch (NullPointerException expected) {
+ }
+
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
+ kpg.initialize(512);
+
+ RSAPrivateCrtKey privKey1, privKey2;
+
+ {
+ KeyPair kp1 = kpg.generateKeyPair();
+ privKey1 = (RSAPrivateCrtKey) kp1.getPrivate();
+ }
+
+ {
+ KeyPair kp2 = kpg.generateKeyPair();
+ privKey2 = (RSAPrivateCrtKey) kp2.getPrivate();
+ }
+
+ int pkey1 = 0, pkey1_copy = 0, pkey2 = 0;
+ try {
+ pkey1 = NativeCrypto.EVP_PKEY_new_RSA(privKey1.getModulus().toByteArray(),
+ privKey1.getPublicExponent().toByteArray(),
+ privKey1.getPrivateExponent().toByteArray(),
+ privKey1.getPrimeP().toByteArray(),
+ privKey1.getPrimeQ().toByteArray(),
+ privKey1.getPrimeExponentP().toByteArray(),
+ privKey1.getPrimeExponentQ().toByteArray(),
+ privKey1.getCrtCoefficient().toByteArray());
+ assertNotSame(NULL, pkey1);
+
+ pkey1_copy = NativeCrypto.EVP_PKEY_new_RSA(privKey1.getModulus().toByteArray(),
+ privKey1.getPublicExponent().toByteArray(),
+ privKey1.getPrivateExponent().toByteArray(),
+ privKey1.getPrimeP().toByteArray(),
+ privKey1.getPrimeQ().toByteArray(),
+ privKey1.getPrimeExponentP().toByteArray(),
+ privKey1.getPrimeExponentQ().toByteArray(),
+ privKey1.getCrtCoefficient().toByteArray());
+ assertNotSame(NULL, pkey1_copy);
+
+ pkey2 = NativeCrypto.EVP_PKEY_new_RSA(privKey2.getModulus().toByteArray(),
+ privKey2.getPublicExponent().toByteArray(),
+ privKey2.getPrivateExponent().toByteArray(),
+ privKey2.getPrimeP().toByteArray(),
+ privKey2.getPrimeQ().toByteArray(),
+ privKey2.getPrimeExponentP().toByteArray(),
+ privKey2.getPrimeExponentQ().toByteArray(),
+ privKey2.getCrtCoefficient().toByteArray());
+ assertNotSame(NULL, pkey2);
+
+ try {
+ NativeCrypto.EVP_PKEY_cmp(pkey1, NULL);
+ fail("Should throw NullPointerException when arguments are NULL");
+ } catch (NullPointerException expected) {
+ }
+
+ try {
+ NativeCrypto.EVP_PKEY_cmp(NULL, pkey1);
+ fail("Should throw NullPointerException when arguments are NULL");
+ } catch (NullPointerException expected) {
+ }
+
+ assertEquals("Same keys should be the equal", 1,
+ NativeCrypto.EVP_PKEY_cmp(pkey1, pkey1));
+
+ assertEquals("Same keys should be the equal", 1,
+ NativeCrypto.EVP_PKEY_cmp(pkey1, pkey1_copy));
+
+ assertEquals("Different keys should not be equal", 0,
+ NativeCrypto.EVP_PKEY_cmp(pkey1, pkey2));
+ } finally {
+ if (pkey1 != 0) {
+ NativeCrypto.EVP_PKEY_free(pkey1);
+ }
+ if (pkey1_copy != 0) {
+ NativeCrypto.EVP_PKEY_free(pkey1_copy);
+ }
+ if (pkey2 != 0) {
+ NativeCrypto.EVP_PKEY_free(pkey2);
+ }
+ }
+ }
+
public void test_SSL_CTX_new() throws Exception {
int c = NativeCrypto.SSL_CTX_new();
assertTrue(c != NULL);
@@ -781,7 +872,7 @@ public class NativeCryptoTest extends TestCase {
NativeCrypto.SSL_set_options(
s, NativeCrypto.SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
NativeCrypto.SSL_renegotiate(s);
- NativeCrypto.SSL_write(s, fd, callback, new byte[] { 42 }, 0, 1);
+ NativeCrypto.SSL_write(s, fd, callback, new byte[] { 42 }, 0, 1, 0);
super.afterHandshake(session, s, c, sock, fd, callback);
}
};
@@ -1150,7 +1241,7 @@ public class NativeCryptoTest extends TestCase {
SSLHandshakeCallbacks callback)
throws Exception {
NativeCrypto.SSL_renegotiate(s);
- NativeCrypto.SSL_write(s, fd, callback, new byte[] { 42 }, 0, 1);
+ NativeCrypto.SSL_write(s, fd, callback, new byte[] { 42 }, 0, 1, 0);
super.afterHandshake(session, s, c, sock, fd, callback);
}
};
@@ -1317,7 +1408,7 @@ public class NativeCryptoTest extends TestCase {
Socket sock, FileDescriptor fd,
SSLHandshakeCallbacks callback)
throws Exception {
- NativeCrypto.SSL_write(s, fd, callback, BYTES, 0, BYTES.length);
+ NativeCrypto.SSL_write(s, fd, callback, BYTES, 0, BYTES.length, 0);
super.afterHandshake(session, s, c, sock, fd, callback);
}
};
@@ -1360,7 +1451,7 @@ public class NativeCryptoTest extends TestCase {
public void test_SSL_write() throws Exception {
try {
- NativeCrypto.SSL_write(NULL, null, null, null, 0, 0);
+ NativeCrypto.SSL_write(NULL, null, null, null, 0, 0, 0);
fail();
} catch (NullPointerException expected) {
}
@@ -1370,7 +1461,7 @@ public class NativeCryptoTest extends TestCase {
int c = NativeCrypto.SSL_CTX_new();
int s = NativeCrypto.SSL_new(c);
try {
- NativeCrypto.SSL_write(s, null, DUMMY_CB, null, 0, 1);
+ NativeCrypto.SSL_write(s, null, DUMMY_CB, null, 0, 1, 0);
fail();
} catch (NullPointerException expected) {
}
@@ -1383,7 +1474,7 @@ public class NativeCryptoTest extends TestCase {
int c = NativeCrypto.SSL_CTX_new();
int s = NativeCrypto.SSL_new(c);
try {
- NativeCrypto.SSL_write(s, INVALID_FD, null, null, 0, 1);
+ NativeCrypto.SSL_write(s, INVALID_FD, null, null, 0, 1, 0);
fail();
} catch (NullPointerException expected) {
}
@@ -1396,7 +1487,7 @@ public class NativeCryptoTest extends TestCase {
int c = NativeCrypto.SSL_CTX_new();
int s = NativeCrypto.SSL_new(c);
try {
- NativeCrypto.SSL_write(s, INVALID_FD, DUMMY_CB, null, 0, 1);
+ NativeCrypto.SSL_write(s, INVALID_FD, DUMMY_CB, null, 0, 1, 0);
fail();
} catch (NullPointerException expected) {
}
@@ -1409,7 +1500,7 @@ public class NativeCryptoTest extends TestCase {
int c = NativeCrypto.SSL_CTX_new();
int s = NativeCrypto.SSL_new(c);
try {
- NativeCrypto.SSL_write(s, INVALID_FD, DUMMY_CB, new byte[1], 0, 1);
+ NativeCrypto.SSL_write(s, INVALID_FD, DUMMY_CB, new byte[1], 0, 1, 0);
fail();
} catch (SSLException expected) {
}
diff --git a/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/TrustManagerImplTest.java b/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/TrustManagerImplTest.java
index 26ebc85..fe5f4f0 100644
--- a/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/TrustManagerImplTest.java
+++ b/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/TrustManagerImplTest.java
@@ -16,9 +16,15 @@
package org.apache.harmony.xnet.provider.jsse;
-import java.security.KeyStore;
+import java.io.File;
+import java.io.FileWriter;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
+import java.security.KeyStore;
+import java.security.MessageDigest;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
@@ -27,12 +33,41 @@ import libcore.java.security.TestKeyStore;
public class TrustManagerImplTest extends TestCase {
+ private List<File> tmpFiles = new ArrayList<File>();
+
+ private String getFingerprint(X509Certificate cert) throws Exception {
+ MessageDigest dgst = MessageDigest.getInstance("SHA512");
+ byte[] encoded = cert.getPublicKey().getEncoded();
+ byte[] fingerprint = dgst.digest(encoded);
+ return IntegralToString.bytesToHexString(fingerprint, false);
+ }
+
+ private String writeTmpPinFile(String text) throws Exception {
+ File tmp = File.createTempFile("pins", null);
+ FileWriter fstream = new FileWriter(tmp);
+ fstream.write(text);
+ fstream.close();
+ tmpFiles.add(tmp);
+ return tmp.getPath();
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ try {
+ for (File f : tmpFiles) {
+ f.delete();
+ }
+ tmpFiles.clear();
+ } finally {
+ super.tearDown();
+ }
+ }
+
/**
* Ensure that our non-standard behavior of learning to trust new
* intermediate CAs does not regress. http://b/3404902
*/
public void testLearnIntermediate() throws Exception {
-
// chain3 should be server/intermediate/root
KeyStore.PrivateKeyEntry pke = TestKeyStore.getServer().getPrivateKey("RSA", "RSA");
X509Certificate[] chain3 = (X509Certificate[])pke.getCertificateChain();
@@ -63,6 +98,52 @@ public class TrustManagerImplTest extends TestCase {
assertValid(chain1, tm);
}
+ public void testGetFullChain() throws Exception {
+ // build the trust manager
+ KeyStore.PrivateKeyEntry pke = TestKeyStore.getServer().getPrivateKey("RSA", "RSA");
+ X509Certificate[] chain3 = (X509Certificate[])pke.getCertificateChain();
+ X509Certificate root = chain3[2];
+ X509TrustManager tm = trustManager(root);
+
+ // build the chains we'll use for testing
+ X509Certificate intermediate = chain3[1];
+ X509Certificate server = chain3[0];
+ X509Certificate[] chain2 = new X509Certificate[] { server, intermediate };
+ X509Certificate[] chain1 = new X509Certificate[] { server };
+
+ assertTrue(tm instanceof TrustManagerImpl);
+ TrustManagerImpl tmi = (TrustManagerImpl) tm;
+ List<X509Certificate> certs = tmi.checkServerTrusted(chain2, "RSA", "purple.com");
+ assertEquals(Arrays.asList(chain3), certs);
+ certs = tmi.checkServerTrusted(chain1, "RSA", "purple.com");
+ assertEquals(Arrays.asList(chain3), certs);
+ }
+
+ public void testCertPinning() throws Exception {
+ // chain3 should be server/intermediate/root
+ KeyStore.PrivateKeyEntry pke = TestKeyStore.getServer().getPrivateKey("RSA", "RSA");
+ X509Certificate[] chain3 = (X509Certificate[]) pke.getCertificateChain();
+ X509Certificate root = chain3[2];
+ X509Certificate intermediate = chain3[1];
+ X509Certificate server = chain3[0];
+ X509Certificate[] chain2 = new X509Certificate[] { server, intermediate };
+ X509Certificate[] chain1 = new X509Certificate[] { server };
+
+ // test without a hostname, expecting failure
+ assertInvalidPinned(chain1, trustManager(root, "gugle.com", root), null);
+ // test without a hostname, expecting success
+ assertValidPinned(chain3, trustManager(root, "gugle.com", root), null, chain3);
+ // test an unpinned hostname that should fail
+ assertInvalidPinned(chain1, trustManager(root, "gugle.com", root), "purple.com");
+ // test an unpinned hostname that should succeed
+ assertValidPinned(chain3, trustManager(root, "gugle.com", root), "purple.com", chain3);
+ // test a pinned hostname that should fail
+ assertInvalidPinned(chain1, trustManager(intermediate, "gugle.com", root), "gugle.com");
+ // test a pinned hostname that should succeed
+ assertValidPinned(chain2, trustManager(intermediate, "gugle.com", server), "gugle.com",
+ chain2);
+ }
+
private X509TrustManager trustManager(X509Certificate ca) throws Exception {
KeyStore keyStore = TestKeyStore.createKeyStore();
keyStore.setCertificateEntry("alias", ca);
@@ -73,10 +154,45 @@ public class TrustManagerImplTest extends TestCase {
return (X509TrustManager) tmf.getTrustManagers()[0];
}
+ private TrustManagerImpl trustManager(X509Certificate ca, String hostname, X509Certificate pin)
+ throws Exception {
+ // build the cert pin manager
+ CertPinManager cm = certManager(hostname, pin);
+ // insert it into the trust manager
+ KeyStore keyStore = TestKeyStore.createKeyStore();
+ keyStore.setCertificateEntry("alias", ca);
+ return new TrustManagerImpl(keyStore, cm);
+ }
+
+ private CertPinManager certManager(String hostname, X509Certificate pin) throws Exception {
+ String pinString = "";
+ if (pin != null) {
+ pinString = hostname + "=true|" + getFingerprint(pin);
+ }
+ // write it to a pinfile
+ String path = writeTmpPinFile(pinString);
+ // build the certpinmanager
+ return new CertPinManager(path, new TrustedCertificateStore());
+ }
+
private void assertValid(X509Certificate[] chain, X509TrustManager tm) throws Exception {
- tm.checkClientTrusted(chain, "RSA");
+ if (tm instanceof TrustManagerImpl) {
+ TrustManagerImpl tmi = (TrustManagerImpl) tm;
+ tmi.checkServerTrusted(chain, "RSA");
+ }
tm.checkServerTrusted(chain, "RSA");
}
+
+ private void assertValidPinned(X509Certificate[] chain, X509TrustManager tm, String hostname,
+ X509Certificate[] fullChain) throws Exception {
+ if (tm instanceof TrustManagerImpl) {
+ TrustManagerImpl tmi = (TrustManagerImpl) tm;
+ List<X509Certificate> checkedChain = tmi.checkServerTrusted(chain, "RSA", hostname);
+ assertEquals(checkedChain, Arrays.asList(fullChain));
+ }
+ tm.checkServerTrusted(chain, "RSA");
+ }
+
private void assertInvalid(X509Certificate[] chain, X509TrustManager tm) {
try {
tm.checkClientTrusted(chain, "RSA");
@@ -89,4 +205,15 @@ public class TrustManagerImplTest extends TestCase {
} catch (CertificateException expected) {
}
}
+
+ private void assertInvalidPinned(X509Certificate[] chain, X509TrustManager tm, String hostname)
+ throws Exception {
+ assertTrue(tm.getClass().getName(), tm instanceof TrustManagerImpl);
+ try {
+ TrustManagerImpl tmi = (TrustManagerImpl) tm;
+ tmi.checkServerTrusted(chain, "RSA", hostname);
+ fail();
+ } catch (CertificateException expected) {
+ }
+ }
}
diff --git a/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/TrustedCertificateStoreTest.java b/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/TrustedCertificateStoreTest.java
index 52880df..8f9b7fa 100644
--- a/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/TrustedCertificateStoreTest.java
+++ b/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/TrustedCertificateStoreTest.java
@@ -530,6 +530,26 @@ public class TrustedCertificateStoreTest extends TestCase {
assertDeleted(getCa1(), getAliasSystemCa1());
}
+ public void testIsUserAddedCertificate() throws Exception {
+ assertFalse(store.isUserAddedCertificate(getCa1()));
+ assertFalse(store.isUserAddedCertificate(getCa2()));
+ install(getCa1(), getAliasSystemCa1());
+ assertFalse(store.isUserAddedCertificate(getCa1()));
+ assertFalse(store.isUserAddedCertificate(getCa2()));
+ install(getCa1(), getAliasUserCa1());
+ assertTrue(store.isUserAddedCertificate(getCa1()));
+ assertFalse(store.isUserAddedCertificate(getCa2()));
+ install(getCa2(), getAliasUserCa2());
+ assertTrue(store.isUserAddedCertificate(getCa1()));
+ assertTrue(store.isUserAddedCertificate(getCa2()));
+ store.deleteCertificateEntry(getAliasUserCa1());
+ assertFalse(store.isUserAddedCertificate(getCa1()));
+ assertTrue(store.isUserAddedCertificate(getCa2()));
+ store.deleteCertificateEntry(getAliasUserCa2());
+ assertFalse(store.isUserAddedCertificate(getCa1()));
+ assertFalse(store.isUserAddedCertificate(getCa2()));
+ }
+
private void assertRootCa(X509Certificate x, String alias) {
assertIntermediateCa(x, alias);
assertEquals(x, store.findIssuer(x));
diff --git a/support/src/test/java/libcore/java/security/StandardNames.java b/support/src/test/java/libcore/java/security/StandardNames.java
index f01a9b9..4211a10 100644
--- a/support/src/test/java/libcore/java/security/StandardNames.java
+++ b/support/src/test/java/libcore/java/security/StandardNames.java
@@ -351,14 +351,6 @@ public final class StandardNames extends Assert {
// different names: added "Encryption" suffix
unprovide("Signature", "MD5withRSA");
provide("Signature", "MD5WithRSAEncryption");
- unprovide("Signature", "SHA1withRSA");
- provide("Signature", "SHA1WithRSAEncryption");
- unprovide("Signature", "SHA256WithRSA");
- provide("Signature", "SHA256WithRSAEncryption");
- unprovide("Signature", "SHA384WithRSA");
- provide("Signature", "SHA384WithRSAEncryption");
- unprovide("Signature", "SHA512WithRSA");
- provide("Signature", "SHA512WithRSAEncryption");
// Added to support Android KeyStore operations
provide("Signature", "NONEwithRSA");
@@ -477,6 +469,12 @@ public final class StandardNames extends Assert {
// Android's CA store
provide("KeyStore", "AndroidCAStore");
+
+ // Android's KeyStore provider
+ if (Security.getProvider("AndroidKeyStoreProvider") != null) {
+ provide("KeyStore", "AndroidKeyStore");
+ provide("KeyPairGenerator", "AndroidKeyPairGenerator");
+ }
}
}