diff options
43 files changed, 2777 insertions, 1077 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 <command>" 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/java/util/Locale.java b/luni/src/main/java/java/util/Locale.java index 6b20a1c..0fbe2f5 100644 --- a/luni/src/main/java/java/util/Locale.java +++ b/luni/src/main/java/java/util/Locale.java @@ -396,6 +396,17 @@ public final class Locale implements Cloneable, Serializable { if (languageCode.isEmpty()) { return ""; } + + // Last-minute workaround for http://b/7291355 in jb-mr1. + // This isn't right for all languages, but it's right for en and tl. + // We should have more CLDR data in a future release, but we'll still + // probably want to have frameworks/base translate the obsolete tl and + // tl-rPH locales to fil and fil-rPH at runtime, at which point + // libcore and icu4c will just do the right thing. + if (languageCode.equals("tl")) { + return "Filipino"; + } + String result = ICU.getDisplayLanguageNative(toString(), locale.toString()); if (result == null) { // TODO: do we need to do this, or does ICU do it for us? result = ICU.getDisplayLanguageNative(toString(), Locale.getDefault().toString()); 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 c78e534..b46432d 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 @@ -85,6 +85,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); @@ -732,7 +734,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; /** @@ -741,7 +743,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/OpenSSLCipherRSA.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLCipherRSA.java index a11ffa9..ddf2e0d 100644 --- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLCipherRSA.java +++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLCipherRSA.java @@ -110,16 +110,34 @@ public abstract class OpenSSLCipherRSA extends CipherSpi { @Override protected int engineGetBlockSize() { - return 0; + if (encrypting) { + return paddedBlockSizeBytes(); + } + return keySizeBytes(); } @Override protected int engineGetOutputSize(int inputLen) { + if (encrypting) { + return keySizeBytes(); + } + return paddedBlockSizeBytes(); + } + + private int paddedBlockSizeBytes() { + int paddedBlockSizeBytes = keySizeBytes(); + if (padding == NativeCrypto.RSA_PKCS1_PADDING) { + paddedBlockSizeBytes--; // for 0 prefix + paddedBlockSizeBytes -= 10; // PKCS1 padding header length + } + return paddedBlockSizeBytes; + } + + private int keySizeBytes() { if (key == null) { throw new IllegalStateException("cipher is not initialized"); } - - return buffer.length; + return NativeCrypto.RSA_size(this.key.getPkeyContext()); } @Override 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 54253da..09b086c 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 @@ -93,34 +93,34 @@ 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.SHA1WithRSA", OpenSSLSignature.SHA1RSA.class.getName()); + put("Alg.Alias.Signature.SHA1WithRSAEncryption", "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("Alg.Alias.Signature.2.16.840.1.101.3.4.2.1with1.2.840.113549.1.1.1", - "SHA256WithRSAEncryption"); + "SHA256WithRSA"); put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.1with1.2.840.113549.1.1.11", - "SHA256WithRSAEncryption"); + "SHA256WithRSA"); - 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.SHA384WithRSA", OpenSSLSignature.SHA384RSA.class.getName()); + put("Alg.Alias.Signature.SHA384WithRSAEncryption", "SHA384WithRSA"); + put("Alg.Alias.Signature.1.2.840.113549.1.1.12", "SHA384WithRSA"); put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.2with1.2.840.113549.1.1.1", - "SHA384WithRSAEncryption"); + "SHA384WithRSA"); - 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.SHA512WithRSA", OpenSSLSignature.SHA512RSA.class.getName()); + put("Alg.Alias.Signature.SHA512WithRSAEncryption", "SHA512WithRSA"); + put("Alg.Alias.Signature.1.2.840.113549.1.1.13", "SHA512WithRSA"); put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.3with1.2.840.113549.1.1.1", - "SHA512WithRSAEncryption"); + "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 8217fb5..1682df7 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,15 +214,65 @@ 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)); } @@ -198,7 +282,7 @@ public final class TrustManagerImpl implements X509TrustManager { ChainStrengthAnalyzer.check(newChain); 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 @@ -215,6 +299,8 @@ public final class TrustManagerImpl implements X509TrustManager { } catch (CertPathValidatorException e) { throw new CertificateException(e); } + + return wholeChain; } /** @@ -236,17 +322,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; @@ -275,15 +353,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 12739a5..d7d8b22 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 @@ -538,11 +538,11 @@ static bool arrayToBignum(JNIEnv* env, jbyteArray source, BIGNUM** dest) { /** * Converts an OpenSSL BIGNUM to a Java byte[] array. */ -static jbyteArray bignumToArray(JNIEnv* env, const BIGNUM* source) { - JNI_TRACE("bignumToArray(%p)", source); +static jbyteArray bignumToArray(JNIEnv* env, const BIGNUM* source, const char* sourceName) { + JNI_TRACE("bignumToArray(%p, %s)", source, sourceName); if (source == NULL) { - jniThrowNullPointerException(env, NULL); + jniThrowNullPointerException(env, sourceName); return NULL; } @@ -550,7 +550,7 @@ static jbyteArray bignumToArray(JNIEnv* env, const BIGNUM* source) { jbyteArray javaBytes = env->NewByteArray(len); ScopedByteArrayRW bytes(env, javaBytes); if (bytes.get() == NULL) { - JNI_TRACE("bignumToArray(%p) => NULL", source); + JNI_TRACE("bignumToArray(%p, %s) => NULL", source, sourceName); return NULL; } @@ -568,7 +568,7 @@ static jbyteArray bignumToArray(JNIEnv* env, const BIGNUM* source) { return NULL; } - JNI_TRACE("bignumToArray(%p) => %p", source, javaBytes); + JNI_TRACE("bignumToArray(%p, %s) => %p", source, sourceName, javaBytes); return javaBytes; } @@ -1111,6 +1111,26 @@ static void NativeCrypto_EVP_PKEY_free(JNIEnv*, jclass, jint pkeyRef) { } } +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[]) */ @@ -1381,13 +1401,13 @@ static jobjectArray NativeCrypto_get_RSA_public_params(JNIEnv* env, jclass, jint return NULL; } - jbyteArray n = bignumToArray(env, rsa->n); + jbyteArray n = bignumToArray(env, rsa->n, "n"); if (env->ExceptionCheck()) { return NULL; } env->SetObjectArrayElement(joa, 0, n); - jbyteArray e = bignumToArray(env, rsa->e); + jbyteArray e = bignumToArray(env, rsa->e, "e"); if (env->ExceptionCheck()) { return NULL; } @@ -1419,14 +1439,14 @@ static jobjectArray NativeCrypto_get_RSA_private_params(JNIEnv* env, jclass, jin return NULL; } - jbyteArray n = bignumToArray(env, rsa->n); + jbyteArray n = bignumToArray(env, rsa->n, "n"); if (env->ExceptionCheck()) { return NULL; } env->SetObjectArrayElement(joa, 0, n); if (rsa->e != NULL) { - jbyteArray e = bignumToArray(env, rsa->e); + jbyteArray e = bignumToArray(env, rsa->e, "e"); if (env->ExceptionCheck()) { return NULL; } @@ -1434,7 +1454,7 @@ static jobjectArray NativeCrypto_get_RSA_private_params(JNIEnv* env, jclass, jin } if (rsa->d != NULL) { - jbyteArray d = bignumToArray(env, rsa->d); + jbyteArray d = bignumToArray(env, rsa->d, "d"); if (env->ExceptionCheck()) { return NULL; } @@ -1442,7 +1462,7 @@ static jobjectArray NativeCrypto_get_RSA_private_params(JNIEnv* env, jclass, jin } if (rsa->p != NULL) { - jbyteArray p = bignumToArray(env, rsa->p); + jbyteArray p = bignumToArray(env, rsa->p, "p"); if (env->ExceptionCheck()) { return NULL; } @@ -1450,7 +1470,7 @@ static jobjectArray NativeCrypto_get_RSA_private_params(JNIEnv* env, jclass, jin } if (rsa->q != NULL) { - jbyteArray q = bignumToArray(env, rsa->q); + jbyteArray q = bignumToArray(env, rsa->q, "q"); if (env->ExceptionCheck()) { return NULL; } @@ -1458,7 +1478,7 @@ static jobjectArray NativeCrypto_get_RSA_private_params(JNIEnv* env, jclass, jin } if (rsa->dmp1 != NULL) { - jbyteArray dmp1 = bignumToArray(env, rsa->dmp1); + jbyteArray dmp1 = bignumToArray(env, rsa->dmp1, "dmp1"); if (env->ExceptionCheck()) { return NULL; } @@ -1466,7 +1486,7 @@ static jobjectArray NativeCrypto_get_RSA_private_params(JNIEnv* env, jclass, jin } if (rsa->dmq1 != NULL) { - jbyteArray dmq1 = bignumToArray(env, rsa->dmq1); + jbyteArray dmq1 = bignumToArray(env, rsa->dmq1, "dmq1"); if (env->ExceptionCheck()) { return NULL; } @@ -1474,7 +1494,7 @@ static jobjectArray NativeCrypto_get_RSA_private_params(JNIEnv* env, jclass, jin } if (rsa->iqmp != NULL) { - jbyteArray iqmp = bignumToArray(env, rsa->iqmp); + jbyteArray iqmp = bignumToArray(env, rsa->iqmp, "iqmp"); if (env->ExceptionCheck()) { return NULL; } @@ -1581,26 +1601,26 @@ static jobjectArray NativeCrypto_get_DSA_params(JNIEnv* env, jclass, jint pkeyRe return NULL; } - jbyteArray g = bignumToArray(env, dsa->g); + jbyteArray g = bignumToArray(env, dsa->g, "g"); if (env->ExceptionCheck()) { return NULL; } env->SetObjectArrayElement(joa, 0, g); - jbyteArray p = bignumToArray(env, dsa->p); + jbyteArray p = bignumToArray(env, dsa->p, "p"); if (env->ExceptionCheck()) { return NULL; } env->SetObjectArrayElement(joa, 1, p); - jbyteArray q = bignumToArray(env, dsa->q); + jbyteArray q = bignumToArray(env, dsa->q, "q"); if (env->ExceptionCheck()) { return NULL; } env->SetObjectArrayElement(joa, 2, q); if (dsa->pub_key != NULL) { - jbyteArray pub_key = bignumToArray(env, dsa->pub_key); + jbyteArray pub_key = bignumToArray(env, dsa->pub_key, "pub_key"); if (env->ExceptionCheck()) { return NULL; } @@ -1608,7 +1628,7 @@ static jobjectArray NativeCrypto_get_DSA_params(JNIEnv* env, jclass, jint pkeyRe } if (dsa->priv_key != NULL) { - jbyteArray priv_key = bignumToArray(env, dsa->priv_key); + jbyteArray priv_key = bignumToArray(env, dsa->priv_key, "priv_key"); if (env->ExceptionCheck()) { return NULL; } @@ -1741,19 +1761,19 @@ static jobjectArray NativeCrypto_EC_GROUP_get_curve(JNIEnv* env, jclass, jint gr return NULL; } - jbyteArray pArray = bignumToArray(env, p.get()); + jbyteArray pArray = bignumToArray(env, p.get(), "p"); if (env->ExceptionCheck()) { return NULL; } env->SetObjectArrayElement(joa, 0, pArray); - jbyteArray aArray = bignumToArray(env, a.get()); + jbyteArray aArray = bignumToArray(env, a.get(), "a"); if (env->ExceptionCheck()) { return NULL; } env->SetObjectArrayElement(joa, 1, aArray); - jbyteArray bArray = bignumToArray(env, b.get()); + jbyteArray bArray = bignumToArray(env, b.get(), "b"); if (env->ExceptionCheck()) { return NULL; } @@ -1781,7 +1801,7 @@ static jbyteArray NativeCrypto_EC_GROUP_get_order(JNIEnv* env, jclass, jint grou return NULL; } - jbyteArray orderArray = bignumToArray(env, order.get()); + jbyteArray orderArray = bignumToArray(env, order.get(), "order"); if (env->ExceptionCheck()) { return NULL; } @@ -1808,7 +1828,7 @@ static jbyteArray NativeCrypto_EC_GROUP_get_cofactor(JNIEnv* env, jclass, jint g return NULL; } - jbyteArray cofactorArray = bignumToArray(env, cofactor.get()); + jbyteArray cofactorArray = bignumToArray(env, cofactor.get(), "cofactor"); if (env->ExceptionCheck()) { return NULL; } @@ -2058,13 +2078,13 @@ static jobjectArray NativeCrypto_EC_POINT_get_affine_coordinates(JNIEnv* env, jc return NULL; } - jbyteArray xBytes = bignumToArray(env, x.get()); + jbyteArray xBytes = bignumToArray(env, x.get(), "x"); if (env->ExceptionCheck()) { return NULL; } env->SetObjectArrayElement(joa, 0, xBytes); - jbyteArray yBytes = bignumToArray(env, y.get()); + jbyteArray yBytes = bignumToArray(env, y.get(), "y"); if (env->ExceptionCheck()) { return NULL; } @@ -2127,7 +2147,7 @@ static jbyteArray NativeCrypto_EC_KEY_get_private_key(JNIEnv* env, jclass, jint const BIGNUM *privkey = EC_KEY_get0_private_key(eckey.get()); - jbyteArray privBytes = bignumToArray(env, privkey); + jbyteArray privBytes = bignumToArray(env, privkey, "privkey"); if (env->ExceptionCheck()) { JNI_TRACE("EC_KEY_get_private_key(%p) => threw error", pkey); return NULL; @@ -3265,12 +3285,15 @@ class AppData { static AppData* create() { UniquePtr<AppData> appData(new AppData()); if (pipe(appData.get()->fdsEmergency) == -1) { + ALOGE("AppData::create pipe(2) failed: %s", strerror(errno)); return NULL; } if (!setBlocking(appData.get()->fdsEmergency[0], false)) { + ALOGE("AppData::create fcntl(2) failed: %s", strerror(errno)); return NULL; } if (MUTEX_SETUP(appData.get()->mutex) == -1) { + ALOGE("pthread_mutex_init(3) failed: %s", strerror(errno)); return NULL; } return appData.release(); @@ -4756,7 +4779,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) { @@ -4835,7 +4858,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; } @@ -4887,11 +4910,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; } @@ -4915,7 +4938,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) { @@ -4955,8 +4978,9 @@ 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) { - JNI_TRACE("ssl=%p sslWrite buf=%p len=%d", ssl, buf, len); + int* sslReturnCode, int* sslErrorCode, int write_timeout_millis) { + JNI_TRACE("ssl=%p sslWrite buf=%p len=%d write_timeout_millis=%d", + ssl, buf, len, write_timeout_millis); if (len == 0) { // Don't bother doing anything in this case. @@ -5041,7 +5065,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; } @@ -5092,11 +5116,11 @@ 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", - ssl, fdObject, shc, b, offset, len); + JNI_TRACE("ssl=%p NativeCrypto_SSL_write fd=%p shc=%p b=%p offset=%d len=%d write_timeout_millis=%d", + ssl, fdObject, shc, b, offset, len, write_timeout_millis); if (ssl == NULL) { return; } @@ -5119,7 +5143,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: @@ -5435,6 +5459,7 @@ static JNINativeMethod sNativeCryptoMethods[] = { NATIVE_METHOD(NativeCrypto, EVP_PKEY_print_public, "(I)Ljava/lang/String;"), NATIVE_METHOD(NativeCrypto, EVP_PKEY_print_private, "(I)Ljava/lang/String;"), 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"), @@ -5527,7 +5552,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/io/InterruptedStreamTest.java b/luni/src/test/java/libcore/java/io/InterruptedStreamTest.java index e1f51bd..e46df5d 100755 --- a/luni/src/test/java/libcore/java/io/InterruptedStreamTest.java +++ b/luni/src/test/java/libcore/java/io/InterruptedStreamTest.java @@ -46,10 +46,16 @@ public final class InterruptedStreamTest extends TestCase { private Socket[] sockets; + @Override protected void setUp() throws Exception { + Thread.interrupted(); // clear interrupted bit + super.tearDown(); + } + @Override protected void tearDown() throws Exception { if (sockets != null) { sockets[0].close(); sockets[1].close(); + sockets = null; } Thread.interrupted(); // clear interrupted bit super.tearDown(); @@ -111,56 +117,66 @@ public final class InterruptedStreamTest extends TestCase { } private void testInterruptInputStream(final InputStream in) throws Exception { - interruptMeLater(); + Thread thread = interruptMeLater(); try { in.read(); fail(); } catch (InterruptedIOException expected) { + } finally { + waitForInterrupt(thread); } } private void testInterruptReader(final PipedReader reader) throws Exception { - interruptMeLater(); + Thread thread = interruptMeLater(); try { reader.read(); fail(); } catch (InterruptedIOException expected) { + } finally { + waitForInterrupt(thread); } } private void testInterruptReadableChannel(final ReadableByteChannel channel) throws Exception { - interruptMeLater(); + Thread thread = interruptMeLater(); try { channel.read(ByteBuffer.allocate(BUFFER_SIZE)); fail(); } catch (ClosedByInterruptException expected) { + } finally { + waitForInterrupt(thread); } } private void testInterruptOutputStream(final OutputStream out) throws Exception { - interruptMeLater(); + Thread thread = interruptMeLater(); try { // this will block when the receiving buffer fills up while (true) { out.write(new byte[BUFFER_SIZE]); } } catch (InterruptedIOException expected) { + } finally { + waitForInterrupt(thread); } } private void testInterruptWriter(final PipedWriter writer) throws Exception { - interruptMeLater(); + Thread thread = interruptMeLater(); try { // this will block when the receiving buffer fills up while (true) { writer.write(new char[BUFFER_SIZE]); } } catch (InterruptedIOException expected) { + } finally { + waitForInterrupt(thread); } } private void testInterruptWritableChannel(final WritableByteChannel channel) throws Exception { - interruptMeLater(); + Thread thread = interruptMeLater(); try { // this will block when the receiving buffer fills up while (true) { @@ -168,12 +184,14 @@ public final class InterruptedStreamTest extends TestCase { } } catch (ClosedByInterruptException expected) { } catch (ClosedChannelException expected) { + } finally { + waitForInterrupt(thread); } } - private void interruptMeLater() throws Exception { + private Thread interruptMeLater() throws Exception { final Thread toInterrupt = Thread.currentThread(); - new Thread(new Runnable () { + Thread thread = new Thread(new Runnable () { @Override public void run() { try { Thread.sleep(1000); @@ -181,6 +199,20 @@ public final class InterruptedStreamTest extends TestCase { } toInterrupt.interrupt(); } - }).start(); + }); + thread.start(); + return thread; + } + + private static void waitForInterrupt(Thread thread) throws Exception { + try { + thread.join(); + } catch (InterruptedException ignore) { + // There is currently a race between Thread.interrupt in + // interruptMeLater and Thread.join here. Most of the time + // we won't get an InterruptedException, but occasionally + // we do, so for now ignore this exception. + // http://b/6951157 + } } } 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/net/OldSocketTest.java b/luni/src/test/java/libcore/java/net/OldSocketTest.java index fda9557..033a7bf 100644 --- a/luni/src/test/java/libcore/java/net/OldSocketTest.java +++ b/luni/src/test/java/libcore/java/net/OldSocketTest.java @@ -38,7 +38,6 @@ import java.nio.channels.IllegalBlockingModeException; import java.nio.channels.SocketChannel; import java.security.Permission; import tests.support.Support_Configuration; -import tests.support.Support_PortManager; public class OldSocketTest extends OldSocketTestCase { @@ -115,17 +114,15 @@ public class OldSocketTest extends OldSocketTestCase { public void test_ConstructorLjava_lang_StringILjava_net_InetAddressI1() throws IOException { int sport = startServer("Cons String,I,InetAddress,I"); - int portNumber = Support_PortManager.getNextPort(); s = new Socket(InetAddress.getLocalHost().getHostName(), sport, - InetAddress.getLocalHost(), portNumber); + InetAddress.getLocalHost(), 0); assertTrue("Failed to create socket", s.getPort() == sport); } public void test_ConstructorLjava_lang_StringILjava_net_InetAddressI2() throws IOException { - int testPort = Support_PortManager.getNextPort(); - Socket s1 = new Socket("www.google.com", 80, null, testPort); + Socket s1 = new Socket("www.google.com", 80, null, 0); try { - Socket s2 = new Socket("www.google.com", 80, null, testPort); + Socket s2 = new Socket("www.google.com", 80, null, s1.getLocalPort()); try { s2.close(); } catch (IOException ignored) { @@ -162,10 +159,8 @@ public class OldSocketTest extends OldSocketTestCase { // Test for method java.net.Socket(java.net.InetAddress, int, // java.net.InetAddress, int) int sport = startServer("Cons InetAddress,I,InetAddress,I"); - int portNumber = Support_PortManager.getNextPort(); s = new Socket(InetAddress.getLocalHost().getHostName(), sport, - InetAddress.getLocalHost(), portNumber); - assertTrue("Failed to create socket", s.getLocalPort() == portNumber); + InetAddress.getLocalHost(), 0); } public void test_ConstructorLjava_net_InetAddressIZ() throws IOException { @@ -180,8 +175,7 @@ public class OldSocketTest extends OldSocketTestCase { public void test_close() throws IOException { // Test for method void java.net.Socket.close() int sport = startServer("SServer close"); - int portNumber = Support_PortManager.getNextPort(); - s = new Socket(InetAddress.getLocalHost(), sport, null, portNumber); + s = new Socket(InetAddress.getLocalHost(), sport, null, 0); try { s.setSoLinger(false, 100); } catch (IOException e) { @@ -199,8 +193,7 @@ public class OldSocketTest extends OldSocketTestCase { public void test_getInetAddress() throws IOException { // Test for method java.net.InetAddress java.net.Socket.getInetAddress() int sport = startServer("SServer getInetAddress"); - int portNumber = Support_PortManager.getNextPort(); - s = new Socket(InetAddress.getLocalHost(), sport, null, portNumber); + s = new Socket(InetAddress.getLocalHost(), sport, null, 0); assertTrue("Returned incorrect InetAddress", s.getInetAddress().equals( InetAddress.getLocalHost())); @@ -220,9 +213,7 @@ public class OldSocketTest extends OldSocketTestCase { public void test_getKeepAlive() { try { int sport = startServer("SServer getKeepAlive"); - int portNumber = Support_PortManager.getNextPort(); - Socket theSocket = new Socket(InetAddress.getLocalHost(), sport, - null, portNumber); + Socket theSocket = new Socket(InetAddress.getLocalHost(), sport, null, 0); theSocket.setKeepAlive(true); assertTrue("getKeepAlive false when it should be true", theSocket .getKeepAlive()); @@ -254,8 +245,7 @@ public class OldSocketTest extends OldSocketTestCase { // Test for method java.net.InetAddress // java.net.Socket.getLocalAddress() int sport = startServer("SServer getLocAddress"); - int portNumber = Support_PortManager.getNextPort(); - s = new Socket(InetAddress.getLocalHost(), sport, null, portNumber); + s = new Socket(InetAddress.getLocalHost(), sport, null, 0); assertEquals("Returned incorrect InetAddress", InetAddress.getLocalHost(), s.getLocalAddress()); @@ -271,10 +261,10 @@ public class OldSocketTest extends OldSocketTestCase { public void test_getLocalPort() throws IOException { // Test for method int java.net.Socket.getLocalPort() int sport = startServer("SServer getLocalPort"); - int portNumber = Support_PortManager.getNextPort(); s = new Socket(InetAddress.getLocalHost().getHostName(), sport, - InetAddress.getLocalHost(), portNumber); - assertTrue("Returned incorrect port", s.getLocalPort() == portNumber); + InetAddress.getLocalHost(), 0); + // There's nothing we can usefully assert about the kernel-assigned port. + s.getLocalPort(); } @SuppressWarnings("deprecation") @@ -282,15 +272,13 @@ public class OldSocketTest extends OldSocketTestCase { // Test for method java.io.OutputStream // java.net.Socket.getOutputStream() int sport = startServer("SServer getOutputStream"); - int portNumber = Support_PortManager.getNextPort(); - s = new Socket(InetAddress.getLocalHost(), sport, null, portNumber); + s = new Socket(InetAddress.getLocalHost(), sport); java.io.OutputStream os = s.getOutputStream(); assertNotNull("Failed to get stream", os); os.write(1); s.close(); // Regression test for harmony-2934 - s = new Socket("127.0.0.1", Support_PortManager.getNextPort(), - false); + s = new Socket("127.0.0.1", sport, false); OutputStream o = s.getOutputStream(); o.write(1); try { @@ -301,8 +289,7 @@ public class OldSocketTest extends OldSocketTestCase { s.close(); // Regression test for harmony-2942 - s = new Socket("0.0.0.0", Support_PortManager.getNextPort(), - false); + s = new Socket("0.0.0.0", sport, false); o = s.getOutputStream(); o.write(1); try { @@ -316,18 +303,15 @@ public class OldSocketTest extends OldSocketTestCase { public void test_getPort() throws IOException { // Test for method int java.net.Socket.getPort() int sport = startServer("SServer getPort"); - int portNumber = Support_PortManager.getNextPort(); - s = new Socket(InetAddress.getLocalHost(), sport, null, portNumber); - assertTrue("Returned incorrect port" + s.getPort(), - s.getPort() == sport); + s = new Socket(InetAddress.getLocalHost(), sport, null, 0); + assertTrue("Returned incorrect port" + s.getPort(), s.getPort() == sport); } public void test_getSoLinger() { // Test for method int java.net.Socket.getSoLinger() int sport = startServer("SServer getSoLinger"); try { - int portNumber = Support_PortManager.getNextPort(); - s = new Socket(InetAddress.getLocalHost(), sport, null, portNumber); + s = new Socket(InetAddress.getLocalHost(), sport, null, 0); s.setSoLinger(true, 200); assertEquals("Returned incorrect linger", 200, s.getSoLinger()); ensureExceptionThrownIfOptionIsUnsupportedOnOS(SO_LINGER); @@ -337,8 +321,7 @@ public class OldSocketTest extends OldSocketTestCase { } try { - int portNumber = Support_PortManager.getNextPort(); - s = new Socket(InetAddress.getLocalHost(), sport, null, portNumber); + s = new Socket(InetAddress.getLocalHost(), sport, null, 0); s.close(); try { s.getSoLinger(); @@ -354,9 +337,7 @@ public class OldSocketTest extends OldSocketTestCase { public void test_getReceiveBufferSize() { try { int sport = startServer("SServer getReceiveBufferSize"); - int portNumber = Support_PortManager.getNextPort(); - s = new Socket(InetAddress.getLocalHost().getHostName(), sport, - null, portNumber); + s = new Socket(InetAddress.getLocalHost().getHostName(), sport, null, 0); s.setReceiveBufferSize(130); assertTrue("Incorrect buffer size", s.getReceiveBufferSize() >= 130); ensureExceptionThrownIfOptionIsUnsupportedOnOS(SO_RCVBUF); @@ -381,9 +362,7 @@ public class OldSocketTest extends OldSocketTestCase { public void test_getSendBufferSize() { int sport = startServer("SServer setSendBufferSize"); try { - int portNumber = Support_PortManager.getNextPort(); - s = new Socket(InetAddress.getLocalHost().getHostName(), sport, - null, portNumber); + s = new Socket(InetAddress.getLocalHost().getHostName(), sport, null, 0); s.setSendBufferSize(134); assertTrue("Incorrect buffer size", s.getSendBufferSize() >= 134); ensureExceptionThrownIfOptionIsUnsupportedOnOS(SO_SNDBUF); @@ -391,8 +370,7 @@ public class OldSocketTest extends OldSocketTestCase { handleException(e, SO_SNDBUF); } try { - int portNumber = Support_PortManager.getNextPort(); - s = new Socket(InetAddress.getLocalHost(), sport, null, portNumber); + s = new Socket(InetAddress.getLocalHost(), sport, null, 0); s.close(); try { s.getSendBufferSize(); @@ -430,8 +408,7 @@ public class OldSocketTest extends OldSocketTestCase { // Test for method boolean java.net.Socket.getTcpNoDelay() int sport = startServer("SServer getTcpNoDelay"); try { - int portNumber = Support_PortManager.getNextPort(); - s = new Socket(InetAddress.getLocalHost(), sport, null, portNumber); + s = new Socket(InetAddress.getLocalHost(), sport, null, 0); boolean bool = !s.getTcpNoDelay(); s.setTcpNoDelay(bool); assertTrue("Failed to get no delay setting: " + s.getTcpNoDelay(), @@ -442,8 +419,7 @@ public class OldSocketTest extends OldSocketTestCase { } try { - int portNumber = Support_PortManager.getNextPort(); - s = new Socket(InetAddress.getLocalHost(), sport, null, portNumber); + s = new Socket(InetAddress.getLocalHost(), sport, null, 0); s.close(); try { s.getTcpNoDelay(); @@ -461,9 +437,7 @@ public class OldSocketTest extends OldSocketTestCase { // crashed machines. Just make sure we can set it try { int sport = startServer("SServer setKeepAlive"); - int portNumber = Support_PortManager.getNextPort(); - Socket theSocket = new Socket(InetAddress.getLocalHost(), sport, - null, portNumber); + Socket theSocket = new Socket(InetAddress.getLocalHost(), sport, null, 0); theSocket.setKeepAlive(true); theSocket.setKeepAlive(false); ensureExceptionThrownIfOptionIsUnsupportedOnOS(SO_KEEPALIVE); @@ -509,8 +483,7 @@ public class OldSocketTest extends OldSocketTestCase { public void test_setSendBufferSizeI() { try { int sport = startServer("SServer setSendBufferSizeI"); - int portNumber = Support_PortManager.getNextPort(); - s = new Socket(InetAddress.getLocalHost(), sport, null, portNumber); + s = new Socket(InetAddress.getLocalHost(), sport, null, 0); s.setSendBufferSize(134); assertTrue("Incorrect buffer size", s.getSendBufferSize() >= 134); ensureExceptionThrownIfOptionIsUnsupportedOnOS(SO_SNDBUF); @@ -533,8 +506,7 @@ public class OldSocketTest extends OldSocketTestCase { public void test_setReceiveBufferSizeI() { try { int sport = startServer("SServer setReceiveBufferSizeI"); - int portNumber = Support_PortManager.getNextPort(); - s = new Socket(InetAddress.getLocalHost(), sport, null, portNumber); + s = new Socket(InetAddress.getLocalHost(), sport, null, 0); s.setReceiveBufferSize(130); assertTrue("Incorrect buffer size", s.getReceiveBufferSize() >= 130); ensureExceptionThrownIfOptionIsUnsupportedOnOS(SO_RCVBUF); @@ -558,8 +530,7 @@ public class OldSocketTest extends OldSocketTestCase { // Test for method void java.net.Socket.setSoLinger(boolean, int) try { int sport = startServer("SServer setSoLingerZI"); - int portNumber = Support_PortManager.getNextPort(); - s = new Socket(InetAddress.getLocalHost(), sport, null, portNumber); + s = new Socket(InetAddress.getLocalHost(), sport, null, 0); s.setSoLinger(true, 500); assertEquals("Set incorrect linger", 500, s.getSoLinger()); ensureExceptionThrownIfOptionIsUnsupportedOnOS(SO_LINGER); @@ -584,8 +555,7 @@ public class OldSocketTest extends OldSocketTestCase { // Test for method void java.net.Socket.setTcpNoDelay(boolean) try { int sport = startServer("SServer setTcpNoDelayZ"); - int portNumber = Support_PortManager.getNextPort(); - s = new Socket(InetAddress.getLocalHost(), sport, null, portNumber); + s = new Socket(InetAddress.getLocalHost(), sport, null, 0); boolean bool; s.setTcpNoDelay(bool = !s.getTcpNoDelay()); assertTrue("Failed to set no delay setting: " + s.getTcpNoDelay(), @@ -610,9 +580,8 @@ public class OldSocketTest extends OldSocketTestCase { public void test_toString() throws IOException { // Test for method java.lang.String java.net.Socket.toString() int sport = startServer("SServer toString"); - int portNumber = Support_PortManager.getNextPort(); s = new Socket(InetAddress.getLocalHost().getHostName(), sport, - InetAddress.getLocalHost(), portNumber); + InetAddress.getLocalHost(), 0); assertEquals("Socket[address=" + InetAddress.getLocalHost() + ",port=" + s.getPort() + ",localPort=" + s.getLocalPort() + "]", s.toString()); } @@ -620,9 +589,8 @@ public class OldSocketTest extends OldSocketTestCase { // AndroidOnly: RI returns wrong value for EOF public void test_shutdownInput() throws Exception { InetAddress addr = InetAddress.getLocalHost(); - int port = Support_PortManager.getNextPort(); - ServerSocket serverSocket = new ServerSocket(port, 5, addr); - Socket theSocket = new Socket(addr, port); + ServerSocket serverSocket = new ServerSocket(0, 5, addr); + Socket theSocket = new Socket(addr, serverSocket.getLocalPort()); Socket servSock = serverSocket.accept(); InputStream theInput = theSocket.getInputStream(); @@ -656,10 +624,8 @@ public class OldSocketTest extends OldSocketTestCase { } public void test_shutdownOutput() throws IOException { - InetAddress addr = InetAddress.getLocalHost(); - int port = Support_PortManager.getNextPort(); - ServerSocket serverSocket = new ServerSocket(port, 5, addr); - Socket theSocket = new Socket(addr, port); + ServerSocket serverSocket = new ServerSocket(0, 5); + Socket theSocket = new Socket(serverSocket.getInetAddress(), serverSocket.getLocalPort()); Socket servSock = serverSocket.accept(); InputStream theInput = theSocket.getInputStream(); @@ -692,17 +658,9 @@ public class OldSocketTest extends OldSocketTestCase { // set up server connect and then validate that we get the right // response for the local address int sport = startServer("SServer getLocSocketAddress"); - int portNumber = Support_PortManager.getNextPort(); - s = new Socket(InetAddress.getLocalHost(), sport, null, portNumber); - assertTrue( - "Returned incorrect InetSocketAddress(1):" - + s.getLocalSocketAddress().toString() - + "Expected: " - + (new InetSocketAddress(InetAddress.getLocalHost(), - portNumber)).toString(), s - .getLocalSocketAddress().equals( - new InetSocketAddress(InetAddress - .getLocalHost(), portNumber))); + s = new Socket(InetAddress.getLocalHost(), sport, null, 0); + assertEquals(new InetSocketAddress(InetAddress.getLocalHost(), s.getLocalPort()), + s.getLocalSocketAddress()); s.close(); // now create a socket that is not bound and validate we get the @@ -713,21 +671,12 @@ public class OldSocketTest extends OldSocketTestCase { theSocket.getLocalSocketAddress()); // now bind the socket and make sure we get the right answer - portNumber = Support_PortManager.getNextPort(); - theSocket.bind(new InetSocketAddress(InetAddress.getLocalHost(), - portNumber)); - assertTrue( - "Returned incorrect InetSocketAddress(2):" - + theSocket.getLocalSocketAddress().toString() - + "Expected: " - + (new InetSocketAddress(InetAddress.getLocalHost(), - portNumber)).toString(), theSocket - .getLocalSocketAddress().equals( - new InetSocketAddress(InetAddress - .getLocalHost(), portNumber))); + theSocket.bind(new InetSocketAddress(InetAddress.getLocalHost(), 0)); + assertEquals(new InetSocketAddress(InetAddress.getLocalHost(), theSocket.getLocalPort()), + theSocket.getLocalSocketAddress()); theSocket.close(); - // now validate that behaviour when the any address is returned + // now validate that behavior when the any address is returned s = new Socket(); s.bind(new InetSocketAddress(InetAddress.getByName("0.0.0.0"), 0)); @@ -747,8 +696,7 @@ public class OldSocketTest extends OldSocketTestCase { // set up server connect and then validate that we get the right // response for the remote address int sport = startServer("SServer getLocRemoteAddress"); - int portNumber = Support_PortManager.getNextPort(); - s = new Socket(InetAddress.getLocalHost(), sport, null, portNumber); + s = new Socket(InetAddress.getLocalHost(), sport, null, 0); assertTrue("Returned incorrect InetSocketAddress(1):" + s.getLocalSocketAddress().toString(), s.getRemoteSocketAddress() @@ -760,9 +708,7 @@ public class OldSocketTest extends OldSocketTestCase { // now create one that is not connect and validate that we get the // right answer Socket theSocket = new Socket(); - portNumber = Support_PortManager.getNextPort(); - theSocket.bind(new InetSocketAddress(InetAddress.getLocalHost(), - portNumber)); + theSocket.bind(new InetSocketAddress(InetAddress.getLocalHost(), 0)); assertNull("Returned incorrect InetSocketAddress -unconnected socket:" + "Expected: NULL", theSocket.getRemoteSocketAddress()); @@ -781,10 +727,8 @@ public class OldSocketTest extends OldSocketTestCase { } public void test_isBound() throws IOException { - InetAddress addr = InetAddress.getLocalHost(); - int port = Support_PortManager.getNextPort(); - ServerSocket serverSocket = new ServerSocket(port, 5, addr); - Socket theSocket = new Socket(addr, port); + ServerSocket serverSocket = new ServerSocket(0, 5); + Socket theSocket = new Socket(serverSocket.getInetAddress(), serverSocket.getLocalPort()); Socket servSock = serverSocket.accept(); assertTrue("Socket indicated not bound when it should be (1)", theSocket.isBound()); @@ -793,14 +737,11 @@ public class OldSocketTest extends OldSocketTestCase { // now do it with the new constructors and revalidate. Connect causes // the socket to be bound - InetSocketAddress theAddress = new InetSocketAddress(InetAddress - .getLocalHost(), Support_PortManager.getNextPort()); theSocket = new Socket(); assertFalse("Socket indicated bound when it was not (2)", theSocket .isBound()); - serverSocket = new ServerSocket(); - serverSocket.bind(theAddress); - theSocket.connect(theAddress); + serverSocket = new ServerSocket(0, 5); + theSocket.connect(serverSocket.getLocalSocketAddress()); servSock = serverSocket.accept(); assertTrue("Socket indicated not bound when it should be (2)", theSocket.isBound()); @@ -808,12 +749,10 @@ public class OldSocketTest extends OldSocketTestCase { serverSocket.close(); // now test when we bind explicitly - InetSocketAddress theLocalAddress = new InetSocketAddress(InetAddress - .getLocalHost(), Support_PortManager.getNextPort()); theSocket = new Socket(); assertFalse("Socket indicated bound when it was not (3)", theSocket .isBound()); - theSocket.bind(theLocalAddress); + theSocket.bind(null); assertTrue("Socket indicated not bound when it should be (3a)", theSocket.isBound()); theSocket.close(); @@ -822,10 +761,8 @@ public class OldSocketTest extends OldSocketTestCase { } public void test_isConnected() throws IOException { - InetAddress addr = InetAddress.getLocalHost(); - int port = Support_PortManager.getNextPort(); - ServerSocket serverSocket = new ServerSocket(port, 5, addr); - Socket theSocket = new Socket(addr, port); + ServerSocket serverSocket = new ServerSocket(0, 5); + Socket theSocket = new Socket(serverSocket.getInetAddress(), serverSocket.getLocalPort()); Socket servSock = serverSocket.accept(); assertTrue("Socket indicated not connected when it should be", theSocket.isConnected()); @@ -833,14 +770,11 @@ public class OldSocketTest extends OldSocketTestCase { serverSocket.close(); // now do it with the new constructors and revalidate - InetSocketAddress theAddress = new InetSocketAddress(InetAddress - .getLocalHost(), Support_PortManager.getNextPort()); theSocket = new Socket(); assertFalse("Socket indicated connected when it was not", theSocket .isConnected()); - serverSocket = new ServerSocket(); - serverSocket.bind(theAddress); - theSocket.connect(theAddress); + serverSocket = new ServerSocket(0, 5); + theSocket.connect(serverSocket.getLocalSocketAddress()); servSock = serverSocket.accept(); assertTrue("Socket indicated not connected when it should be", theSocket.isConnected()); @@ -849,10 +783,8 @@ public class OldSocketTest extends OldSocketTestCase { } public void test_isClosed() throws IOException { - InetAddress addr = InetAddress.getLocalHost(); - int port = Support_PortManager.getNextPort(); - ServerSocket serverSocket = new ServerSocket(port, 5, addr); - Socket theSocket = new Socket(addr, port); + ServerSocket serverSocket = new ServerSocket(0, 5); + Socket theSocket = new Socket(serverSocket.getInetAddress(), serverSocket.getLocalPort()); Socket servSock = serverSocket.accept(); // validate isClosed returns expected values @@ -862,7 +794,7 @@ public class OldSocketTest extends OldSocketTestCase { assertTrue("Socket should indicate it is closed(1):", theSocket .isClosed()); - theSocket = new Socket(addr, port); + theSocket = new Socket(serverSocket.getInetAddress(), serverSocket.getLocalPort()); assertFalse("Socket should indicate it is not closed(2):", theSocket .isClosed()); theSocket.close(); @@ -891,7 +823,7 @@ public class OldSocketTest extends OldSocketTestCase { try { theSocket.bind(new InetSocketAddress(InetAddress .getByAddress(Support_Configuration.nonLocalAddressBytes), - Support_PortManager.getNextPort())); + 80)); fail("No exception when binding to bad address:" + theSocket.getLocalSocketAddress().toString()); } catch (IOException ex) { @@ -900,39 +832,21 @@ public class OldSocketTest extends OldSocketTestCase { // now create a socket that is not bound and then bind it theSocket = new Socket(); - int portNumber = Support_PortManager.getNextPort(); theSocket.bind(new InetSocketAddress(InetAddress.getLocalHost(), - portNumber)); + 0)); // validate that the localSocketAddress reflects the address we // bound to - assertTrue( - "Local address not correct after bind:" - + theSocket.getLocalSocketAddress().toString() - + " Expected: " - + (new InetSocketAddress(InetAddress.getLocalHost(), - portNumber)).toString(), theSocket - .getLocalSocketAddress().equals( - new InetSocketAddress(InetAddress - .getLocalHost(), portNumber))); + assertEquals(new InetSocketAddress(InetAddress.getLocalHost(), theSocket.getLocalPort()), + theSocket.getLocalSocketAddress()); // make sure we can now connect and that connections appear to come // from the address we bound to. - InetSocketAddress theAddress = new InetSocketAddress(InetAddress - .getLocalHost(), Support_PortManager.getNextPort()); - ServerSocket serverSocket = new ServerSocket(); - serverSocket.bind(theAddress); - theSocket.connect(theAddress); + ServerSocket serverSocket = new ServerSocket(0, 5); + theSocket.connect(serverSocket.getLocalSocketAddress()); Socket servSock = serverSocket.accept(); - assertTrue( - "Returned Remote address from server connected to does not match expected local address:" - + servSock.getRemoteSocketAddress().toString() - + " Expected: " - + (new InetSocketAddress(InetAddress.getLocalHost(), - portNumber)).toString(), servSock - .getRemoteSocketAddress().equals( - new InetSocketAddress(InetAddress - .getLocalHost(), portNumber))); + assertEquals(new InetSocketAddress(InetAddress.getLocalHost(), theSocket.getLocalPort()), + servSock.getRemoteSocketAddress()); theSocket.close(); servSock.close(); serverSocket.close(); @@ -951,10 +865,8 @@ public class OldSocketTest extends OldSocketTestCase { theSocket = new Socket(); Socket theSocket2 = new Socket(); try { - theAddress = new InetSocketAddress(InetAddress.getLocalHost(), - Support_PortManager.getNextPort()); - theSocket.bind(theAddress); - theSocket2.bind(theAddress); + theSocket.bind(null); + theSocket2.bind(theSocket.getLocalSocketAddress()); fail("No exception binding to address that is not available"); } catch (IOException ex) { } @@ -1020,7 +932,7 @@ public class OldSocketTest extends OldSocketTestCase { } // start by validating the error checks - int portNumber = Support_PortManager.getNextPort(); + int portNumber = 0; Socket theSocket = null; ServerSocket serverSocket = null; SocketAddress theAddress = null; @@ -1084,17 +996,8 @@ public class OldSocketTest extends OldSocketTestCase { // now validate that we can actually connect when somebody is listening theSocket = new Socket(); - serverSocket = new ServerSocket(); - serverSocket.bind(theAddress); - theSocket.connect(theAddress); - theSocket.close(); - serverSocket.close(); - - // now validate that we can actually connect when somebody is listening - theSocket = new Socket(); - serverSocket = new ServerSocket(); - serverSocket.bind(theAddress); - theSocket.connect(theAddress); + serverSocket = new ServerSocket(0, 5); + theSocket.connect(serverSocket.getLocalSocketAddress()); // validate that when a socket is connected that it answers // correctly to related queries @@ -1119,10 +1022,9 @@ public class OldSocketTest extends OldSocketTestCase { // are already connected try { theSocket = new Socket(); - serverSocket = new ServerSocket(); - serverSocket.bind(theAddress); - theSocket.connect(theAddress); - theSocket.connect(theAddress); + serverSocket = new ServerSocket(0, 5); + theSocket.connect(serverSocket.getLocalSocketAddress()); + theSocket.connect(serverSocket.getLocalSocketAddress()); theSocket.close(); serverSocket.close(); fail("No exception when we try to connect on a connected socket: "); @@ -1145,9 +1047,8 @@ public class OldSocketTest extends OldSocketTestCase { // now validate that connected socket can be used to read/write theSocket = new Socket(); - serverSocket = new ServerSocket(); - serverSocket.bind(theAddress); - theSocket.connect(theAddress); + serverSocket = new ServerSocket(0, 5); + theSocket.connect(serverSocket.getLocalSocketAddress()); Socket servSock = serverSocket.accept(); InputStream theInput = theSocket.getInputStream(); OutputStream theOutput = servSock.getOutputStream(); @@ -1197,10 +1098,8 @@ public class OldSocketTest extends OldSocketTestCase { SocketChannel channel = SocketChannel.open(); channel.configureBlocking(false); Socket socket = channel.socket(); - int port = Support_PortManager.getNextPort(); try { - socket.connect( new InetSocketAddress(InetAddress.getLocalHost(), - Support_PortManager.getNextPort())); + socket.connect(serverSocket.getLocalSocketAddress()); fail("IllegalBlockingModeException was not thrown."); } catch (IllegalBlockingModeException expected) { } @@ -1263,28 +1162,14 @@ public class OldSocketTest extends OldSocketTestCase { } // start by validating the error checks - int portNumber = Support_PortManager.getNextPort(); - Socket theSocket = null; - ServerSocket serverSocket = null; - SocketAddress theAddress = null; - SocketAddress nonConnectableAddress = null; - SocketAddress nonReachableAddress = null; - SocketAddress nonListeningAddress = null; - SocketAddress invalidType = null; byte[] theBytes = { 0, 0, 0, 0 }; + SocketAddress theAddress = new InetSocketAddress(InetAddress.getLocalHost(), 0); + SocketAddress nonConnectableAddress = new InetSocketAddress(InetAddress.getByAddress(theBytes), 0); + SocketAddress nonReachableAddress = new InetSocketAddress(InetAddress.getByName(Support_Configuration.ResolvedNotExistingHost), 0); + SocketAddress invalidType = new mySocketAddress(); - theAddress = new InetSocketAddress(InetAddress.getLocalHost(), - portNumber); - nonConnectableAddress = new InetSocketAddress(InetAddress - .getByAddress(theBytes), portNumber); - nonReachableAddress = new InetSocketAddress(InetAddress - .getByName(Support_Configuration.ResolvedNotExistingHost), - portNumber); - // make sure we get another port - Thread.sleep(7000); - nonListeningAddress = new InetSocketAddress(InetAddress.getLocalHost(), - Support_PortManager.getNextPort()); - invalidType = new mySocketAddress(); + Socket theSocket = null; + ServerSocket serverSocket = null; try { theSocket = new Socket(); @@ -1340,9 +1225,8 @@ public class OldSocketTest extends OldSocketTestCase { // now validate that we can actually connect when somebody is listening theSocket = new Socket(); - serverSocket = new ServerSocket(); - serverSocket.bind(theAddress); - theSocket.connect(theAddress, 0); + serverSocket = new ServerSocket(0, 5); + theSocket.connect(serverSocket.getLocalSocketAddress()); theSocket.close(); serverSocket.close(); @@ -1350,7 +1234,7 @@ public class OldSocketTest extends OldSocketTestCase { // an address on which nobody is listening try { theSocket = new Socket(); - theSocket.connect(nonListeningAddress, 100000); + theSocket.connect(new InetSocketAddress(InetAddress.getLocalHost(), 80), 100000); theSocket.close(); fail("No exception when connecting to address nobody listening on: "); } catch (Exception e) { @@ -1390,12 +1274,9 @@ public class OldSocketTest extends OldSocketTestCase { } // now validate that we can actually connect when somebody is listening - new InetSocketAddress(InetAddress.getLocalHost(), Support_PortManager - .getNextPort()); theSocket = new Socket(); - serverSocket = new ServerSocket(); - serverSocket.bind(theAddress); - theSocket.connect(theAddress, 100000); + serverSocket = new ServerSocket(0, 5); + theSocket.connect(serverSocket.getLocalSocketAddress()); // validate that when a socket is connected that it answers // correctly to related queries @@ -1419,8 +1300,6 @@ public class OldSocketTest extends OldSocketTestCase { // now validate that we get the right exception if we connect when we // are already connected try { - new InetSocketAddress(InetAddress.getLocalHost(), - Support_PortManager.getNextPort()); theSocket = new Socket(); serverSocket = new ServerSocket(); serverSocket.bind(theAddress); @@ -1447,12 +1326,9 @@ public class OldSocketTest extends OldSocketTestCase { } // now validate that connected socket can be used to read/write - new InetSocketAddress(InetAddress.getLocalHost(), Support_PortManager - .getNextPort()); theSocket = new Socket(); - serverSocket = new ServerSocket(); - serverSocket.bind(theAddress); - theSocket.connect(theAddress, 100000); + serverSocket = new ServerSocket(0, 5); + theSocket.connect(serverSocket.getLocalSocketAddress()); Socket servSock = serverSocket.accept(); InputStream theInput = theSocket.getInputStream(); OutputStream theOutput = servSock.getOutputStream(); @@ -1515,10 +1391,8 @@ public class OldSocketTest extends OldSocketTestCase { SocketChannel channel = SocketChannel.open(); channel.configureBlocking(false); Socket socket = channel.socket(); - int port = Support_PortManager.getNextPort(); try { - socket.connect( new InetSocketAddress(InetAddress.getLocalHost(), - Support_PortManager.getNextPort()), port); + socket.connect(serverSocket.getLocalSocketAddress()); fail("IllegalBlockingModeException was not thrown."); } catch (IllegalBlockingModeException expected) { } @@ -1526,12 +1400,9 @@ public class OldSocketTest extends OldSocketTestCase { } public void test_isInputShutdown() throws IOException { - InetSocketAddress theAddress = new InetSocketAddress(InetAddress - .getLocalHost(), Support_PortManager.getNextPort()); Socket theSocket = new Socket(); - ServerSocket serverSocket = new ServerSocket(); - serverSocket.bind(theAddress); - theSocket.connect(theAddress); + ServerSocket serverSocket = new ServerSocket(0, 5); + theSocket.connect(serverSocket.getLocalSocketAddress()); Socket servSock = serverSocket.accept(); InputStream theInput = theSocket.getInputStream(); OutputStream theOutput = servSock.getOutputStream(); @@ -1559,12 +1430,9 @@ public class OldSocketTest extends OldSocketTestCase { } public void test_isOutputShutdown() throws IOException { - InetSocketAddress theAddress = new InetSocketAddress(InetAddress - .getLocalHost(), Support_PortManager.getNextPort()); Socket theSocket = new Socket(); - ServerSocket serverSocket = new ServerSocket(); - serverSocket.bind(theAddress); - theSocket.connect(theAddress); + ServerSocket serverSocket = new ServerSocket(0, 5); + theSocket.connect(serverSocket.getLocalSocketAddress()); Socket servSock = serverSocket.accept(); InputStream theInput = theSocket.getInputStream(); OutputStream theOutput = servSock.getOutputStream(); @@ -1591,18 +1459,14 @@ public class OldSocketTest extends OldSocketTestCase { } - public void test_setReuseAddressZ() { + public void test_setReuseAddressZ() throws Exception { try { InetAddress allAddresses[] = InetAddress.getAllByName(InetAddress .getLocalHost().getHostName()); if (allAddresses.length > 1) { - InetSocketAddress theAddress = new InetSocketAddress( - InetAddress.getLocalHost(), Support_PortManager - .getNextPort()); - ServerSocket serverSocket = new ServerSocket(); - serverSocket.bind(theAddress); + ServerSocket serverSocket = new ServerSocket(0, 5); // try to bind to port address that is already in use with // reuseAddress = false. @@ -1612,17 +1476,15 @@ public class OldSocketTest extends OldSocketTestCase { // what the expected result is. It seems that on linux // platforms we also don't get an exception. InetSocketAddress theLocalAddress = new InetSocketAddress( - (InetAddress) allAddresses[1], Support_PortManager - .getNextPort()); + (InetAddress) allAddresses[1], 0); InetSocketAddress theOtherLocalAddress = new InetSocketAddress( - (InetAddress) allAddresses[0], theLocalAddress - .getPort()); + (InetAddress) allAddresses[0], theLocalAddress.getPort()); Socket theSocket = new Socket(); theSocket.setReuseAddress(false); theSocket.bind(theLocalAddress); Socket theSocket2 = null; String platform = System.getProperty("os.name"); - try { + theSocket2 = new Socket(); theSocket2.setReuseAddress(false); theSocket2.bind(theOtherLocalAddress); @@ -1639,69 +1501,34 @@ public class OldSocketTest extends OldSocketTestCase { + ":" + theOtherLocalAddress.toString()); } - } catch (IOException ex) { - if ((platform.startsWith("Linux")) - || ((platform.startsWith("Windows")) && ((((InetAddress) allAddresses[0]) instanceof Inet4Address) && (((InetAddress) allAddresses[1]) instanceof Inet4Address)))) { - fail("Got unexpected exception when binding with setReuseAddress false on windows platform:" - + theAddress.toString() + ":" + ex.toString()); - } - } theSocket.close(); theSocket2.close(); // try to bind to port that is already in use with reuseAddress // = true - theLocalAddress = new InetSocketAddress( - (InetAddress) allAddresses[0], Support_PortManager - .getNextPort()); - theOtherLocalAddress = new InetSocketAddress( - (InetAddress) allAddresses[1], theLocalAddress - .getPort()); + theLocalAddress = new InetSocketAddress((InetAddress) allAddresses[0], 0); theSocket = new Socket(); theSocket.setReuseAddress(true); theSocket.bind(theLocalAddress); - try { - theSocket2 = new Socket(); - theSocket2.setReuseAddress(true); - theSocket2.bind(theOtherLocalAddress); - theSocket2.close(); - } catch (IOException ex) { - fail("IOException when setReuseAddress is true and we bind :" - + ex.toString()); - } + theSocket2 = new Socket(); + theSocket2.setReuseAddress(true); + theOtherLocalAddress = new InetSocketAddress((InetAddress) allAddresses[1], theSocket.getLocalPort()); + theSocket2.bind(theOtherLocalAddress); + theSocket2.close(); theSocket.close(); serverSocket.close(); // try with default behavior which should be the same on all // platforms - theLocalAddress = new InetSocketAddress( - (InetAddress) allAddresses[0], Support_PortManager - .getNextPort()); - theOtherLocalAddress = new InetSocketAddress( - (InetAddress) allAddresses[1], theLocalAddress - .getPort()); + theLocalAddress = new InetSocketAddress((InetAddress) allAddresses[0], 0); theSocket = new Socket(); theSocket.bind(theLocalAddress); - try { - theSocket2 = new Socket(); - theSocket2.bind(theOtherLocalAddress); - theSocket2.close(); - if ((!platform.startsWith("Linux")) - && ((!platform.startsWith("Windows")) || !((((InetAddress) allAddresses[0]) instanceof Inet4Address) && (((InetAddress) allAddresses[1]) instanceof Inet4Address)))) { - fail("No exception when setReuseAddress is default and we bind:" - + theLocalAddress.toString() - + ":" - + theOtherLocalAddress.toString()); - } - } catch (IOException ex) { - if ((platform.startsWith("Linux")) - || ((platform.startsWith("Windows")) && ((((InetAddress) allAddresses[0]) instanceof Inet4Address) && (((InetAddress) allAddresses[1]) instanceof Inet4Address)))) { - fail("Got unexpected exception when binding with setReuseAddress default on windows platform:" - + theAddress.toString() + ":" + ex.toString()); - } - } + theSocket2 = new Socket(); + theOtherLocalAddress = new InetSocketAddress((InetAddress) allAddresses[1], theSocket.getLocalPort()); + theSocket2.bind(theOtherLocalAddress); + theSocket2.close(); theSocket.close(); serverSocket.close(); @@ -1754,8 +1581,6 @@ public class OldSocketTest extends OldSocketTestCase { public void test_setOOBInlineZ() { // mostly tested in getOOBInline. Just set to make sure call works ok try { - new InetSocketAddress(InetAddress.getLocalHost(), - Support_PortManager.getNextPort()); Socket theSocket = new Socket(); theSocket.setOOBInline(true); assertTrue("expected OOBIline to be true", theSocket.getOOBInline()); @@ -1779,8 +1604,6 @@ public class OldSocketTest extends OldSocketTestCase { public void test_getOOBInline() { try { - new InetSocketAddress(InetAddress.getLocalHost(), - Support_PortManager.getNextPort()); Socket theSocket = new Socket(); // validate that value reflects what we set it to true after true, @@ -1812,8 +1635,6 @@ public class OldSocketTest extends OldSocketTestCase { int IPTOS_LOWCOST = 0x2; int IPTOS_THROUGHPUT = 0x8; - new InetSocketAddress(InetAddress.getLocalHost(), - Support_PortManager.getNextPort()); Socket theSocket = new Socket(); // validate that value set must be between 0 and 255 @@ -1851,8 +1672,6 @@ public class OldSocketTest extends OldSocketTestCase { public void test_getTrafficClass() { try { - new InetSocketAddress(InetAddress.getLocalHost(), - Support_PortManager.getNextPort()); Socket theSocket = new Socket(); /* @@ -1888,13 +1707,9 @@ public class OldSocketTest extends OldSocketTestCase { // is silently ignored String urgentData = "U"; try { - InetSocketAddress theAddress = new InetSocketAddress( - InetAddress.getLocalHost(), Support_PortManager - .getNextPort()); Socket theSocket = new Socket(); - ServerSocket serverSocket = new ServerSocket(); - serverSocket.bind(theAddress); - theSocket.connect(theAddress); + ServerSocket serverSocket = new ServerSocket(0, 5); + theSocket.connect(serverSocket.getLocalSocketAddress()); Socket servSock = serverSocket.accept(); InputStream theInput = theSocket.getInputStream(); OutputStream theOutput = servSock.getOutputStream(); @@ -1931,12 +1746,9 @@ public class OldSocketTest extends OldSocketTestCase { // now validate that urgent data is received as expected. Expect // that it should be between the two writes. - theAddress = new InetSocketAddress(InetAddress.getLocalHost(), - Support_PortManager.getNextPort()); theSocket = new Socket(); - serverSocket = new ServerSocket(); - serverSocket.bind(theAddress); - theSocket.connect(theAddress); + serverSocket = new ServerSocket(0, 5); + theSocket.connect(serverSocket.getLocalSocketAddress()); servSock = serverSocket.accept(); theInput = theSocket.getInputStream(); theOutput = servSock.getOutputStream(); @@ -1973,12 +1785,9 @@ public class OldSocketTest extends OldSocketTestCase { serverSocket.close(); // now test case where we try to send two urgent bytes. - theAddress = new InetSocketAddress(InetAddress.getLocalHost(), - Support_PortManager.getNextPort()); theSocket = new Socket(); - serverSocket = new ServerSocket(); - serverSocket.bind(theAddress); - theSocket.connect(theAddress); + serverSocket = new ServerSocket(0, 5); + theSocket.connect(serverSocket.getLocalSocketAddress()); servSock = serverSocket.accept(); theInput = theSocket.getInputStream(); theOutput = servSock.getOutputStream(); @@ -2022,12 +1831,9 @@ public class OldSocketTest extends OldSocketTestCase { */ if (!platform.startsWith("Windows")) { // now test the case were we send turn the OOBInline on/off - theAddress = new InetSocketAddress(InetAddress - .getLocalHost(), Support_PortManager.getNextPort()); theSocket = new Socket(); - serverSocket = new ServerSocket(); - serverSocket.bind(theAddress); - theSocket.connect(theAddress); + serverSocket = new ServerSocket(0, 5); + theSocket.connect(serverSocket.getLocalSocketAddress()); servSock = serverSocket.accept(); theInput = theSocket.getInputStream(); theOutput = servSock.getOutputStream(); @@ -2139,12 +1945,9 @@ public class OldSocketTest extends OldSocketTestCase { } // now test the case where there is only urgent data - theAddress = new InetSocketAddress(InetAddress.getLocalHost(), - Support_PortManager.getNextPort()); theSocket = new Socket(); - serverSocket = new ServerSocket(); - serverSocket.bind(theAddress); - theSocket.connect(theAddress); + serverSocket = new ServerSocket(0, 5); + theSocket.connect(serverSocket.getLocalSocketAddress()); servSock = serverSocket.accept(); theInput = theSocket.getInputStream(); theOutput = servSock.getOutputStream(); @@ -2370,13 +2173,9 @@ public class OldSocketTest extends OldSocketTestCase { } - /** - * - */ protected int startServer(String name) { - int portNumber = Support_PortManager.getNextPort(); try { - ss = new ServerSocket(portNumber, 5); + ss = new ServerSocket(0, 5); } catch (IOException e) { fail(name + ": " + e); } 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/java/util/LocaleTest.java b/luni/src/test/java/libcore/java/util/LocaleTest.java index 541dd66..b146b1a 100644 --- a/luni/src/test/java/libcore/java/util/LocaleTest.java +++ b/luni/src/test/java/libcore/java/util/LocaleTest.java @@ -46,6 +46,16 @@ public class LocaleTest extends junit.framework.TestCase { assertEquals("Deutsch", Locale.GERMAN.getDisplayLanguage(Locale.GERMAN)); } + // http://b/7291355; Locale.getDisplayLanguage fails for tl in tl in ICU 4.9. + public void test_tl() throws Exception { + Locale tl = new Locale("tl"); + Locale tl_PH = new Locale("tl", "PH"); + assertEquals("Filipino", tl.getDisplayLanguage(Locale.ENGLISH)); + assertEquals("Filipino", tl_PH.getDisplayLanguage(Locale.ENGLISH)); + assertEquals("Filipino", tl.getDisplayLanguage(tl)); + assertEquals("Filipino", tl_PH.getDisplayLanguage(tl_PH)); + } + // http://b/3452611; Locale.getDisplayLanguage fails for the obsolete language codes. public void test_getDisplayName_obsolete() throws Exception { // he (new) -> iw (obsolete) diff --git a/luni/src/test/java/libcore/javax/crypto/CipherTest.java b/luni/src/test/java/libcore/javax/crypto/CipherTest.java index 764b63c..a98cdec 100644 --- a/luni/src/test/java/libcore/javax/crypto/CipherTest.java +++ b/luni/src/test/java/libcore/javax/crypto/CipherTest.java @@ -17,7 +17,6 @@ package libcore.javax.crypto; import com.android.org.bouncycastle.asn1.x509.KeyUsage; - import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.math.BigInteger; @@ -56,7 +55,6 @@ import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.PBEParameterSpec; import javax.crypto.spec.SecretKeySpec; - import junit.framework.TestCase; import libcore.java.security.StandardNames; import libcore.java.security.TestKeyStore; @@ -64,6 +62,35 @@ import libcore.util.EmptyArray; public final class CipherTest extends TestCase { + private static final String[] RSA_PROVIDERS = ((StandardNames.IS_RI) + ? new String[] { "SunJCE" } + : new String[] { "BC" , "AndroidOpenSSL" }); + + private static final String[] AES_PROVIDERS = ((StandardNames.IS_RI) + ? new String[] { "SunJCE" } + : new String[] { "BC", "AndroidOpenSSL" }); + + private static final boolean IS_UNLIMITED; + static { + boolean is_unlimited; + if (StandardNames.IS_RI) { + try { + String algorithm = "PBEWITHMD5ANDTRIPLEDES"; + Cipher.getInstance(algorithm).init(getEncryptMode(algorithm), + getEncryptKey(algorithm), + getAlgorithmParameterSpec(algorithm)); + is_unlimited = true; + } catch (Exception e) { + is_unlimited = false; + System.out.println("WARNING: Some tests disabled due to lack of " + + "'Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files'"); + } + } else { + is_unlimited = true; + } + IS_UNLIMITED = is_unlimited; + } + private static boolean isUnsupported(String algorithm) { if (algorithm.equals("RC2")) { return true; @@ -83,9 +110,28 @@ public final class CipherTest extends TestCase { if (algorithm.equals("PBEWITHSHAANDTWOFISH-CBC")) { return true; } + if (!IS_UNLIMITED) { + if (algorithm.equals("PBEWITHMD5ANDTRIPLEDES")) { + return true; + } + } return false; } + private synchronized static int getEncryptMode(String algorithm) throws Exception { + if (isOnlyWrappingAlgorithm(algorithm)) { + return Cipher.WRAP_MODE; + } + return Cipher.ENCRYPT_MODE; + } + + private synchronized static int getDecryptMode(String algorithm) throws Exception { + if (isOnlyWrappingAlgorithm(algorithm)) { + return Cipher.UNWRAP_MODE; + } + return Cipher.DECRYPT_MODE; + } + private static String getBaseAlgorithm(String algorithm) { if (algorithm.equals("AESWRAP")) { return "AES"; @@ -164,6 +210,11 @@ public final class CipherTest extends TestCase { return algorithm.endsWith("WRAP"); } + private static boolean isWrappingSupported(String algorithm, String provider) { + // All Cipher's should support wrapping but BouncyCastle PBE ciphers do not. + return !(provider.equals("BC") && isPBE(algorithm)); + } + private static boolean isPBE(String algorithm) { return algorithm.startsWith("PBE"); } @@ -211,135 +262,213 @@ public final class CipherTest extends TestCase { private static Map<String, Integer> EXPECTED_BLOCK_SIZE = new HashMap<String, Integer>(); static { - EXPECTED_BLOCK_SIZE.put("AES", 16); - EXPECTED_BLOCK_SIZE.put("PBEWITHMD5AND128BITAES-CBC-OPENSSL", 16); - EXPECTED_BLOCK_SIZE.put("PBEWITHMD5AND192BITAES-CBC-OPENSSL", 16); - EXPECTED_BLOCK_SIZE.put("PBEWITHMD5AND256BITAES-CBC-OPENSSL", 16); - EXPECTED_BLOCK_SIZE.put("PBEWITHSHA256AND128BITAES-CBC-BC", 16); - EXPECTED_BLOCK_SIZE.put("PBEWITHSHA256AND192BITAES-CBC-BC", 16); - EXPECTED_BLOCK_SIZE.put("PBEWITHSHA256AND256BITAES-CBC-BC", 16); - EXPECTED_BLOCK_SIZE.put("PBEWITHSHAAND128BITAES-CBC-BC", 16); - EXPECTED_BLOCK_SIZE.put("PBEWITHSHAAND192BITAES-CBC-BC", 16); - EXPECTED_BLOCK_SIZE.put("PBEWITHSHAAND256BITAES-CBC-BC", 16); + setExpectedBlockSize("AES", 16); + setExpectedBlockSize("PBEWITHMD5AND128BITAES-CBC-OPENSSL", 16); + setExpectedBlockSize("PBEWITHMD5AND192BITAES-CBC-OPENSSL", 16); + setExpectedBlockSize("PBEWITHMD5AND256BITAES-CBC-OPENSSL", 16); + setExpectedBlockSize("PBEWITHSHA256AND128BITAES-CBC-BC", 16); + setExpectedBlockSize("PBEWITHSHA256AND192BITAES-CBC-BC", 16); + setExpectedBlockSize("PBEWITHSHA256AND256BITAES-CBC-BC", 16); + setExpectedBlockSize("PBEWITHSHAAND128BITAES-CBC-BC", 16); + setExpectedBlockSize("PBEWITHSHAAND192BITAES-CBC-BC", 16); + setExpectedBlockSize("PBEWITHSHAAND256BITAES-CBC-BC", 16); if (StandardNames.IS_RI) { - EXPECTED_BLOCK_SIZE.put("AESWRAP", 16); + setExpectedBlockSize("AESWRAP", 16); } else { - EXPECTED_BLOCK_SIZE.put("AESWRAP", 0); + setExpectedBlockSize("AESWRAP", 0); } - EXPECTED_BLOCK_SIZE.put("ARC4", 0); - EXPECTED_BLOCK_SIZE.put("ARCFOUR", 0); + setExpectedBlockSize("ARC4", 0); + setExpectedBlockSize("ARCFOUR", 0); + setExpectedBlockSize("PBEWITHSHAAND40BITRC4", 0); + setExpectedBlockSize("PBEWITHSHAAND128BITRC4", 0); - EXPECTED_BLOCK_SIZE.put("PBEWITHSHAAND40BITRC4", 0); - EXPECTED_BLOCK_SIZE.put("PBEWITHSHAAND128BITRC4", 0); + setExpectedBlockSize("BLOWFISH", 8); - EXPECTED_BLOCK_SIZE.put("BLOWFISH", 8); + setExpectedBlockSize("DES", 8); + setExpectedBlockSize("PBEWITHMD5ANDDES", 8); + setExpectedBlockSize("PBEWITHSHA1ANDDES", 8); - EXPECTED_BLOCK_SIZE.put("DES", 8); - EXPECTED_BLOCK_SIZE.put("PBEWITHMD5ANDDES", 8); - EXPECTED_BLOCK_SIZE.put("PBEWITHMD5ANDTRIPLEDES", 8); - EXPECTED_BLOCK_SIZE.put("PBEWITHSHA1ANDDES", 8); - EXPECTED_BLOCK_SIZE.put("PBEWITHSHA1ANDDESEDE", 8); + setExpectedBlockSize("DESEDE", 8); + setExpectedBlockSize("PBEWITHSHAAND2-KEYTRIPLEDES-CBC", 8); + setExpectedBlockSize("PBEWITHSHAAND3-KEYTRIPLEDES-CBC", 8); + setExpectedBlockSize("PBEWITHMD5ANDTRIPLEDES", 8); + setExpectedBlockSize("PBEWITHSHA1ANDDESEDE", 8); - EXPECTED_BLOCK_SIZE.put("DESEDE", 8); - EXPECTED_BLOCK_SIZE.put("PBEWITHSHAAND2-KEYTRIPLEDES-CBC", 8); - EXPECTED_BLOCK_SIZE.put("PBEWITHSHAAND3-KEYTRIPLEDES-CBC", 8); if (StandardNames.IS_RI) { - EXPECTED_BLOCK_SIZE.put("DESEDEWRAP", 8); + setExpectedBlockSize("DESEDEWRAP", 8); } else { - EXPECTED_BLOCK_SIZE.put("DESEDEWRAP", 0); + setExpectedBlockSize("DESEDEWRAP", 0); } - EXPECTED_BLOCK_SIZE.put("RSA", 0); - } + if (StandardNames.IS_RI) { + setExpectedBlockSize("RSA", 0); + setExpectedBlockSize("RSA/ECB/NoPadding", 0); + setExpectedBlockSize("RSA/ECB/PKCS1Padding", 0); + } else { + setExpectedBlockSize("RSA", Cipher.ENCRYPT_MODE, 256); + setExpectedBlockSize("RSA/ECB/NoPadding", Cipher.ENCRYPT_MODE, 256); + setExpectedBlockSize("RSA/ECB/PKCS1Padding", Cipher.ENCRYPT_MODE, 245); - private static int getExpectedBlockSize(String algorithm, Key key) { - final int firstSlash = algorithm.indexOf('/'); - if (firstSlash != -1) { - algorithm = algorithm.substring(0, firstSlash); - } + // BC strips the leading 0 for us even when NoPadding is specified + setExpectedBlockSize("RSA", Cipher.ENCRYPT_MODE, "BC", 255); + setExpectedBlockSize("RSA/ECB/NoPadding", Cipher.ENCRYPT_MODE, "BC", 255); - if (!StandardNames.IS_RI && "RSA".equals(getBaseAlgorithm(algorithm))) { - // Must be one less than the modulus size to make sure it fits. - return getRSAModulusSize(key) - 1; + setExpectedBlockSize("RSA", Cipher.DECRYPT_MODE, 256); + setExpectedBlockSize("RSA/ECB/NoPadding", Cipher.DECRYPT_MODE, 256); + setExpectedBlockSize("RSA/ECB/PKCS1Padding", Cipher.DECRYPT_MODE, 256); } + } - Integer expected = EXPECTED_BLOCK_SIZE.get(algorithm); - assertNotNull(algorithm, expected); - return expected; + private static String modeKey(String algorithm, int mode) { + return algorithm + ":" + mode; } - private static int getRSAModulusSize(Key key) { - if (key instanceof RSAPrivateKey) { - RSAPrivateKey rsaKey = (RSAPrivateKey) key; - return rsaKey.getModulus().bitLength() / 8; - } else if (key instanceof RSAPublicKey) { - RSAPublicKey rsaKey = (RSAPublicKey) key; - return rsaKey.getModulus().bitLength() / 8; - } else { - throw new RuntimeException("Unknown RSA key type: " + key.getClass().getName()); + private static String modeProviderKey(String algorithm, int mode, String provider) { + return algorithm + ":" + mode + ":" + provider; + } + + private static void setExpectedSize(Map<String, Integer> map, + String algorithm, int value) { + algorithm = algorithm.toUpperCase(Locale.US); + map.put(algorithm, value); + } + + private static void setExpectedSize(Map<String, Integer> map, + String algorithm, int mode, int value) { + setExpectedSize(map, modeKey(algorithm, mode), value); + } + + private static void setExpectedSize(Map<String, Integer> map, + String algorithm, int mode, String provider, int value) { + setExpectedSize(map, modeProviderKey(algorithm, mode, provider), value); + } + + private static int getExpectedSize(Map<String, Integer> map, String algorithm, int mode, String provider) { + Integer expected = map.get(modeProviderKey(algorithm, mode, provider)); + if (expected != null) { + return expected; + } + expected = map.get(modeKey(algorithm, mode)); + if (expected != null) { + return expected; } + expected = map.get(algorithm); + assertNotNull("Algorithm " + algorithm + " not found in " + map, expected); + return expected; + } + + private static void setExpectedBlockSize(String algorithm, int value) { + setExpectedSize(EXPECTED_BLOCK_SIZE, algorithm, value); + } + + private static void setExpectedBlockSize(String algorithm, int mode, int value) { + setExpectedSize(EXPECTED_BLOCK_SIZE, algorithm, mode, value); + } + + private static void setExpectedBlockSize(String algorithm, int mode, String provider, int value) { + setExpectedSize(EXPECTED_BLOCK_SIZE, algorithm, mode, provider, value); + } + + private static int getExpectedBlockSize(String algorithm, int mode, String provider) { + return getExpectedSize(EXPECTED_BLOCK_SIZE, algorithm, mode, provider); } private static Map<String, Integer> EXPECTED_OUTPUT_SIZE = new HashMap<String, Integer>(); static { - EXPECTED_OUTPUT_SIZE.put("AES", 16); - EXPECTED_OUTPUT_SIZE.put("PBEWITHMD5AND128BITAES-CBC-OPENSSL", 16); - EXPECTED_OUTPUT_SIZE.put("PBEWITHMD5AND192BITAES-CBC-OPENSSL", 16); - EXPECTED_OUTPUT_SIZE.put("PBEWITHMD5AND256BITAES-CBC-OPENSSL", 16); - EXPECTED_OUTPUT_SIZE.put("PBEWITHSHA256AND128BITAES-CBC-BC", 16); - EXPECTED_OUTPUT_SIZE.put("PBEWITHSHA256AND192BITAES-CBC-BC", 16); - EXPECTED_OUTPUT_SIZE.put("PBEWITHSHA256AND256BITAES-CBC-BC", 16); - EXPECTED_OUTPUT_SIZE.put("PBEWITHSHAAND128BITAES-CBC-BC", 16); - EXPECTED_OUTPUT_SIZE.put("PBEWITHSHAAND192BITAES-CBC-BC", 16); - EXPECTED_OUTPUT_SIZE.put("PBEWITHSHAAND256BITAES-CBC-BC", 16); + setExpectedOutputSize("AES", Cipher.ENCRYPT_MODE, 16); + setExpectedOutputSize("PBEWITHMD5AND128BITAES-CBC-OPENSSL", 16); + setExpectedOutputSize("PBEWITHMD5AND192BITAES-CBC-OPENSSL", 16); + setExpectedOutputSize("PBEWITHMD5AND256BITAES-CBC-OPENSSL", 16); + setExpectedOutputSize("PBEWITHSHA256AND128BITAES-CBC-BC", 16); + setExpectedOutputSize("PBEWITHSHA256AND192BITAES-CBC-BC", 16); + setExpectedOutputSize("PBEWITHSHA256AND256BITAES-CBC-BC", 16); + setExpectedOutputSize("PBEWITHSHAAND128BITAES-CBC-BC", 16); + setExpectedOutputSize("PBEWITHSHAAND192BITAES-CBC-BC", 16); + setExpectedOutputSize("PBEWITHSHAAND256BITAES-CBC-BC", 16); + + setExpectedOutputSize("AES", Cipher.DECRYPT_MODE, 0); + setExpectedOutputSize("PBEWITHMD5AND128BITAES-CBC-OPENSSL", Cipher.DECRYPT_MODE, 0); + setExpectedOutputSize("PBEWITHMD5AND192BITAES-CBC-OPENSSL", Cipher.DECRYPT_MODE, 0); + setExpectedOutputSize("PBEWITHMD5AND256BITAES-CBC-OPENSSL", Cipher.DECRYPT_MODE, 0); + setExpectedOutputSize("PBEWITHSHA256AND128BITAES-CBC-BC", Cipher.DECRYPT_MODE, 0); + setExpectedOutputSize("PBEWITHSHA256AND192BITAES-CBC-BC", Cipher.DECRYPT_MODE, 0); + setExpectedOutputSize("PBEWITHSHA256AND256BITAES-CBC-BC", Cipher.DECRYPT_MODE, 0); + setExpectedOutputSize("PBEWITHSHAAND128BITAES-CBC-BC", Cipher.DECRYPT_MODE, 0); + setExpectedOutputSize("PBEWITHSHAAND192BITAES-CBC-BC", Cipher.DECRYPT_MODE, 0); + setExpectedOutputSize("PBEWITHSHAAND256BITAES-CBC-BC", Cipher.DECRYPT_MODE, 0); if (StandardNames.IS_RI) { - EXPECTED_OUTPUT_SIZE.put("AESWRAP", 8); + setExpectedOutputSize("AESWRAP", Cipher.WRAP_MODE, 8); + setExpectedOutputSize("AESWRAP", Cipher.UNWRAP_MODE, 0); } else { - EXPECTED_OUTPUT_SIZE.put("AESWRAP", -1); + setExpectedOutputSize("AESWRAP", -1); } - EXPECTED_OUTPUT_SIZE.put("ARC4", 0); - EXPECTED_OUTPUT_SIZE.put("ARCFOUR", 0); + setExpectedOutputSize("ARC4", 0); + setExpectedOutputSize("ARCFOUR", 0); + setExpectedOutputSize("PBEWITHSHAAND40BITRC4", 0); + setExpectedOutputSize("PBEWITHSHAAND128BITRC4", 0); - EXPECTED_OUTPUT_SIZE.put("PBEWITHSHAAND40BITRC4", 0); - EXPECTED_OUTPUT_SIZE.put("PBEWITHSHAAND128BITRC4", 0); + setExpectedOutputSize("BLOWFISH", Cipher.ENCRYPT_MODE, 8); + setExpectedOutputSize("BLOWFISH", Cipher.DECRYPT_MODE, 0); - EXPECTED_OUTPUT_SIZE.put("BLOWFISH", 8); + setExpectedOutputSize("DES", Cipher.ENCRYPT_MODE, 8); + setExpectedOutputSize("PBEWITHMD5ANDDES", Cipher.ENCRYPT_MODE, 8); + setExpectedOutputSize("PBEWITHSHA1ANDDES", Cipher.ENCRYPT_MODE, 8); - EXPECTED_OUTPUT_SIZE.put("DES", 8); - EXPECTED_OUTPUT_SIZE.put("PBEWITHMD5ANDDES", 8); - EXPECTED_OUTPUT_SIZE.put("PBEWITHMD5ANDTRIPLEDES", 8); - EXPECTED_OUTPUT_SIZE.put("PBEWITHSHA1ANDDES", 8); - EXPECTED_OUTPUT_SIZE.put("PBEWITHSHA1ANDDESEDE", 8); + setExpectedOutputSize("DES", Cipher.DECRYPT_MODE, 0); + setExpectedOutputSize("PBEWITHMD5ANDDES", Cipher.DECRYPT_MODE, 0); + setExpectedOutputSize("PBEWITHSHA1ANDDES", Cipher.DECRYPT_MODE, 0); - EXPECTED_OUTPUT_SIZE.put("DESEDE", 8); - EXPECTED_OUTPUT_SIZE.put("PBEWITHSHAAND2-KEYTRIPLEDES-CBC", 8); - EXPECTED_OUTPUT_SIZE.put("PBEWITHSHAAND3-KEYTRIPLEDES-CBC", 8); + setExpectedOutputSize("DESEDE", Cipher.ENCRYPT_MODE, 8); + setExpectedOutputSize("PBEWITHSHAAND2-KEYTRIPLEDES-CBC", Cipher.ENCRYPT_MODE, 8); + setExpectedOutputSize("PBEWITHSHAAND3-KEYTRIPLEDES-CBC", Cipher.ENCRYPT_MODE, 8); + setExpectedOutputSize("PBEWITHMD5ANDTRIPLEDES", Cipher.ENCRYPT_MODE, 8); + setExpectedOutputSize("PBEWITHSHA1ANDDESEDE", Cipher.ENCRYPT_MODE, 8); + + setExpectedOutputSize("DESEDE", Cipher.DECRYPT_MODE, 0); + setExpectedOutputSize("PBEWITHSHAAND2-KEYTRIPLEDES-CBC", Cipher.DECRYPT_MODE, 0); + setExpectedOutputSize("PBEWITHSHAAND3-KEYTRIPLEDES-CBC", Cipher.DECRYPT_MODE, 0); + setExpectedOutputSize("PBEWITHMD5ANDTRIPLEDES", Cipher.DECRYPT_MODE, 0); + setExpectedOutputSize("PBEWITHSHA1ANDDESEDE", Cipher.DECRYPT_MODE, 0); if (StandardNames.IS_RI) { - EXPECTED_OUTPUT_SIZE.put("DESEDEWRAP", 16); + setExpectedOutputSize("DESEDEWRAP", Cipher.WRAP_MODE, 16); + setExpectedOutputSize("DESEDEWRAP", Cipher.UNWRAP_MODE, 0); } else { - EXPECTED_OUTPUT_SIZE.put("DESEDEWRAP", -1); + setExpectedOutputSize("DESEDEWRAP", -1); } + + setExpectedOutputSize("RSA", Cipher.ENCRYPT_MODE, 256); + setExpectedOutputSize("RSA/ECB/NoPadding", Cipher.ENCRYPT_MODE, 256); + setExpectedOutputSize("RSA/ECB/PKCS1Padding", Cipher.ENCRYPT_MODE, 256); + + setExpectedOutputSize("RSA", Cipher.DECRYPT_MODE, 256); + setExpectedOutputSize("RSA/ECB/NoPadding", Cipher.DECRYPT_MODE, 256); + setExpectedOutputSize("RSA/ECB/PKCS1Padding", Cipher.DECRYPT_MODE, 245); + + // BC strips the leading 0 for us even when NoPadding is specified + setExpectedOutputSize("RSA", Cipher.DECRYPT_MODE, "BC", 255); + setExpectedOutputSize("RSA/ECB/NoPadding", Cipher.DECRYPT_MODE, "BC", 255); } - private static int getExpectedOutputSize(String algorithm, Key key) { - final int firstSlash = algorithm.indexOf('/'); - if (firstSlash != -1) { - algorithm = algorithm.substring(0, firstSlash); - } - // Output size for RSA depends on the key size being used. - if ("RSA".equals(getBaseAlgorithm(algorithm))) { - return getRSAModulusSize(key); - } + private static void setExpectedOutputSize(String algorithm, int value) { + setExpectedSize(EXPECTED_OUTPUT_SIZE, algorithm, value); + } - Integer expected = EXPECTED_OUTPUT_SIZE.get(algorithm); - assertNotNull(algorithm, expected); - return expected; + private static void setExpectedOutputSize(String algorithm, int mode, int value) { + setExpectedSize(EXPECTED_OUTPUT_SIZE, algorithm, mode, value); + } + + private static void setExpectedOutputSize(String algorithm, int mode, String provider, int value) { + setExpectedSize(EXPECTED_OUTPUT_SIZE, algorithm, mode, provider, value); + } + + private static int getExpectedOutputSize(String algorithm, int mode, String provider) { + return getExpectedSize(EXPECTED_OUTPUT_SIZE, algorithm, mode, provider); } private static byte[] ORIGINAL_PLAIN_TEXT = new byte[] { 0x0a, 0x0b, 0x0c }; @@ -437,6 +566,15 @@ public final class CipherTest extends TestCase { return ORIGINAL_PLAIN_TEXT; } + private static AlgorithmParameterSpec getAlgorithmParameterSpec(String algorithm) { + if (!isPBE(algorithm)) { + return null; + } + final byte[] salt = new byte[8]; + new SecureRandom().nextBytes(salt); + return new PBEParameterSpec(salt, 1024); + } + public void test_getInstance() throws Exception { final ByteArrayOutputStream errBuffer = new ByteArrayOutputStream(); PrintStream out = new PrintStream(errBuffer); @@ -475,7 +613,8 @@ public final class CipherTest extends TestCase { try { test_Cipher_Algorithm(provider, algorithm); } catch (Throwable e) { - out.append("Error encountered checking " + algorithm + "\n"); + out.append("Error encountered checking " + algorithm + + " with provider " + provider.getName() + "\n"); e.printStackTrace(out); } @@ -489,7 +628,8 @@ public final class CipherTest extends TestCase { try { test_Cipher_Algorithm(provider, algorithmName); } catch (Throwable e) { - out.append("Error encountered checking " + algorithmName + "\n"); + out.append("Error encountered checking " + algorithmName + + " with provider " + provider.getName() + "\n"); e.printStackTrace(out); } } @@ -533,6 +673,8 @@ public final class CipherTest extends TestCase { if (isUnsupported(algorithm)) { return; } + String providerName = c.getProvider().getName(); + String cipherID = algorithm + ":" + providerName; try { c.getOutputSize(0); @@ -541,35 +683,30 @@ public final class CipherTest extends TestCase { // TODO: test keys from different factories (e.g. OpenSSLRSAPrivateKey vs JCERSAPrivateKey) Key encryptKey = getEncryptKey(algorithm); - final AlgorithmParameterSpec spec; - if (isPBE(algorithm)) { - final byte[] salt = new byte[8]; - new SecureRandom().nextBytes(salt); - spec = new PBEParameterSpec(salt, 1024); - } else { - spec = null; - } - if (!isOnlyWrappingAlgorithm(algorithm)) { - c.init(Cipher.ENCRYPT_MODE, encryptKey, spec); - } else { - c.init(Cipher.WRAP_MODE, encryptKey, spec); - } - - assertEquals("getBlockSize()", getExpectedBlockSize(algorithm, encryptKey), - c.getBlockSize()); - - assertEquals("getOutputSize(0)", getExpectedOutputSize(algorithm, encryptKey), - c.getOutputSize(0)); + final AlgorithmParameterSpec spec = getAlgorithmParameterSpec(algorithm); + + int encryptMode = getEncryptMode(algorithm); + c.init(encryptMode, encryptKey, spec); + assertEquals(cipherID + " getBlockSize()", + getExpectedBlockSize(algorithm, encryptMode, providerName), c.getBlockSize()); + assertEquals(cipherID + " getOutputSize(0)", + getExpectedOutputSize(algorithm, encryptMode, providerName), c.getOutputSize(0)); + int decryptMode = getDecryptMode(algorithm); + c.init(decryptMode, encryptKey, spec); + assertEquals(cipherID + " getBlockSize()", + getExpectedBlockSize(algorithm, decryptMode, providerName), c.getBlockSize()); + assertEquals(cipherID + " getOutputSize(0)", + getExpectedOutputSize(algorithm, decryptMode, providerName), c.getOutputSize(0)); // TODO: test Cipher.getIV() // TODO: test Cipher.getParameters() - assertNull(c.getExemptionMechanism()); + assertNull(cipherID, c.getExemptionMechanism()); - // Test wrapping a key. Every cipher should be able to wrap. - { + // Test wrapping a key. Most every cipher should be able to wrap. + if (isWrappingSupported(algorithm, providerName)) { // Generate a small SecretKey for AES. KeyGenerator kg = KeyGenerator.getInstance("AES"); kg.init(128); @@ -583,7 +720,8 @@ public final class CipherTest extends TestCase { c.init(Cipher.UNWRAP_MODE, getDecryptKey(algorithm), spec); Key decryptedKey = c.unwrap(cipherText, sk.getAlgorithm(), Cipher.SECRET_KEY); - assertEquals("sk.getAlgorithm()=" + sk.getAlgorithm() + assertEquals(cipherID + + " sk.getAlgorithm()=" + sk.getAlgorithm() + " decryptedKey.getAlgorithm()=" + decryptedKey.getAlgorithm() + " encryptKey.getEncoded()=" + Arrays.toString(sk.getEncoded()) + " decryptedKey.getEncoded()=" + Arrays.toString(decryptedKey.getEncoded()), @@ -595,31 +733,37 @@ public final class CipherTest extends TestCase { byte[] cipherText = c.doFinal(ORIGINAL_PLAIN_TEXT); c.init(Cipher.DECRYPT_MODE, getDecryptKey(algorithm), spec); byte[] decryptedPlainText = c.doFinal(cipherText); - assertEquals(Arrays.toString(getExpectedPlainText(algorithm)), + assertEquals(cipherID, Arrays.toString(getExpectedPlainText(algorithm)), Arrays.toString(decryptedPlainText)); } } public void testInputPKCS1Padding() throws Exception { - testInputPKCS1Padding(PKCS1_BLOCK_TYPE_01_PADDED_PLAIN_TEXT, getEncryptKey("RSA"), getDecryptKey("RSA")); + for (String provider : RSA_PROVIDERS) { + testInputPKCS1Padding(provider); + } + } + + private void testInputPKCS1Padding(String provider) throws Exception { + testInputPKCS1Padding(provider, PKCS1_BLOCK_TYPE_01_PADDED_PLAIN_TEXT, getEncryptKey("RSA"), getDecryptKey("RSA")); try { - testInputPKCS1Padding(PKCS1_BLOCK_TYPE_02_PADDED_PLAIN_TEXT, getEncryptKey("RSA"), getDecryptKey("RSA")); + testInputPKCS1Padding(provider, PKCS1_BLOCK_TYPE_02_PADDED_PLAIN_TEXT, getEncryptKey("RSA"), getDecryptKey("RSA")); fail(); } catch (BadPaddingException expected) { } try { - testInputPKCS1Padding(PKCS1_BLOCK_TYPE_01_PADDED_PLAIN_TEXT, getDecryptKey("RSA"), getEncryptKey("RSA")); + testInputPKCS1Padding(provider, PKCS1_BLOCK_TYPE_01_PADDED_PLAIN_TEXT, getDecryptKey("RSA"), getEncryptKey("RSA")); fail(); } catch (BadPaddingException expected) { } - testInputPKCS1Padding(PKCS1_BLOCK_TYPE_02_PADDED_PLAIN_TEXT, getDecryptKey("RSA"), getEncryptKey("RSA")); + testInputPKCS1Padding(provider, PKCS1_BLOCK_TYPE_02_PADDED_PLAIN_TEXT, getDecryptKey("RSA"), getEncryptKey("RSA")); } - private void testInputPKCS1Padding(byte[] prePaddedPlainText, Key encryptKey, Key decryptKey) throws Exception { - Cipher encryptCipher = Cipher.getInstance("RSA/ECB/NoPadding"); + private void testInputPKCS1Padding(String provider, byte[] prePaddedPlainText, Key encryptKey, Key decryptKey) throws Exception { + Cipher encryptCipher = Cipher.getInstance("RSA/ECB/NoPadding", provider); encryptCipher.init(Cipher.ENCRYPT_MODE, encryptKey); byte[] cipherText = encryptCipher.doFinal(prePaddedPlainText); - Cipher decryptCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + Cipher decryptCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", provider); decryptCipher.init(Cipher.DECRYPT_MODE, decryptKey); byte[] plainText = decryptCipher.doFinal(cipherText); assertEquals(Arrays.toString(ORIGINAL_PLAIN_TEXT), @@ -627,37 +771,51 @@ public final class CipherTest extends TestCase { } public void testOutputPKCS1Padding() throws Exception { - testOutputPKCS1Padding((byte) 1, getEncryptKey("RSA"), getDecryptKey("RSA")); - testOutputPKCS1Padding((byte) 2, getDecryptKey("RSA"), getEncryptKey("RSA")); + for (String provider : RSA_PROVIDERS) { + testOutputPKCS1Padding(provider); + } + } + + private void testOutputPKCS1Padding(String provider) throws Exception { + testOutputPKCS1Padding(provider, (byte) 1, getEncryptKey("RSA"), getDecryptKey("RSA")); + testOutputPKCS1Padding(provider, (byte) 2, getDecryptKey("RSA"), getEncryptKey("RSA")); } - private void testOutputPKCS1Padding(byte expectedBlockType, Key encryptKey, Key decryptKey) throws Exception { - Cipher encryptCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + private void testOutputPKCS1Padding(String provider, byte expectedBlockType, Key encryptKey, Key decryptKey) throws Exception { + Cipher encryptCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", provider); encryptCipher.init(Cipher.ENCRYPT_MODE, encryptKey); byte[] cipherText = encryptCipher.doFinal(ORIGINAL_PLAIN_TEXT); - Cipher decryptCipher = Cipher.getInstance("RSA/ECB/NoPadding"); + Cipher decryptCipher = Cipher.getInstance("RSA/ECB/NoPadding", provider); decryptCipher.init(Cipher.DECRYPT_MODE, decryptKey); byte[] plainText = decryptCipher.doFinal(cipherText); - assertPadding(encryptKey, expectedBlockType, ORIGINAL_PLAIN_TEXT, plainText); + assertPadding(provider, expectedBlockType, ORIGINAL_PLAIN_TEXT, plainText); } - private void assertPadding(Key key, byte expectedBlockType, byte[] expectedData, - byte[] actualDataWithPadding) { - assertNotNull(actualDataWithPadding); - assertEquals(getExpectedOutputSize("RSA", key), actualDataWithPadding.length); - assertEquals(0, actualDataWithPadding[0]); - byte actualBlockType = actualDataWithPadding[1]; - assertEquals(expectedBlockType, actualBlockType); + private void assertPadding(String provider, byte expectedBlockType, byte[] expectedData, byte[] actualDataWithPadding) { + assertNotNull(provider, actualDataWithPadding); + int expectedOutputSize = getExpectedOutputSize("RSA", Cipher.DECRYPT_MODE, provider); + assertEquals(provider, expectedOutputSize, actualDataWithPadding.length); + int expectedBlockTypeOffset; + if (provider.equals("BC")) { + // BC strips the leading 0 for us on decrypt even when NoPadding is specified... + expectedBlockTypeOffset = 0; + } else { + expectedBlockTypeOffset = 1; + assertEquals(provider, 0, actualDataWithPadding[0]); + } + byte actualBlockType = actualDataWithPadding[expectedBlockTypeOffset]; + assertEquals(provider, expectedBlockType, actualBlockType); int actualDataOffset = actualDataWithPadding.length - expectedData.length; if (actualBlockType == 1) { - for (int i = 2; i < actualDataOffset - 1; i++) { - assertEquals((byte) 0xFF, actualDataWithPadding[i]); + int expectedDataOffset = expectedBlockTypeOffset + 1; + for (int i = expectedDataOffset; i < actualDataOffset - 1; i++) { + assertEquals(provider, (byte) 0xFF, actualDataWithPadding[i]); } } - assertEquals(0x00, actualDataWithPadding[actualDataOffset-1]); + assertEquals(provider, 0x00, actualDataWithPadding[actualDataOffset-1]); byte[] actualData = new byte[expectedData.length]; System.arraycopy(actualDataWithPadding, actualDataOffset, actualData, 0, actualData.length); - assertEquals(Arrays.toString(expectedData), Arrays.toString(actualData)); + assertEquals(provider, Arrays.toString(expectedData), Arrays.toString(actualData)); } public void testCipherInitWithCertificate () throws Exception { @@ -1095,13 +1253,19 @@ public final class CipherTest extends TestCase { }; public void testRSA_ECB_NoPadding_Private_OnlyDoFinal_Success() throws Exception { + for (String provider : RSA_PROVIDERS) { + testRSA_ECB_NoPadding_Private_OnlyDoFinal_Success(provider); + } + } + + private void testRSA_ECB_NoPadding_Private_OnlyDoFinal_Success(String provider) throws Exception { KeyFactory kf = KeyFactory.getInstance("RSA"); RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus, RSA_2048_privateExponent); final PrivateKey privKey = kf.generatePrivate(keySpec); - Cipher c = Cipher.getInstance("RSA/ECB/NoPadding"); + Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); /* * You're actually decrypting with private keys, but there is no @@ -1120,13 +1284,19 @@ public final class CipherTest extends TestCase { } public void testRSA_ECB_NoPadding_Private_UpdateThenEmptyDoFinal_Success() throws Exception { + for (String provider : RSA_PROVIDERS) { + testRSA_ECB_NoPadding_Private_UpdateThenEmptyDoFinal_Success(provider); + } + } + + private void testRSA_ECB_NoPadding_Private_UpdateThenEmptyDoFinal_Success(String provider) throws Exception { KeyFactory kf = KeyFactory.getInstance("RSA"); RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus, RSA_2048_privateExponent); final PrivateKey privKey = kf.generatePrivate(keySpec); - Cipher c = Cipher.getInstance("RSA/ECB/NoPadding"); + Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); /* * You're actually decrypting with private keys, but there is no @@ -1148,13 +1318,20 @@ public final class CipherTest extends TestCase { public void testRSA_ECB_NoPadding_Private_SingleByteUpdateThenEmptyDoFinal_Success() throws Exception { + for (String provider : RSA_PROVIDERS) { + testRSA_ECB_NoPadding_Private_SingleByteUpdateThenEmptyDoFinal_Success(provider); + } + } + + private void testRSA_ECB_NoPadding_Private_SingleByteUpdateThenEmptyDoFinal_Success(String provider) + throws Exception { KeyFactory kf = KeyFactory.getInstance("RSA"); RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus, RSA_2048_privateExponent); final PrivateKey privKey = kf.generatePrivate(keySpec); - Cipher c = Cipher.getInstance("RSA/ECB/NoPadding"); + Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); /* * You're actually decrypting with private keys, but there is no @@ -1180,12 +1357,18 @@ public final class CipherTest extends TestCase { } public void testRSA_ECB_NoPadding_Private_OnlyDoFinalWithOffset_Success() throws Exception { + for (String provider : RSA_PROVIDERS) { + testRSA_ECB_NoPadding_Private_OnlyDoFinalWithOffset_Success(provider); + } + } + + private void testRSA_ECB_NoPadding_Private_OnlyDoFinalWithOffset_Success(String provider) throws Exception { KeyFactory kf = KeyFactory.getInstance("RSA"); RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus, RSA_2048_privateExponent); final PrivateKey privKey = kf.generatePrivate(keySpec); - Cipher c = Cipher.getInstance("RSA/ECB/NoPadding"); + Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); /* * You're actually decrypting with private keys, but there is no @@ -1211,12 +1394,18 @@ public final class CipherTest extends TestCase { } public void testRSA_ECB_NoPadding_Public_OnlyDoFinal_Success() throws Exception { + for (String provider : RSA_PROVIDERS) { + testRSA_ECB_NoPadding_Public_OnlyDoFinal_Success(provider); + } + } + + private void testRSA_ECB_NoPadding_Public_OnlyDoFinal_Success(String provider) throws Exception { KeyFactory kf = KeyFactory.getInstance("RSA"); RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent); final PublicKey privKey = kf.generatePublic(keySpec); - Cipher c = Cipher.getInstance("RSA/ECB/NoPadding"); + Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); /* * You're actually encrypting with public keys, but there is no @@ -1225,22 +1414,26 @@ public final class CipherTest extends TestCase { */ c.init(Cipher.ENCRYPT_MODE, privKey); byte[] encrypted = c.doFinal(RSA_Vector1_Encrypt_Private); - assertTrue("Encrypted should match expected", - Arrays.equals(RSA_2048_Vector1, encrypted)); + assertEncryptedEqualsNoPadding(provider, Cipher.ENCRYPT_MODE, RSA_2048_Vector1, encrypted); c.init(Cipher.DECRYPT_MODE, privKey); encrypted = c.doFinal(RSA_Vector1_Encrypt_Private); - assertTrue("Encrypted should match expected", - Arrays.equals(RSA_2048_Vector1, encrypted)); + assertEncryptedEqualsNoPadding(provider, Cipher.DECRYPT_MODE, RSA_2048_Vector1, encrypted); } public void testRSA_ECB_NoPadding_Public_OnlyDoFinalWithOffset_Success() throws Exception { + for (String provider : RSA_PROVIDERS) { + testRSA_ECB_NoPadding_Public_OnlyDoFinalWithOffset_Success(provider); + } + } + + private void testRSA_ECB_NoPadding_Public_OnlyDoFinalWithOffset_Success(String provider) throws Exception { KeyFactory kf = KeyFactory.getInstance("RSA"); RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent); final PublicKey pubKey = kf.generatePublic(keySpec); - Cipher c = Cipher.getInstance("RSA/ECB/NoPadding"); + Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); /* * You're actually encrypting with public keys, but there is no @@ -1252,22 +1445,33 @@ public final class CipherTest extends TestCase { final int encryptLen = c.doFinal(RSA_Vector1_Encrypt_Private, 0, RSA_Vector1_Encrypt_Private.length, encrypted, 0); assertEquals("Encrypted size should match expected", RSA_2048_Vector1.length, encryptLen); - assertTrue("Encrypted should match expected", Arrays.equals(RSA_2048_Vector1, encrypted)); + assertEncryptedEqualsNoPadding(provider, Cipher.ENCRYPT_MODE, RSA_2048_Vector1, encrypted); c.init(Cipher.DECRYPT_MODE, pubKey); - final int decryptLen = c.doFinal(RSA_Vector1_Encrypt_Private, 0, + int decryptLen = c.doFinal(RSA_Vector1_Encrypt_Private, 0, RSA_Vector1_Encrypt_Private.length, encrypted, 0); + if (provider.equals("BC")) { + // BC strips the leading 0 for us on decrypt even when NoPadding is specified... + decryptLen++; + encrypted = Arrays.copyOf(encrypted, encrypted.length - 1); + } assertEquals("Encrypted size should match expected", RSA_2048_Vector1.length, decryptLen); - assertTrue("Encrypted should match expected", Arrays.equals(RSA_2048_Vector1, encrypted)); + assertEncryptedEqualsNoPadding(provider, Cipher.DECRYPT_MODE, RSA_2048_Vector1, encrypted); } public void testRSA_ECB_NoPadding_Public_UpdateThenEmptyDoFinal_Success() throws Exception { + for (String provider : RSA_PROVIDERS) { + testRSA_ECB_NoPadding_Public_UpdateThenEmptyDoFinal_Success(provider); + } + } + + private void testRSA_ECB_NoPadding_Public_UpdateThenEmptyDoFinal_Success(String provider) throws Exception { KeyFactory kf = KeyFactory.getInstance("RSA"); RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent); final PublicKey privKey = kf.generatePublic(keySpec); - Cipher c = Cipher.getInstance("RSA/ECB/NoPadding"); + Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); /* * You're actually encrypting with public keys, but there is no @@ -1277,22 +1481,29 @@ public final class CipherTest extends TestCase { c.init(Cipher.ENCRYPT_MODE, privKey); c.update(RSA_Vector1_Encrypt_Private); byte[] encrypted = c.doFinal(); - assertTrue("Encrypted should match expected", Arrays.equals(RSA_2048_Vector1, encrypted)); + assertEncryptedEqualsNoPadding(provider, Cipher.ENCRYPT_MODE, RSA_2048_Vector1, encrypted); c.init(Cipher.DECRYPT_MODE, privKey); c.update(RSA_Vector1_Encrypt_Private); encrypted = c.doFinal(); - assertTrue("Encrypted should match expected", Arrays.equals(RSA_2048_Vector1, encrypted)); + assertEncryptedEqualsNoPadding(provider, Cipher.DECRYPT_MODE, RSA_2048_Vector1, encrypted); } public void testRSA_ECB_NoPadding_Public_SingleByteUpdateThenEmptyDoFinal_Success() throws Exception { + for (String provider : RSA_PROVIDERS) { + testRSA_ECB_NoPadding_Public_SingleByteUpdateThenEmptyDoFinal_Success(provider); + } + } + + private void testRSA_ECB_NoPadding_Public_SingleByteUpdateThenEmptyDoFinal_Success(String provider) + throws Exception { KeyFactory kf = KeyFactory.getInstance("RSA"); RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent); final PublicKey privKey = kf.generatePublic(keySpec); - Cipher c = Cipher.getInstance("RSA/ECB/NoPadding"); + Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); /* * You're actually encrypting with public keys, but there is no @@ -1305,23 +1516,29 @@ public final class CipherTest extends TestCase { c.update(RSA_Vector1_Encrypt_Private, i, 1); } byte[] encrypted = c.doFinal(RSA_Vector1_Encrypt_Private, i, RSA_2048_Vector1.length - i); - assertTrue("Encrypted should match expected", Arrays.equals(RSA_2048_Vector1, encrypted)); + assertEncryptedEqualsNoPadding(provider, Cipher.ENCRYPT_MODE, RSA_2048_Vector1, encrypted); c.init(Cipher.DECRYPT_MODE, privKey); for (i = 0; i < RSA_Vector1_Encrypt_Private.length / 2; i++) { c.update(RSA_Vector1_Encrypt_Private, i, 1); } encrypted = c.doFinal(RSA_Vector1_Encrypt_Private, i, RSA_2048_Vector1.length - i); - assertTrue("Encrypted should match expected", Arrays.equals(RSA_2048_Vector1, encrypted)); + assertEncryptedEqualsNoPadding(provider, Cipher.DECRYPT_MODE, RSA_2048_Vector1, encrypted); } public void testRSA_ECB_NoPadding_Public_TooSmall_Success() throws Exception { + for (String provider : RSA_PROVIDERS) { + testRSA_ECB_NoPadding_Public_TooSmall_Success(provider); + } + } + + private void testRSA_ECB_NoPadding_Public_TooSmall_Success(String provider) throws Exception { KeyFactory kf = KeyFactory.getInstance("RSA"); RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent); final PublicKey privKey = kf.generatePublic(keySpec); - Cipher c = Cipher.getInstance("RSA/ECB/NoPadding"); + Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); /* * You're actually encrypting with public keys, but there is no @@ -1340,13 +1557,19 @@ public final class CipherTest extends TestCase { } public void testRSA_ECB_NoPadding_Private_TooSmall_Success() throws Exception { + for (String provider : RSA_PROVIDERS) { + testRSA_ECB_NoPadding_Private_TooSmall_Success(provider); + } + } + + private void testRSA_ECB_NoPadding_Private_TooSmall_Success(String provider) throws Exception { KeyFactory kf = KeyFactory.getInstance("RSA"); RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus, RSA_2048_privateExponent); final PrivateKey privKey = kf.generatePrivate(keySpec); - Cipher c = Cipher.getInstance("RSA/ECB/NoPadding"); + Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); /* * You're actually encrypting with public keys, but there is no @@ -1355,24 +1578,48 @@ public final class CipherTest extends TestCase { */ c.init(Cipher.ENCRYPT_MODE, privKey); byte[] encrypted = c.doFinal(RSA_Vector1_ZeroPadded_Encrypted); - assertTrue("Encrypted should match expected", - Arrays.equals(TooShort_Vector_Zero_Padded, encrypted)); + assertEncryptedEqualsNoPadding(provider, Cipher.ENCRYPT_MODE, + TooShort_Vector_Zero_Padded, encrypted); c.init(Cipher.DECRYPT_MODE, privKey); encrypted = c.doFinal(RSA_Vector1_ZeroPadded_Encrypted); - assertTrue("Encrypted should match expected", - Arrays.equals(TooShort_Vector_Zero_Padded, encrypted)); + assertEncryptedEqualsNoPadding(provider, Cipher.DECRYPT_MODE, + TooShort_Vector_Zero_Padded, encrypted); + } + + private static void assertEncryptedEqualsNoPadding(String provider, int mode, + byte[] expected, byte[] actual) { + if (provider.equals("BC") && mode == Cipher.DECRYPT_MODE) { + // BouncyCastle does us the favor of stripping leading zeroes in DECRYPT_MODE + int nonZeroOffset = 0; + for (byte b : expected) { + if (b != 0) { + break; + } + nonZeroOffset++; + } + expected = Arrays.copyOfRange(expected, nonZeroOffset, expected.length); + } + assertEquals("Encrypted should match expected", + Arrays.toString(expected), Arrays.toString(actual)); } public void testRSA_ECB_NoPadding_Private_CombinedUpdateAndDoFinal_TooBig_Failure() throws Exception { + for (String provider : RSA_PROVIDERS) { + testRSA_ECB_NoPadding_Private_CombinedUpdateAndDoFinal_TooBig_Failure(provider); + } + } + + private void testRSA_ECB_NoPadding_Private_CombinedUpdateAndDoFinal_TooBig_Failure(String provider) + throws Exception { KeyFactory kf = KeyFactory.getInstance("RSA"); RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus, RSA_2048_privateExponent); final PrivateKey privKey = kf.generatePrivate(keySpec); - Cipher c = Cipher.getInstance("RSA/ECB/NoPadding"); + Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); /* * You're actually encrypting with public keys, but there is no @@ -1386,18 +1633,28 @@ public final class CipherTest extends TestCase { c.doFinal(RSA_Vector1_ZeroPadded_Encrypted); fail("Should have error when block size is too big."); } catch (IllegalBlockSizeException success) { + assertFalse(provider, "BC".equals(provider)); + } catch (ArrayIndexOutOfBoundsException success) { + assertEquals("BC", provider); } } public void testRSA_ECB_NoPadding_Private_UpdateInAndOutPlusDoFinal_TooBig_Failure() throws Exception { + for (String provider : RSA_PROVIDERS) { + testRSA_ECB_NoPadding_Private_UpdateInAndOutPlusDoFinal_TooBig_Failure(provider); + } + } + + private void testRSA_ECB_NoPadding_Private_UpdateInAndOutPlusDoFinal_TooBig_Failure(String provider) + throws Exception { KeyFactory kf = KeyFactory.getInstance("RSA"); RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus, RSA_2048_privateExponent); final PrivateKey privKey = kf.generatePrivate(keySpec); - Cipher c = Cipher.getInstance("RSA/ECB/NoPadding"); + Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); /* * You're actually encrypting with public keys, but there is no @@ -1414,17 +1671,26 @@ public final class CipherTest extends TestCase { c.doFinal(RSA_Vector1_ZeroPadded_Encrypted); fail("Should have error when block size is too big."); } catch (IllegalBlockSizeException success) { + assertFalse(provider, "BC".equals(provider)); + } catch (ArrayIndexOutOfBoundsException success) { + assertEquals("BC", provider); } } public void testRSA_ECB_NoPadding_Private_OnlyDoFinal_TooBig_Failure() throws Exception { + for (String provider : RSA_PROVIDERS) { + testRSA_ECB_NoPadding_Private_OnlyDoFinal_TooBig_Failure(provider); + } + } + + private void testRSA_ECB_NoPadding_Private_OnlyDoFinal_TooBig_Failure(String provider) throws Exception { KeyFactory kf = KeyFactory.getInstance("RSA"); RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus, RSA_2048_privateExponent); final PrivateKey privKey = kf.generatePrivate(keySpec); - Cipher c = Cipher.getInstance("RSA/ECB/NoPadding"); + Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); /* * You're actually encrypting with public keys, but there is no @@ -1443,26 +1709,46 @@ public final class CipherTest extends TestCase { c.doFinal(tooBig_Vector); fail("Should have error when block size is too big."); } catch (IllegalBlockSizeException success) { + assertFalse(provider, "BC".equals(provider)); + } catch (ArrayIndexOutOfBoundsException success) { + assertEquals("BC", provider); } } public void testRSA_ECB_NoPadding_GetBlockSize_Success() throws Exception { - Cipher c = Cipher.getInstance("RSA/ECB/NoPadding"); - assertEquals("RSA is not a block cipher and should return block size of 0", - 0, c.getBlockSize()); + for (String provider : RSA_PROVIDERS) { + testRSA_ECB_NoPadding_GetBlockSize_Success(provider); + } + } + + private void testRSA_ECB_NoPadding_GetBlockSize_Success(String provider) throws Exception { + Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); + if (StandardNames.IS_RI) { + assertEquals(0, c.getBlockSize()); + } else { + try { + c.getBlockSize(); + fail(); + } catch (IllegalStateException expected) { + } + } KeyFactory kf = KeyFactory.getInstance("RSA"); RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent); final PublicKey pubKey = kf.generatePublic(pubKeySpec); c.init(Cipher.ENCRYPT_MODE, pubKey); - - assertEquals("RSA is not a block cipher and should return block size of 0", - 0, c.getBlockSize()); + assertEquals(getExpectedBlockSize("RSA", Cipher.ENCRYPT_MODE, provider), c.getBlockSize()); } public void testRSA_ECB_NoPadding_GetOutputSize_NoInit_Failure() throws Exception { - Cipher c = Cipher.getInstance("RSA/ECB/NoPadding"); + for (String provider : RSA_PROVIDERS) { + testRSA_ECB_NoPadding_GetOutputSize_NoInit_Failure(provider); + } + } + + private void testRSA_ECB_NoPadding_GetOutputSize_NoInit_Failure(String provider) throws Exception { + Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); try { c.getOutputSize(RSA_2048_Vector1.length); fail("Should throw IllegalStateException if getOutputSize is called before init"); @@ -1471,32 +1757,39 @@ public final class CipherTest extends TestCase { } public void testRSA_ECB_NoPadding_GetOutputSize_Success() throws Exception { + for (String provider : RSA_PROVIDERS) { + testRSA_ECB_NoPadding_GetOutputSize_Success(provider); + } + } + + private void testRSA_ECB_NoPadding_GetOutputSize_Success(String provider) throws Exception { KeyFactory kf = KeyFactory.getInstance("RSA"); RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent); final PublicKey pubKey = kf.generatePublic(pubKeySpec); - Cipher c = Cipher.getInstance("RSA/ECB/NoPadding"); + Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); c.init(Cipher.ENCRYPT_MODE, pubKey); final int modulusInBytes = RSA_2048_modulus.bitLength() / 8; - assertEquals("Output size should be equal to modulus size", - modulusInBytes, c.getOutputSize(RSA_2048_Vector1.length)); - - assertEquals("Output size should be equal to modulus size", - modulusInBytes, c.getOutputSize(RSA_2048_Vector1.length * 2)); - - assertEquals("Output size should be equal to modulus size", - modulusInBytes, c.getOutputSize(0)); + assertEquals(modulusInBytes, c.getOutputSize(RSA_2048_Vector1.length)); + assertEquals(modulusInBytes, c.getOutputSize(RSA_2048_Vector1.length * 2)); + assertEquals(modulusInBytes, c.getOutputSize(0)); } public void testRSA_ECB_NoPadding_GetIV_Success() throws Exception { + for (String provider : RSA_PROVIDERS) { + testRSA_ECB_NoPadding_GetIV_Success(provider); + } + } + + private void testRSA_ECB_NoPadding_GetIV_Success(String provider) throws Exception { KeyFactory kf = KeyFactory.getInstance("RSA"); RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent); final PublicKey pubKey = kf.generatePublic(pubKeySpec); - Cipher c = Cipher.getInstance("RSA/ECB/NoPadding"); + Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); assertNull("ECB mode has no IV and should be null", c.getIV()); c.init(Cipher.ENCRYPT_MODE, pubKey); @@ -1505,12 +1798,18 @@ public final class CipherTest extends TestCase { } public void testRSA_ECB_NoPadding_GetParameters_NoneProvided_Success() throws Exception { + for (String provider : RSA_PROVIDERS) { + testRSA_ECB_NoPadding_GetParameters_NoneProvided_Success(provider); + } + } + + private void testRSA_ECB_NoPadding_GetParameters_NoneProvided_Success(String provider) throws Exception { KeyFactory kf = KeyFactory.getInstance("RSA"); RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(RSA_2048_modulus, RSA_2048_publicExponent); final PublicKey pubKey = kf.generatePublic(pubKeySpec); - Cipher c = Cipher.getInstance("RSA/ECB/NoPadding"); + Cipher c = Cipher.getInstance("RSA/ECB/NoPadding", provider); assertNull("Parameters should be null", c.getParameters()); } @@ -1686,22 +1985,32 @@ public final class CipherTest extends TestCase { AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext, AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext_Padded, AES_128_ECB_PKCS5Padding_TestVector_1_Encrypted)); - CIPHER_TEST_PARAMS.add(new CipherTestParam("AES/CBC", AES_256_KEY, - AES_256_CBC_PKCS5Padding_TestVector_1_IV, - AES_256_CBC_PKCS5Padding_TestVector_1_Plaintext, - AES_256_CBC_PKCS5Padding_TestVector_1_Plaintext_Padded, - AES_256_CBC_PKCS5Padding_TestVector_1_Ciphertext)); + if (IS_UNLIMITED) { + CIPHER_TEST_PARAMS.add(new CipherTestParam("AES/CBC", AES_256_KEY, + AES_256_CBC_PKCS5Padding_TestVector_1_IV, + AES_256_CBC_PKCS5Padding_TestVector_1_Plaintext, + AES_256_CBC_PKCS5Padding_TestVector_1_Plaintext_Padded, + AES_256_CBC_PKCS5Padding_TestVector_1_Ciphertext)); + } } public void testCipher_Success() throws Exception { + for (String provider : AES_PROVIDERS) { + testCipher_Success(provider); + } + } + + private void testCipher_Success(String provider) throws Exception { final ByteArrayOutputStream errBuffer = new ByteArrayOutputStream(); PrintStream out = new PrintStream(errBuffer); for (CipherTestParam p : CIPHER_TEST_PARAMS) { try { - checkCipher(p); + checkCipher(p, provider); } catch (Exception e) { out.append("Error encountered checking " + p.mode + ", keySize=" - + (p.key.length * 8) + "\n"); + + (p.key.length * 8) + + " with provider " + provider + "\n"); + e.printStackTrace(out); } } @@ -1711,9 +2020,9 @@ public final class CipherTest extends TestCase { } } - private void checkCipher(CipherTestParam p) throws Exception { + private void checkCipher(CipherTestParam p, String provider) throws Exception { SecretKey key = new SecretKeySpec(p.key, "AES"); - Cipher c = Cipher.getInstance(p.mode + "/PKCS5Padding"); + Cipher c = Cipher.getInstance(p.mode + "/PKCS5Padding", provider); AlgorithmParameterSpec spec = null; if (p.iv != null) { spec = new IvParameterSpec(p.iv); @@ -1733,10 +2042,33 @@ public final class CipherTest extends TestCase { // empty decrypt { - assertNull(c.doFinal()); + if (StandardNames.IS_RI) { + assertEquals(Arrays.toString(EmptyArray.BYTE), + Arrays.toString(c.doFinal())); + + c.update(EmptyArray.BYTE); + assertEquals(Arrays.toString(EmptyArray.BYTE), + Arrays.toString(c.doFinal())); + } else if (provider.equals("BC")) { + try { + c.doFinal(); + fail(); + } catch (IllegalBlockSizeException expected) { + } + try { + c.update(EmptyArray.BYTE); + c.doFinal(); + fail(); + } catch (IllegalBlockSizeException expected) { + } + } else if (provider.equals("AndroidOpenSSL")) { + assertNull(c.doFinal()); - c.update(EmptyArray.BYTE); - assertNull(c.doFinal()); + c.update(EmptyArray.BYTE); + assertNull(c.doFinal()); + } else { + throw new AssertionError("Define your behavior here for " + provider); + } } // .doFinal(input) @@ -1769,7 +2101,7 @@ public final class CipherTest extends TestCase { Arrays.toString(Arrays.copyOfRange(actualPlaintext, 1, p.plaintext.length + 1))); } - Cipher cNoPad = Cipher.getInstance(p.mode + "/NoPadding"); + Cipher cNoPad = Cipher.getInstance(p.mode + "/NoPadding", provider); cNoPad.init(Cipher.DECRYPT_MODE, key, spec); final byte[] actualPlaintextPadded = cNoPad.doFinal(p.ciphertext); @@ -1799,14 +2131,21 @@ public final class CipherTest extends TestCase { } public void testCipher_ShortBlock_Failure() throws Exception { + for (String provider : AES_PROVIDERS) { + testCipher_ShortBlock_Failure(provider); + } + } + + private void testCipher_ShortBlock_Failure(String provider) throws Exception { final ByteArrayOutputStream errBuffer = new ByteArrayOutputStream(); PrintStream out = new PrintStream(errBuffer); for (CipherTestParam p : CIPHER_TEST_PARAMS) { try { - checkCipher_ShortBlock_Failure(p); + checkCipher_ShortBlock_Failure(p, provider); } catch (Exception e) { out.append("Error encountered checking " + p.mode + ", keySize=" - + (p.key.length * 8) + "\n"); + + (p.key.length * 8) + + " with provider " + provider + "\n"); e.printStackTrace(out); } } @@ -1816,9 +2155,9 @@ public final class CipherTest extends TestCase { } } - private void checkCipher_ShortBlock_Failure(CipherTestParam p) throws Exception { + private void checkCipher_ShortBlock_Failure(CipherTestParam p, String provider) throws Exception { SecretKey key = new SecretKeySpec(p.key, "AES"); - Cipher c = Cipher.getInstance(p.mode + "/NoPadding"); + Cipher c = Cipher.getInstance(p.mode + "/NoPadding", provider); if (c.getBlockSize() == 0) { return; } @@ -1832,8 +2171,14 @@ public final class CipherTest extends TestCase { } public void testAES_ECB_PKCS5Padding_ShortBuffer_Failure() throws Exception { + for (String provider : AES_PROVIDERS) { + testAES_ECB_PKCS5Padding_ShortBuffer_Failure(provider); + } + } + + private void testAES_ECB_PKCS5Padding_ShortBuffer_Failure(String provider) throws Exception { SecretKey key = new SecretKeySpec(AES_128_KEY, "AES"); - Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding"); + Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding", provider); c.init(Cipher.ENCRYPT_MODE, key); final byte[] fragmentOutput = c.update(AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext); @@ -1880,8 +2225,14 @@ public final class CipherTest extends TestCase { } public void testAES_ECB_NoPadding_IncrementalUpdate_Success() throws Exception { + for (String provider : AES_PROVIDERS) { + testAES_ECB_NoPadding_IncrementalUpdate_Success(provider); + } + } + + private void testAES_ECB_NoPadding_IncrementalUpdate_Success(String provider) throws Exception { SecretKey key = new SecretKeySpec(AES_128_KEY, "AES"); - Cipher c = Cipher.getInstance("AES/ECB/NoPadding"); + Cipher c = Cipher.getInstance("AES/ECB/NoPadding", provider); c.init(Cipher.ENCRYPT_MODE, key); for (int i = 0; i < AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext_Padded.length - 1; i++) { @@ -1906,8 +2257,14 @@ public final class CipherTest extends TestCase { }; public void testAES_ECB_NoPadding_IvParameters_Failure() throws Exception { + for (String provider : AES_PROVIDERS) { + testAES_ECB_NoPadding_IvParameters_Failure(provider); + } + } + + private void testAES_ECB_NoPadding_IvParameters_Failure(String provider) throws Exception { SecretKey key = new SecretKeySpec(AES_128_KEY, "AES"); - Cipher c = Cipher.getInstance("AES/ECB/NoPadding"); + Cipher c = Cipher.getInstance("AES/ECB/NoPadding", provider); AlgorithmParameterSpec spec = new IvParameterSpec(AES_IV_ZEROES); try { 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 a1122ce..b4da1b8 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 b861353..687e4a7 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 @@ -22,10 +22,14 @@ import java.math.BigInteger; 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; @@ -39,6 +43,7 @@ import javax.net.ssl.SSLException; import javax.net.ssl.SSLProtocolException; import javax.security.auth.x500.X500Principal; import junit.framework.TestCase; +import libcore.io.IoUtils; import libcore.java.security.StandardNames; import libcore.java.security.TestKeyStore; import org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSLHandshakeCallbacks; @@ -48,7 +53,8 @@ public class NativeCryptoTest extends TestCase { private static final int NULL = 0; private static final FileDescriptor INVALID_FD = new FileDescriptor(); - private static final SSLHandshakeCallbacks DUMMY_CB = new TestSSLHandshakeCallbacks(-1, null); + private static final SSLHandshakeCallbacks DUMMY_CB + = new TestSSLHandshakeCallbacks(null, 0, null); private static final long TIMEOUT_SECONDS = 5; @@ -137,6 +143,87 @@ 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); + + KeyPair kp1 = kpg.generateKeyPair(); + RSAPrivateCrtKey privKey1 = (RSAPrivateCrtKey) kp1.getPrivate(); + + KeyPair kp2 = kpg.generateKeyPair(); + RSAPrivateCrtKey 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); @@ -496,11 +583,14 @@ public class NativeCryptoTest extends TestCase { } public static class TestSSLHandshakeCallbacks implements SSLHandshakeCallbacks { + private final Socket socket; private final int sslNativePointer; private final Hooks hooks; - public TestSSLHandshakeCallbacks(int sslNativePointer, + public TestSSLHandshakeCallbacks(Socket socket, + int sslNativePointer, Hooks hooks) { + this.socket = socket; this.sslNativePointer = sslNativePointer; this.hooks = hooks; } @@ -552,6 +642,10 @@ public class NativeCryptoTest extends TestCase { } this.handshakeCompletedCalled = true; } + + public Socket getSocket() { + return socket; + } } public static class ServerHooks extends Hooks { @@ -589,12 +683,13 @@ public class NativeCryptoTest extends TestCase { listener.getLocalPort()) : listener.accept()); if (timeout == -1) { - return null; + return new TestSSLHandshakeCallbacks(socket, 0, null); } FileDescriptor fd = socket.getFileDescriptor$(); int c = hooks.getContext(); int s = hooks.beforeHandshake(c); - TestSSLHandshakeCallbacks callback = new TestSSLHandshakeCallbacks(s, hooks); + TestSSLHandshakeCallbacks callback + = new TestSSLHandshakeCallbacks(socket, s, hooks); if (DEBUG) { System.out.println("ssl=0x" + Integer.toString(s, 16) + " handshake" @@ -604,14 +699,19 @@ public class NativeCryptoTest extends TestCase { + " timeout=" + timeout + " client=" + client); } - int session = NativeCrypto.SSL_do_handshake(s, fd, callback, timeout, client, - npnProtocols); - if (DEBUG) { - System.out.println("ssl=0x" + Integer.toString(s, 16) - + " handshake" - + " session=0x" + Integer.toString(session, 16)); + int session = NULL; + try { + session = NativeCrypto.SSL_do_handshake(s, fd, callback, timeout, client, + npnProtocols); + if (DEBUG) { + System.out.println("ssl=0x" + Integer.toString(s, 16) + + " handshake" + + " session=0x" + Integer.toString(session, 16)); + } + } finally { + // Ensure afterHandshake is called to free resources + hooks.afterHandshake(session, s, c, socket, fd, callback); } - hooks.afterHandshake(session, s, c, socket, fd, callback); return callback; } }); @@ -783,17 +883,21 @@ public class NativeCryptoTest extends TestCase { Socket sock, FileDescriptor fd, SSLHandshakeCallbacks callback) throws Exception { - NativeCrypto.SSL_set_verify(s, NativeCrypto.SSL_VERIFY_PEER); - 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); - super.afterHandshake(session, s, c, sock, fd, callback); + try { + NativeCrypto.SSL_set_verify(s, NativeCrypto.SSL_VERIFY_PEER); + 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, + (int) ((TIMEOUT_SECONDS * 1000) / 2)); + } catch (IOException expected) { + } finally { + super.afterHandshake(session, s, c, sock, fd, callback); + } } }; Future<TestSSLHandshakeCallbacks> client = handshake(listener, 0, true, cHooks, null); Future<TestSSLHandshakeCallbacks> server = handshake(listener, 0, false, sHooks, null); - server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); try { client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); } catch (ExecutionException e) { @@ -801,35 +905,49 @@ public class NativeCryptoTest extends TestCase { throw e; } } + server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); } public void test_SSL_do_handshake_client_timeout() throws Exception { // client timeout final ServerSocket listener = new ServerSocket(0); + Socket serverSocket = null; try { Hooks cHooks = new Hooks(); Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()); Future<TestSSLHandshakeCallbacks> client = handshake(listener, 1, true, cHooks, null); Future<TestSSLHandshakeCallbacks> server = handshake(listener, -1, false, sHooks, null); + serverSocket = server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS).getSocket(); client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); fail(); } catch (ExecutionException expected) { + if (SocketTimeoutException.class != expected.getCause().getClass()) { + expected.printStackTrace(); + } assertEquals(SocketTimeoutException.class, expected.getCause().getClass()); + } finally { + // Manually close peer socket when testing timeout + IoUtils.closeQuietly(serverSocket); } } public void test_SSL_do_handshake_server_timeout() throws Exception { // server timeout final ServerSocket listener = new ServerSocket(0); + Socket clientSocket = null; try { Hooks cHooks = new Hooks(); Hooks sHooks = new ServerHooks(getServerPrivateKey(), getServerCertificates()); Future<TestSSLHandshakeCallbacks> client = handshake(listener, -1, true, cHooks, null); Future<TestSSLHandshakeCallbacks> server = handshake(listener, 1, false, sHooks, null); + clientSocket = client.get(TIMEOUT_SECONDS, TimeUnit.SECONDS).getSocket(); server.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); fail(); } catch (ExecutionException expected) { assertEquals(SocketTimeoutException.class, expected.getCause().getClass()); + } finally { + // Manually close peer socket when testing timeout + IoUtils.closeQuietly(clientSocket); } } @@ -1156,7 +1274,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); } }; @@ -1323,7 +1441,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); } }; @@ -1366,7 +1484,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) { } @@ -1376,7 +1494,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) { } @@ -1389,7 +1507,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) { } @@ -1402,7 +1520,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) { } @@ -1415,7 +1533,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/luni/src/test/java/tests/api/org/apache/harmony/kernel/dalvik/ThreadsTest.java b/luni/src/test/java/tests/api/org/apache/harmony/kernel/dalvik/ThreadsTest.java index bdc580d..9c9f346 100644 --- a/luni/src/test/java/tests/api/org/apache/harmony/kernel/dalvik/ThreadsTest.java +++ b/luni/src/test/java/tests/api/org/apache/harmony/kernel/dalvik/ThreadsTest.java @@ -17,7 +17,8 @@ package tests.api.org.apache.harmony.kernel.dalvik; import java.lang.reflect.Field; - +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.TimeUnit; import junit.framework.Assert; import junit.framework.TestCase; import sun.misc.Unsafe; @@ -50,10 +51,11 @@ public class ThreadsTest extends TestCase { /** Test the case where the park times out. */ public void test_parkFor_1() { - Parker parker = new Parker(false, 500); + CyclicBarrier barrier = new CyclicBarrier(2); + Parker parker = new Parker(barrier, false, 500); Thread parkerThread = new Thread(parker); Thread waiterThread = - new Thread(new WaitAndUnpark(1000, parkerThread)); + new Thread(new WaitAndUnpark(barrier, 1000, parkerThread)); parkerThread.start(); waiterThread.start(); @@ -62,10 +64,11 @@ public class ThreadsTest extends TestCase { /** Test the case where the unpark happens before the timeout. */ public void test_parkFor_2() { - Parker parker = new Parker(false, 1000); + CyclicBarrier barrier = new CyclicBarrier(2); + Parker parker = new Parker(barrier, false, 1000); Thread parkerThread = new Thread(parker); Thread waiterThread = - new Thread(new WaitAndUnpark(300, parkerThread)); + new Thread(new WaitAndUnpark(barrier, 300, parkerThread)); parkerThread.start(); waiterThread.start(); @@ -74,7 +77,8 @@ public class ThreadsTest extends TestCase { /** Test the case where the thread is preemptively unparked. */ public void test_parkFor_3() { - Parker parker = new Parker(false, 1000); + CyclicBarrier barrier = new CyclicBarrier(1); + Parker parker = new Parker(barrier, false, 1000); Thread parkerThread = new Thread(parker); UNSAFE.unpark(parkerThread); @@ -84,10 +88,11 @@ public class ThreadsTest extends TestCase { /** Test the case where the park times out. */ public void test_parkUntil_1() { - Parker parker = new Parker(true, 500); + CyclicBarrier barrier = new CyclicBarrier(2); + Parker parker = new Parker(barrier, true, 500); Thread parkerThread = new Thread(parker); Thread waiterThread = - new Thread(new WaitAndUnpark(1000, parkerThread)); + new Thread(new WaitAndUnpark(barrier, 1000, parkerThread)); parkerThread.start(); waiterThread.start(); @@ -96,10 +101,11 @@ public class ThreadsTest extends TestCase { /** Test the case where the unpark happens before the timeout. */ public void test_parkUntil_2() { - Parker parker = new Parker(true, 1000); + CyclicBarrier barrier = new CyclicBarrier(2); + Parker parker = new Parker(barrier, true, 1000); Thread parkerThread = new Thread(parker); Thread waiterThread = - new Thread(new WaitAndUnpark(300, parkerThread)); + new Thread(new WaitAndUnpark(barrier, 300, parkerThread)); parkerThread.start(); waiterThread.start(); @@ -108,7 +114,8 @@ public class ThreadsTest extends TestCase { /** Test the case where the thread is preemptively unparked. */ public void test_parkUntil_3() { - Parker parker = new Parker(true, 1000); + CyclicBarrier barrier = new CyclicBarrier(1); + Parker parker = new Parker(barrier, true, 1000); Thread parkerThread = new Thread(parker); UNSAFE.unpark(parkerThread); @@ -123,6 +130,9 @@ public class ThreadsTest extends TestCase { * the indicated value, noting the duration of time actually parked. */ private static class Parker implements Runnable { + + private final CyclicBarrier barrier; + /** whether {@link #amount} is milliseconds to wait in an * absolute fashion (<code>true</code>) or nanoseconds to wait * in a relative fashion (<code>false</code>) */ @@ -147,7 +157,8 @@ public class ThreadsTest extends TestCase { * either case, this constructor takes a duration to park for * @param parkMillis the number of milliseconds to be parked */ - public Parker(boolean absolute, long parkMillis) { + public Parker(CyclicBarrier barrier, boolean absolute, long parkMillis) { + this.barrier = barrier; this.absolute = absolute; // Multiply by 1000000 because parkFor() takes nanoseconds. @@ -155,8 +166,14 @@ public class ThreadsTest extends TestCase { } public void run() { + try { + barrier.await(60, TimeUnit.SECONDS); + } catch (Exception e) { + throw new AssertionError(e); + } boolean absolute = this.absolute; long amount = this.amount; + long startNanos = System.nanoTime(); long start = System.currentTimeMillis(); if (absolute) { @@ -165,11 +182,11 @@ public class ThreadsTest extends TestCase { UNSAFE.park(false, amount); } - long end = System.currentTimeMillis(); + long endNanos = System.nanoTime(); synchronized (this) { - startMillis = start; - endMillis = end; + startMillis = startNanos / 1000000; + endMillis = endNanos / 1000000; completed = true; notifyAll(); } @@ -230,16 +247,23 @@ public class ThreadsTest extends TestCase { * specified amount of time and then unparks an indicated thread. */ private static class WaitAndUnpark implements Runnable { + private final CyclicBarrier barrier; private final long waitMillis; private final Thread thread; - public WaitAndUnpark(long waitMillis, Thread thread) { + public WaitAndUnpark(CyclicBarrier barrier, long waitMillis, Thread thread) { + this.barrier = barrier; this.waitMillis = waitMillis; this.thread = thread; } public void run() { try { + barrier.await(60, TimeUnit.SECONDS); + } catch (Exception e) { + throw new AssertionError(e); + } + try { Thread.sleep(waitMillis); } catch (InterruptedException ex) { throw new RuntimeException("shouldn't happen", ex); diff --git a/support/src/test/java/libcore/java/security/StandardNames.java b/support/src/test/java/libcore/java/security/StandardNames.java index d5ceedf..7778896 100644 --- a/support/src/test/java/libcore/java/security/StandardNames.java +++ b/support/src/test/java/libcore/java/security/StandardNames.java @@ -352,14 +352,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"); @@ -498,6 +490,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"); + } } } |