am 9f178544: am 44e8930b: Bumper ZipFile/ZipEntry backport.
* commit '9f1785441b6e81fe158b735c089758fde3b657ed':
Bumper ZipFile/ZipEntry backport.
diff --git a/JavaLibrary.mk b/JavaLibrary.mk
index 59ac2e1..26a586a 100644
--- a/JavaLibrary.mk
+++ b/JavaLibrary.mk
@@ -55,9 +55,11 @@
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_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_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 @@
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 @@
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 @@
/** 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 @@
* @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 @@
* @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/expectations/knownfailures.txt b/expectations/knownfailures.txt
index 972f1ef..5e24be3 100644
--- a/expectations/knownfailures.txt
+++ b/expectations/knownfailures.txt
@@ -194,15 +194,6 @@
bug: 2400429
},
{
- description: "Concurrent close tests fail on the device",
- names: [
- "libcore.java.net.ConcurrentCloseTest#test_connect",
- "libcore.java.net.ConcurrentCloseTest#test_connect_nonBlocking"
- ],
- modes: [ "device" ],
- bug: 3044772
-},
-{
description: "HTTPS connections should not be pooled.",
name: "libcore.java.net.URLConnectionTest#testConnectViaHttpsReusingConnectionsDifferentFactories",
bug: 3042192
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 @@
* @see java.lang.Thread
*/
public final void wait() throws InterruptedException {
- wait(0 ,0);
+ wait(0, 0);
}
/**
diff --git a/luni/src/main/java/java/nio/PipeImpl.java b/luni/src/main/java/java/nio/PipeImpl.java
index 50028f4..d4dde3b 100644
--- a/luni/src/main/java/java/nio/PipeImpl.java
+++ b/luni/src/main/java/java/nio/PipeImpl.java
@@ -19,8 +19,8 @@
import java.io.Closeable;
import java.io.FileDescriptor;
import java.io.IOException;
-import java.nio.channels.FileChannel;
import java.nio.channels.Pipe;
+import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;
import libcore.io.ErrnoException;
import libcore.io.IoUtils;
@@ -34,13 +34,16 @@
private final PipeSinkChannel sink;
private final PipeSourceChannel source;
- public PipeImpl() throws IOException {
+ public PipeImpl(SelectorProvider selectorProvider) throws IOException {
try {
- FileDescriptor[] fds = Libcore.os.pipe();
- // Which fd is used for which channel is important. Unix pipes are only guaranteed to be
- // unidirectional, and indeed are only unidirectional on Linux.
- this.sink = new PipeSinkChannel(fds[1]);
- this.source = new PipeSourceChannel(fds[0]);
+ FileDescriptor fd1 = new FileDescriptor();
+ FileDescriptor fd2 = new FileDescriptor();
+ Libcore.os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd1, fd2);
+
+ // It doesn't matter which file descriptor we use for which end;
+ // they're guaranteed to be indistinguishable.
+ this.sink = new PipeSinkChannel(selectorProvider, fd1);
+ this.source = new PipeSourceChannel(selectorProvider, fd2);
} catch (ErrnoException errnoException) {
throw errnoException.rethrowAsIOException();
}
@@ -54,27 +57,14 @@
return source;
}
- /**
- * FileChannelImpl doesn't close its fd itself; it calls close on the object it's given.
- */
- private static class FdCloser implements Closeable {
- private final FileDescriptor fd;
- private FdCloser(FileDescriptor fd) {
- this.fd = fd;
- }
- public void close() throws IOException {
- IoUtils.close(fd);
- }
- }
-
private class PipeSourceChannel extends Pipe.SourceChannel implements FileDescriptorChannel {
private final FileDescriptor fd;
- private final FileChannel channel;
+ private final SocketChannel channel;
- private PipeSourceChannel(FileDescriptor fd) throws IOException {
- super(SelectorProvider.provider());
+ private PipeSourceChannel(SelectorProvider selectorProvider, FileDescriptor fd) throws IOException {
+ super(selectorProvider);
this.fd = fd;
- this.channel = NioUtils.newFileChannel(new FdCloser(fd), fd, O_RDONLY);
+ this.channel = new SocketChannelImpl(selectorProvider, fd);
}
@Override protected void implCloseSelectableChannel() throws IOException {
@@ -104,12 +94,12 @@
private class PipeSinkChannel extends Pipe.SinkChannel implements FileDescriptorChannel {
private final FileDescriptor fd;
- private final FileChannel channel;
+ private final SocketChannel channel;
- private PipeSinkChannel(FileDescriptor fd) throws IOException {
- super(SelectorProvider.provider());
+ private PipeSinkChannel(SelectorProvider selectorProvider, FileDescriptor fd) throws IOException {
+ super(selectorProvider);
this.fd = fd;
- this.channel = NioUtils.newFileChannel(new FdCloser(fd), fd, O_WRONLY);
+ this.channel = new SocketChannelImpl(selectorProvider, fd);
}
@Override protected void implCloseSelectableChannel() throws IOException {
diff --git a/luni/src/main/java/java/nio/SelectorProviderImpl.java b/luni/src/main/java/java/nio/SelectorProviderImpl.java
index 03003fe..b7c34e8 100644
--- a/luni/src/main/java/java/nio/SelectorProviderImpl.java
+++ b/luni/src/main/java/java/nio/SelectorProviderImpl.java
@@ -34,7 +34,7 @@
}
public Pipe openPipe() throws IOException {
- return new PipeImpl();
+ return new PipeImpl(this);
}
public AbstractSelector openSelector() throws IOException {
diff --git a/luni/src/main/java/java/nio/SocketChannelImpl.java b/luni/src/main/java/java/nio/SocketChannelImpl.java
index ff2c157..233daf0 100644
--- a/luni/src/main/java/java/nio/SocketChannelImpl.java
+++ b/luni/src/main/java/java/nio/SocketChannelImpl.java
@@ -103,6 +103,15 @@
}
/*
+ * Constructor for use by Pipe.SinkChannel and Pipe.SourceChannel.
+ */
+ public SocketChannelImpl(SelectorProvider selectorProvider, FileDescriptor existingFd) throws IOException {
+ super(selectorProvider);
+ status = SOCKET_STATUS_CONNECTED;
+ fd = existingFd;
+ }
+
+ /*
* Getting the internal Socket If we have not the socket, we create a new
* one.
*/
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 @@
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/BlockGuardOs.java b/luni/src/main/java/libcore/io/BlockGuardOs.java
index 61c9765..c61a3cf 100644
--- a/luni/src/main/java/libcore/io/BlockGuardOs.java
+++ b/luni/src/main/java/libcore/io/BlockGuardOs.java
@@ -181,6 +181,12 @@
return tagSocket(os.socket(domain, type, protocol));
}
+ @Override public void socketpair(int domain, int type, int protocol, FileDescriptor fd1, FileDescriptor fd2) throws ErrnoException {
+ os.socketpair(domain, type, protocol, fd1, fd2);
+ tagSocket(fd1);
+ tagSocket(fd2);
+ }
+
@Override public int write(FileDescriptor fd, ByteBuffer buffer) throws ErrnoException {
BlockGuard.getThreadPolicy().onWriteToDisk();
return os.write(fd, buffer);
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/libcore/io/ForwardingOs.java b/luni/src/main/java/libcore/io/ForwardingOs.java
index 719c5f0..ee26d04 100644
--- a/luni/src/main/java/libcore/io/ForwardingOs.java
+++ b/luni/src/main/java/libcore/io/ForwardingOs.java
@@ -121,6 +121,7 @@
public void setuid(int uid) throws ErrnoException { os.setuid(uid); }
public void shutdown(FileDescriptor fd, int how) throws ErrnoException { os.shutdown(fd, how); }
public FileDescriptor socket(int domain, int type, int protocol) throws ErrnoException { return os.socket(domain, type, protocol); }
+ public void socketpair(int domain, int type, int protocol, FileDescriptor fd1, FileDescriptor fd2) throws ErrnoException { os.socketpair(domain, type, protocol, fd1, fd2); }
public StructStat stat(String path) throws ErrnoException { return os.stat(path); }
public StructStatFs statfs(String path) throws ErrnoException { return os.statfs(path); }
public String strerror(int errno) { return os.strerror(errno); }
diff --git a/luni/src/main/java/libcore/io/Os.java b/luni/src/main/java/libcore/io/Os.java
index 55588d8..1f42497 100644
--- a/luni/src/main/java/libcore/io/Os.java
+++ b/luni/src/main/java/libcore/io/Os.java
@@ -114,6 +114,7 @@
public void setuid(int uid) throws ErrnoException;
public void shutdown(FileDescriptor fd, int how) throws ErrnoException;
public FileDescriptor socket(int domain, int type, int protocol) throws ErrnoException;
+ public void socketpair(int domain, int type, int protocol, FileDescriptor fd1, FileDescriptor fd2) throws ErrnoException;
public StructStat stat(String path) throws ErrnoException;
/* TODO: replace statfs with statvfs. */
public StructStatFs statfs(String path) throws ErrnoException;
diff --git a/luni/src/main/java/libcore/io/Posix.java b/luni/src/main/java/libcore/io/Posix.java
index ad01bcf..2fb187e 100644
--- a/luni/src/main/java/libcore/io/Posix.java
+++ b/luni/src/main/java/libcore/io/Posix.java
@@ -165,6 +165,7 @@
public native void setuid(int uid) throws ErrnoException;
public native void shutdown(FileDescriptor fd, int how) throws ErrnoException;
public native FileDescriptor socket(int domain, int type, int protocol) throws ErrnoException;
+ public native void socketpair(int domain, int type, int protocol, FileDescriptor fd1, FileDescriptor fd2) throws ErrnoException;
public native StructStat stat(String path) throws ErrnoException;
public native StructStatFs statfs(String path) throws ErrnoException;
public native String strerror(int errno);
diff --git a/luni/src/main/java/libcore/net/http/HttpEngine.java b/luni/src/main/java/libcore/net/http/HttpEngine.java
index a370956..42c9b96 100644
--- a/luni/src/main/java/libcore/net/http/HttpEngine.java
+++ b/luni/src/main/java/libcore/net/http/HttpEngine.java
@@ -491,8 +491,15 @@
reusable = false;
}
- // If the headers specify that the connection shouldn't be reused, don't reuse it.
- if (hasConnectionCloseHeader()) {
+ // If the request specified that the connection shouldn't be reused,
+ // don't reuse it. This advice doesn't apply to CONNECT requests because
+ // the "Connection: close" header goes the origin server, not the proxy.
+ if (requestHeaders.hasConnectionClose() && method != CONNECT) {
+ reusable = false;
+ }
+
+ // If the response specified that the connection shouldn't be reused, don't reuse it.
+ if (responseHeaders != null && responseHeaders.hasConnectionClose()) {
reusable = false;
}
@@ -524,8 +531,13 @@
/*
* If the response was transparently gzipped, remove the gzip header field
* so clients don't double decompress. http://b/3009828
+ *
+ * Also remove the Content-Length in this case because it contains the length
+ * of the gzipped response. This isn't terribly useful and is dangerous because
+ * clients can query the content length, but not the content encoding.
*/
responseHeaders.stripContentEncoding();
+ responseHeaders.stripContentLength();
responseBodyIn = new GZIPInputStream(transferStream);
} else {
responseBodyIn = transferStream;
@@ -759,11 +771,6 @@
return agent != null ? agent : ("Java" + System.getProperty("java.version"));
}
- private boolean hasConnectionCloseHeader() {
- return (responseHeaders != null && responseHeaders.hasConnectionClose())
- || requestHeaders.hasConnectionClose();
- }
-
protected final String getOriginAddress(URL url) {
int port = url.getPort();
String result = url.getHost();
diff --git a/luni/src/main/java/libcore/net/http/ResponseHeaders.java b/luni/src/main/java/libcore/net/http/ResponseHeaders.java
index 003b445..c0b4200 100644
--- a/luni/src/main/java/libcore/net/http/ResponseHeaders.java
+++ b/luni/src/main/java/libcore/net/http/ResponseHeaders.java
@@ -187,6 +187,11 @@
headers.removeAll("Content-Encoding");
}
+ public void stripContentLength() {
+ contentLength = -1;
+ headers.removeAll("Content-Length");
+ }
+
public boolean isChunked() {
return "chunked".equalsIgnoreCase(transferEncoding);
}
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.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 @@
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 @@
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 @@
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 @@
host = engineOwner.getPeerHost();
port = engineOwner.getPeerPort();
} else {
- host = socketOwner.getInetAddress().getHostName();
- port = socketOwner.getPort();
+ host = socketOwner.getPeerHostName();
+ port = socketOwner.getPeerPort();
}
if (host == null || port == -1) {
return null; // starts new session
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java
index 84f33f2..65373ff 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java
@@ -78,6 +78,8 @@
public static native void EVP_PKEY_free(int pkey);
+ public static native int EVP_PKEY_cmp(int pkey1, int pkey2);
+
public static native byte[] i2d_PKCS8_PRIV_KEY_INFO(int pkey);
public static native int d2i_PKCS8_PRIV_KEY_INFO(byte[] data);
@@ -643,7 +645,7 @@
public static native int SSL_read(int sslNativePointer,
FileDescriptor fd,
SSLHandshakeCallbacks shc,
- byte[] b, int off, int len, int timeoutMillis)
+ byte[] b, int off, int len, int readTimeoutMillis)
throws IOException;
/**
@@ -652,7 +654,7 @@
public 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 @@
@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 e1d0fb0..d4aa57f 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
@@ -73,33 +73,32 @@
// put("KeyFactory.DSA", OpenSSLDSAKeyFactory.class.getName());
// Signatures
- put("Signature.MD5WithRSAEncryption", OpenSSLSignature.MD5RSA.class.getName());
- put("Alg.Alias.Signature.MD5WithRSA", "MD5WithRSAEncryption");
- put("Alg.Alias.Signature.MD5/RSA", "MD5WithRSAEncryption");
- put("Alg.Alias.Signature.1.2.840.113549.1.1.4", "MD5WithRSAEncryption");
- put("Alg.Alias.Signature.1.2.840.113549.2.5with1.2.840.113549.1.1.1",
- "MD5WithRSAEncryption");
+ put("Signature.MD5WithRSA", OpenSSLSignature.MD5RSA.class.getName());
+ put("Alg.Alias.Signature.MD5WithRSAEncryption", "MD5WithRSA");
+ put("Alg.Alias.Signature.MD5/RSA", "MD5WithRSA");
+ put("Alg.Alias.Signature.1.2.840.113549.1.1.4", "MD5WithRSA");
+ put("Alg.Alias.Signature.1.2.840.113549.2.5with1.2.840.113549.1.1.1", "MD5WithRSA");
- 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.SHA1WithRSA", OpenSSLSignature.SHA1RSA.class.getName());
+ put("Alg.Alias.Signature.SHA1WithRSA", "SHA1WithRSA");
+ put("Alg.Alias.Signature.SHA1/RSA", "SHA1WithRSA");
+ put("Alg.Alias.Signature.SHA-1/RSA", "SHA1WithRSA");
+ put("Alg.Alias.Signature.1.2.840.113549.1.1.5", "SHA1WithRSA");
+ put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.113549.1.1.1", "SHA1WithRSA");
+ put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.113549.1.1.5", "SHA1WithRSA");
+ put("Alg.Alias.Signature.1.3.14.3.2.29", "SHA1WithRSA");
- put("Signature.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.SHA256WithRSA", OpenSSLSignature.SHA256RSA.class.getName());
+ put("Alg.Alias.Signature.SHA256WithRSAEncryption", "SHA256WithRSA");
+ put("Alg.Alias.Signature.1.2.840.113549.1.1.11", "SHA256WithRSA");
- put("Signature.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("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("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 48e1494..4303e5a 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
@@ -191,8 +191,8 @@
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
@@ -202,28 +202,35 @@
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 5c2f075..adb05a9 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
@@ -201,14 +201,7 @@
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.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 @@
* 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 @@
}
// 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 @@
// 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 @@
}
}
- private String getPeerHostName() {
+ String getPeerHostName() {
if (wrappedHost != null) {
return wrappedHost;
}
@@ -429,7 +437,7 @@
return null;
}
- private int getPeerPort() {
+ int getPeerPort() {
return wrappedHost == null ? super.getPort() : wrappedPort;
}
@@ -570,8 +578,13 @@
}
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 @@
return;
}
NativeCrypto.SSL_write(sslNativePointer, socket.getFileDescriptor$(),
- OpenSSLSocketImpl.this, buf, offset, byteCount);
+ OpenSSLSocketImpl.this, buf, offset, byteCount, writeTimeoutMilliseconds);
}
}
}
@@ -822,21 +835,42 @@
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 @@
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 @@
// 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 @@
*/
protected SSLSocketImpl(SSLParametersImpl sslParameters) {
this.sslParameters = sslParameters;
+ this.wrappedHost = null;
+ this.wrappedPort = -1;
// init should be called after creation!
}
@@ -99,6 +105,8 @@
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 @@
SSLParametersImpl sslParameters) throws IOException,
UnknownHostException {
super(host, port, localHost, localPort);
+ this.wrappedHost = host;
+ this.wrappedPort = port;
this.sslParameters = sslParameters;
init();
}
@@ -138,6 +148,8 @@
SSLParametersImpl sslParameters) throws IOException {
super(host, port);
this.sslParameters = sslParameters;
+ this.wrappedHost = null;
+ this.wrappedPort = -1;
init();
}
@@ -158,6 +170,8 @@
SSLParametersImpl sslParameters) throws IOException {
super(address, port, localAddress, localPort);
this.sslParameters = sslParameters;
+ this.wrappedHost = null;
+ this.wrappedPort = -1;
init();
}
@@ -193,6 +207,29 @@
}
}
+ 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 @@
private final Socket socket;
private final boolean autoClose;
- protected SSLSocketWrapper(Socket socket, boolean autoClose, SSLParametersImpl sslParameters) throws IOException {
- super(sslParameters);
+ protected SSLSocketWrapper(Socket socket, String host, int port, boolean autoClose,
+ SSLParametersImpl sslParameters) throws IOException {
+ super(host, port, sslParameters);
if (!socket.isConnected()) {
throw new SocketException("Socket is not connected.");
}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustManagerImpl.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustManagerImpl.java
index 3f362c5..0218249 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustManagerImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustManagerImpl.java
@@ -35,6 +35,7 @@
import java.util.List;
import java.util.Set;
import javax.net.ssl.X509TrustManager;
+import libcore.io.EventLogger;
/**
*
@@ -52,6 +53,11 @@
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 @@
* @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 @@
} 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 @@
@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 @@
trustedCertificateIndex.reset();
} else {
trustedCertificateIndex.reset(trustAnchors(acceptedIssuers));
- }
+ }
}
- private void checkTrusted(X509Certificate[] chain, String authType)
+ private List<X509Certificate> checkTrusted(X509Certificate[] chain, String authType, String host)
throws CertificateException {
if (chain == null || chain.length == 0 || authType == null || authType.length() == 0) {
throw new IllegalArgumentException("null or zero-length parameter");
@@ -180,21 +214,71 @@
throw new CertificateException(err);
}
- Set<TrustAnchor> trustAnchors = new HashSet<TrustAnchor>();
- X509Certificate[] newChain = cleanupCertChainAndFindTrustAnchors(chain, trustAnchors);
- if (newChain.length == 0) {
- // chain was entirely trusted, skip the validator
- return;
+ // 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 (trustAnchors.isEmpty()) {
+
+ 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 wholeChain;
+ }
+
+ if (trustAnchor.isEmpty()) {
throw new CertificateException(new CertPathValidatorException(
"Trust anchor for certification path not found.", null, certPath, -1));
}
try {
- PKIXParameters params = new PKIXParameters(trustAnchors);
+ PKIXParameters params = new PKIXParameters(trustAnchor);
params.setRevocationEnabled(false);
validator.validate(certPath, params);
// Add intermediate CAs to the index to tolerate sites
@@ -211,6 +295,8 @@
} catch (CertPathValidatorException e) {
throw new CertificateException(e);
}
+
+ return wholeChain;
}
/**
@@ -232,17 +318,9 @@
// Start with the first certificate in the chain, assuming it
// is the leaf certificate (server or client cert).
for (currIndex = 0; currIndex < chain.length; currIndex++) {
- // If the current cert is a TrustAnchor, we can ignore the rest of the chain.
- // This avoids including "bridge" CA certs that added for legacy compatability.
- TrustAnchor trustAnchor = findTrustAnchorBySubjectAndPublicKey(chain[currIndex]);
- if (trustAnchor != null) {
- trustAnchors.add(trustAnchor);
- currIndex--;
- break;
- }
- // Walk the rest of the chain to find a "subject" matching
+ // Walk the chain to find a "subject" matching
// the "issuer" of the current certificate. In a properly
- // order chain this should be the next cert and be fast.
+ // ordered chain this should be the next cert and be fast.
// If not, we reorder things to be as the validator will
// expect.
boolean foundNext = false;
@@ -271,15 +349,27 @@
}
}
- // 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 @@
}
/**
+ * 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/libcore_io_Posix.cpp b/luni/src/main/native/libcore_io_Posix.cpp
index dd9b87f..acb3dc2 100644
--- a/luni/src/main/native/libcore_io_Posix.cpp
+++ b/luni/src/main/native/libcore_io_Posix.cpp
@@ -1168,6 +1168,15 @@
return fd != -1 ? jniCreateFileDescriptor(env, fd) : NULL;
}
+static void Posix_socketpair(JNIEnv* env, jobject, jint domain, jint type, jint protocol, jobject javaFd1, jobject javaFd2) {
+ int fds[2];
+ int rc = throwIfMinusOne(env, "socketpair", TEMP_FAILURE_RETRY(socketpair(domain, type, protocol, fds)));
+ if (rc != -1) {
+ jniSetFileDescriptorOfFD(env, javaFd1, fds[0]);
+ jniSetFileDescriptorOfFD(env, javaFd2, fds[1]);
+ }
+}
+
static jobject Posix_stat(JNIEnv* env, jobject, jstring javaPath) {
return doStat(env, javaPath, false);
}
@@ -1341,6 +1350,7 @@
NATIVE_METHOD(Posix, setuid, "(I)V"),
NATIVE_METHOD(Posix, shutdown, "(Ljava/io/FileDescriptor;I)V"),
NATIVE_METHOD(Posix, socket, "(III)Ljava/io/FileDescriptor;"),
+ NATIVE_METHOD(Posix, socketpair, "(IIILjava/io/FileDescriptor;Ljava/io/FileDescriptor;)V"),
NATIVE_METHOD(Posix, stat, "(Ljava/lang/String;)Llibcore/io/StructStat;"),
NATIVE_METHOD(Posix, statfs, "(Ljava/lang/String;)Llibcore/io/StructStatFs;"),
NATIVE_METHOD(Posix, strerror, "(I)Ljava/lang/String;"),
diff --git a/luni/src/main/native/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp b/luni/src/main/native/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp
index a04bebf..322f416 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
@@ -505,11 +505,11 @@
/**
* Converts an OpenSSL BIGNUM to a Java byte[] array.
*/
-static jbyteArray bignumToArray(JNIEnv* env, BIGNUM* source) {
- JNI_TRACE("bignumToArray(%p)", source);
+static jbyteArray bignumToArray(JNIEnv* env, BIGNUM* source, const char* sourceName) {
+ JNI_TRACE("bignumToArray(%p, %s)", source, sourceName);
if (source == NULL) {
- jniThrowNullPointerException(env, NULL);
+ jniThrowNullPointerException(env, sourceName);
return NULL;
}
@@ -517,7 +517,7 @@
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;
}
@@ -535,7 +535,7 @@
return NULL;
}
- JNI_TRACE("bignumToArray(%p) => %p", source, javaBytes);
+ JNI_TRACE("bignumToArray(%p, %s) => %p", source, sourceName, javaBytes);
return javaBytes;
}
@@ -923,6 +923,26 @@
}
}
+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[])
*/
@@ -1184,13 +1204,13 @@
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;
}
@@ -1217,14 +1237,14 @@
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;
}
@@ -1232,7 +1252,7 @@
}
if (rsa->d != NULL) {
- jbyteArray d = bignumToArray(env, rsa->d);
+ jbyteArray d = bignumToArray(env, rsa->d, "d");
if (env->ExceptionCheck()) {
return NULL;
}
@@ -1240,7 +1260,7 @@
}
if (rsa->p != NULL) {
- jbyteArray p = bignumToArray(env, rsa->p);
+ jbyteArray p = bignumToArray(env, rsa->p, "p");
if (env->ExceptionCheck()) {
return NULL;
}
@@ -1248,7 +1268,7 @@
}
if (rsa->q != NULL) {
- jbyteArray q = bignumToArray(env, rsa->q);
+ jbyteArray q = bignumToArray(env, rsa->q, "q");
if (env->ExceptionCheck()) {
return NULL;
}
@@ -1256,7 +1276,7 @@
}
if (rsa->dmp1 != NULL) {
- jbyteArray dmp1 = bignumToArray(env, rsa->dmp1);
+ jbyteArray dmp1 = bignumToArray(env, rsa->dmp1, "dmp1");
if (env->ExceptionCheck()) {
return NULL;
}
@@ -1264,7 +1284,7 @@
}
if (rsa->dmq1 != NULL) {
- jbyteArray dmq1 = bignumToArray(env, rsa->dmq1);
+ jbyteArray dmq1 = bignumToArray(env, rsa->dmq1, "dmq1");
if (env->ExceptionCheck()) {
return NULL;
}
@@ -1272,7 +1292,7 @@
}
if (rsa->iqmp != NULL) {
- jbyteArray iqmp = bignumToArray(env, rsa->iqmp);
+ jbyteArray iqmp = bignumToArray(env, rsa->iqmp, "iqmp");
if (env->ExceptionCheck()) {
return NULL;
}
@@ -1377,26 +1397,26 @@
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;
}
@@ -1404,7 +1424,7 @@
}
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;
}
@@ -1790,6 +1810,13 @@
if (ok < 0) {
throwExceptionIfNecessary(env, "NativeCrypto_EVP_VerifyFinal");
}
+
+ /*
+ * For DSA keys, OpenSSL appears to have a bug where it returns
+ * errors for any result != 1. See dsa_ossl.c in dsa_do_verify
+ */
+ freeOpenSslErrorState();
+
JNI_TRACE("NativeCrypto_EVP_VerifyFinal(%p, %p, %d, %d, %p) => %d",
ctx, buffer, offset, length, pkey, ok);
@@ -2244,12 +2271,15 @@
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();
@@ -3735,7 +3765,7 @@
* cleanly shut down, or THROW_SSLEXCEPTION if an exception should be thrown.
*/
static int sslRead(JNIEnv* env, SSL* ssl, jobject fdObject, jobject shc, char* buf, jint len,
- int* sslReturnCode, int* sslErrorCode, int timeout_millis) {
+ int* sslReturnCode, int* sslErrorCode, int read_timeout_millis) {
JNI_TRACE("ssl=%p sslRead buf=%p len=%d", ssl, buf, len);
if (len == 0) {
@@ -3814,7 +3844,7 @@
// Need to wait for availability of underlying layer, then retry.
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE: {
- int selectResult = sslSelect(env, sslError, fdObject, appData, timeout_millis);
+ int selectResult = sslSelect(env, sslError, fdObject, appData, read_timeout_millis);
if (selectResult == THROWN_EXCEPTION) {
return THROWN_EXCEPTION;
}
@@ -3866,11 +3896,11 @@
*/
static jint NativeCrypto_SSL_read(JNIEnv* env, jclass, jint ssl_address, jobject fdObject,
jobject shc, jbyteArray b, jint offset, jint len,
- jint timeout_millis)
+ jint read_timeout_millis)
{
SSL* ssl = to_SSL(env, ssl_address, true);
- JNI_TRACE("ssl=%p NativeCrypto_SSL_read fd=%p shc=%p b=%p offset=%d len=%d timeout_millis=%d",
- ssl, fdObject, shc, b, offset, len, timeout_millis);
+ JNI_TRACE("ssl=%p NativeCrypto_SSL_read fd=%p shc=%p b=%p offset=%d len=%d read_timeout_millis=%d",
+ ssl, fdObject, shc, b, offset, len, read_timeout_millis);
if (ssl == NULL) {
return 0;
}
@@ -3894,7 +3924,7 @@
int sslErrorCode = SSL_ERROR_NONE;;
int ret = sslRead(env, ssl, fdObject, shc, reinterpret_cast<char*>(bytes.get() + offset), len,
- &returnCode, &sslErrorCode, timeout_millis);
+ &returnCode, &sslErrorCode, read_timeout_millis);
int result;
switch (ret) {
@@ -3934,8 +3964,9 @@
* 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.
@@ -4020,7 +4051,7 @@
// it's also not standard Java behavior, so we wait forever here.
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE: {
- int selectResult = sslSelect(env, sslError, fdObject, appData, 0);
+ int selectResult = sslSelect(env, sslError, fdObject, appData, write_timeout_millis);
if (selectResult == THROWN_EXCEPTION) {
return THROWN_EXCEPTION;
}
@@ -4071,11 +4102,11 @@
* 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;
}
@@ -4098,7 +4129,7 @@
int returnCode = 0;
int sslErrorCode = SSL_ERROR_NONE;
int ret = sslWrite(env, ssl, fdObject, shc, reinterpret_cast<const char*>(bytes.get() + offset),
- len, &returnCode, &sslErrorCode);
+ len, &returnCode, &sslErrorCode, write_timeout_millis);
switch (ret) {
case THROW_SSLEXCEPTION:
@@ -4404,6 +4435,7 @@
NATIVE_METHOD(NativeCrypto, EVP_PKEY_type, "(I)I"),
NATIVE_METHOD(NativeCrypto, EVP_PKEY_size, "(I)I"),
NATIVE_METHOD(NativeCrypto, EVP_PKEY_free, "(I)V"),
+ NATIVE_METHOD(NativeCrypto, EVP_PKEY_cmp, "(II)I"),
NATIVE_METHOD(NativeCrypto, i2d_PKCS8_PRIV_KEY_INFO, "(I)[B"),
NATIVE_METHOD(NativeCrypto, d2i_PKCS8_PRIV_KEY_INFO, "([B)I"),
NATIVE_METHOD(NativeCrypto, i2d_PUBKEY, "(I)[B"),
@@ -4466,7 +4498,7 @@
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 @@
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 @@
}
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 @@
}
} 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 @@
}
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 @@
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/ConcurrentCloseTest.java b/luni/src/test/java/libcore/java/net/ConcurrentCloseTest.java
index d33c5f3..99a479c2 100644
--- a/luni/src/test/java/libcore/java/net/ConcurrentCloseTest.java
+++ b/luni/src/test/java/libcore/java/net/ConcurrentCloseTest.java
@@ -16,11 +16,13 @@
package libcore.java.net;
+import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
+import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.channels.AsynchronousCloseException;
import java.nio.channels.ClosedChannelException;
@@ -36,25 +38,25 @@
*/
public class ConcurrentCloseTest extends junit.framework.TestCase {
public void test_accept() throws Exception {
- ServerSocket s = new ServerSocket(0);
- new Killer(s).start();
+ ServerSocket ss = new ServerSocket(0);
+ new Killer(ss).start();
try {
System.err.println("accept...");
- s.accept();
- fail("accept returned!");
+ Socket s = ss.accept();
+ fail("accept returned " + s + "!");
} catch (SocketException expected) {
assertEquals("Socket closed", expected.getMessage());
}
}
public void test_connect() throws Exception {
- StuckServer ss = new StuckServer();
+ StuckServer ss = new StuckServer(false);
Socket s = new Socket();
new Killer(s).start();
try {
System.err.println("connect...");
s.connect(ss.getLocalSocketAddress());
- fail("connect returned!");
+ fail("connect returned: " + s + "!");
} catch (SocketException expected) {
assertEquals("Socket closed", expected.getMessage());
} finally {
@@ -63,13 +65,13 @@
}
public void test_connect_timeout() throws Exception {
- StuckServer ss = new StuckServer();
+ StuckServer ss = new StuckServer(false);
Socket s = new Socket();
new Killer(s).start();
try {
System.err.println("connect (with timeout)...");
s.connect(ss.getLocalSocketAddress(), 3600 * 1000);
- fail("connect returned!");
+ fail("connect returned: " + s + "!");
} catch (SocketException expected) {
assertEquals("Socket closed", expected.getMessage());
} finally {
@@ -78,7 +80,7 @@
}
public void test_connect_nonBlocking() throws Exception {
- StuckServer ss = new StuckServer();
+ StuckServer ss = new StuckServer(false);
SocketChannel s = SocketChannel.open();
new Killer(s.socket()).start();
try {
@@ -88,7 +90,7 @@
while (!s.finishConnect()) {
// Spin like a mad thing!
}
- fail("connect returned!");
+ fail("connect returned: " + s + "!");
} catch (SocketException expected) {
assertEquals("Socket closed", expected.getMessage());
} catch (AsynchronousCloseException alsoOkay) {
@@ -102,23 +104,14 @@
}
public void test_read() throws Exception {
- final ServerSocket ss = new ServerSocket(0);
- new Thread(new Runnable() {
- public void run() {
- try {
- ss.accept();
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- }
- }).start();
+ SilentServer ss = new SilentServer();
Socket s = new Socket();
s.connect(ss.getLocalSocketAddress());
new Killer(s).start();
try {
System.err.println("read...");
int i = s.getInputStream().read();
- fail("read returned " + i);
+ fail("read returned: " + i);
} catch (SocketException expected) {
assertEquals("Socket closed", expected.getMessage());
}
@@ -126,16 +119,7 @@
}
public void test_read_multiple() throws Throwable {
- final ServerSocket ss = new ServerSocket(0);
- new Thread(new Runnable() {
- public void run() {
- try {
- ss.accept();
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- }
- }).start();
+ SilentServer ss = new SilentServer();
final Socket s = new Socket();
s.connect(ss.getLocalSocketAddress());
@@ -152,7 +136,7 @@
try {
System.err.println("read...");
int i = s.getInputStream().read();
- fail("read returned " + i);
+ fail("read returned: " + i);
} catch (SocketException expected) {
assertEquals("Socket closed", expected.getMessage());
}
@@ -173,6 +157,8 @@
for (Throwable exception : thrownExceptions) {
throw exception;
}
+
+ ss.close();
}
public void test_recv() throws Exception {
@@ -190,21 +176,7 @@
}
public void test_write() throws Exception {
- final ServerSocket ss = new ServerSocket(0);
- new Thread(new Runnable() {
- public void run() {
- try {
- System.err.println("accepting...");
-
- Socket client = ss.accept();
- System.err.println("accepted...");
- Thread.sleep(30 * 1000);
- System.err.println("server exiting...");
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- }
- }).start();
+ final SilentServer ss = new SilentServer();
Socket s = new Socket();
s.connect(ss.getLocalSocketAddress());
new Killer(s).start();
@@ -224,6 +196,37 @@
ss.close();
}
+ // This server accepts connections, but doesn't read or write anything.
+ // It holds on to the Socket connecting to the client so it won't be GCed.
+ // Call "close" to close both the server socket and its client connection.
+ static class SilentServer {
+ private final ServerSocket ss;
+ private Socket client;
+
+ public SilentServer() throws IOException {
+ ss = new ServerSocket(0);
+ new Thread(new Runnable() {
+ public void run() {
+ try {
+ client = ss.accept();
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ }).start();
+ }
+
+ public SocketAddress getLocalSocketAddress() {
+ return ss.getLocalSocketAddress();
+ }
+
+ public void close() throws IOException {
+ client.close();
+ ss.close();
+ }
+ }
+
+ // This thread calls the "close" method on the supplied T after 2s.
static class Killer<T> extends Thread {
private final T s;
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.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 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 @@
// 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 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 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 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 @@
// 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 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 @@
// 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 @@
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 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 @@
}
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 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 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 @@
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 @@
// 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 @@
}
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 @@
// 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 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 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 @@
// 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 @@
// 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 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 @@
// 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 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 @@
// 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 @@
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 @@
// 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 @@
// 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 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 @@
// 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 @@
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 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 @@
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 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 @@
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 @@
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 @@
// 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 @@
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 @@
}
// 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 @@
// 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 @@
// 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 @@
// 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 @@
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 @@
}
// start by validating the error checks
- int portNumber = Support_PortManager.getNextPort();
+ 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();
+
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 };
-
- 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();
try {
theSocket = new Socket();
@@ -1340,9 +1225,8 @@
// 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 @@
// 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 @@
}
// 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 @@
// 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 @@
}
// 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 @@
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 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 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 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 @@
// 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 @@
+ ":"
+ 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 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 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 @@
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 void test_getTrafficClass() {
try {
- new InetSocketAddress(InetAddress.getLocalHost(),
- Support_PortManager.getNextPort());
Socket theSocket = new Socket();
/*
@@ -1888,13 +1707,9 @@
// 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 @@
// 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 @@
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 @@
*/
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 @@
}
// 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 @@
}
- /**
- *
- */
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/net/URLConnectionTest.java b/luni/src/test/java/libcore/java/net/URLConnectionTest.java
index 762bac4..1f2ebf9 100644
--- a/luni/src/test/java/libcore/java/net/URLConnectionTest.java
+++ b/luni/src/test/java/libcore/java/net/URLConnectionTest.java
@@ -795,6 +795,27 @@
assertContainsNoneMatching(get.getHeaders(), "Proxy\\-Authorization.*");
}
+ // Don't disconnect after building a tunnel with CONNECT
+ // http://code.google.com/p/android/issues/detail?id=37221
+ public void testProxyWithConnectionClose() throws IOException {
+ TestSSLContext testSSLContext = TestSSLContext.create();
+ server.useHttps(testSSLContext.serverContext.getSocketFactory(), true);
+ server.enqueue(new MockResponse()
+ .setSocketPolicy(SocketPolicy.UPGRADE_TO_SSL_AT_END)
+ .clearHeaders());
+ server.enqueue(new MockResponse().setBody("this response comes via a proxy"));
+ server.play();
+
+ URL url = new URL("https://android.com/foo");
+ HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(
+ server.toProxyAddress());
+ connection.setRequestProperty("Connection", "close");
+ connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory());
+ connection.setHostnameVerifier(new RecordingHostnameVerifier());
+
+ assertContent("this response comes via a proxy", connection);
+ }
+
public void testDisconnectedConnection() throws IOException {
server.enqueue(new MockResponse().setBody("ABCDEFGHIJKLMNOPQR"));
server.play();
@@ -989,21 +1010,25 @@
URLConnection connection = server.getUrl("/").openConnection();
assertEquals("ABCABCABC", readAscii(connection.getInputStream(), Integer.MAX_VALUE));
assertNull(connection.getContentEncoding());
+ assertEquals(-1, connection.getContentLength());
RecordedRequest request = server.takeRequest();
assertContains(request.getHeaders(), "Accept-Encoding: gzip");
}
public void testClientConfiguredGzipContentEncoding() throws Exception {
+ byte[] bodyBytes = gzip("ABCDEFGHIJKLMNOPQRSTUVWXYZ".getBytes("UTF-8"));
server.enqueue(new MockResponse()
- .setBody(gzip("ABCDEFGHIJKLMNOPQRSTUVWXYZ".getBytes("UTF-8")))
- .addHeader("Content-Encoding: gzip"));
+ .setBody(bodyBytes)
+ .addHeader("Content-Encoding: gzip")
+ .addHeader("Content-Length: " + bodyBytes.length));
server.play();
URLConnection connection = server.getUrl("/").openConnection();
connection.addRequestProperty("Accept-Encoding", "gzip");
InputStream gunzippedIn = new GZIPInputStream(connection.getInputStream());
assertEquals("ABCDEFGHIJKLMNOPQRSTUVWXYZ", readAscii(gunzippedIn, Integer.MAX_VALUE));
+ assertEquals(bodyBytes.length, connection.getContentLength());
RecordedRequest request = server.takeRequest();
assertContains(request.getHeaders(), "Accept-Encoding: gzip");
@@ -1620,7 +1645,7 @@
* addresses. This is typically one IPv4 address and one IPv6 address.
*/
public void testConnectTimeouts() throws IOException {
- StuckServer ss = new StuckServer();
+ StuckServer ss = new StuckServer(false);
int serverPort = ss.getLocalPort();
URLConnection urlConnection = new URL("http://localhost:" + serverPort).openConnection();
int timeout = 1000;
diff --git a/luni/src/test/java/libcore/java/nio/channels/SelectorTest.java b/luni/src/test/java/libcore/java/nio/channels/SelectorTest.java
index f73b6d5..4fc70c4 100644
--- a/luni/src/test/java/libcore/java/nio/channels/SelectorTest.java
+++ b/luni/src/test/java/libcore/java/nio/channels/SelectorTest.java
@@ -55,11 +55,10 @@
public void testNonBlockingConnect_slow() throws Exception {
// Test the case where we have to wait for the connection.
Selector selector = Selector.open();
- StuckServer ss = new StuckServer();
+ StuckServer ss = new StuckServer(true);
try {
SocketChannel sc = SocketChannel.open();
sc.configureBlocking(false);
- ss.unblockAfterMs(2000);
sc.connect(ss.getLocalSocketAddress());
SelectionKey key = sc.register(selector, SelectionKey.OP_CONNECT);
assertEquals(1, selector.select());
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.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 @@
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 @@
// 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 @@
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 @@
|| 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 @@
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 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 @@
}
}
+ 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 @@
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 @@
// 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 @@
// 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 @@
// 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 @@
}
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
continue;
}
- keyStore.load(null, null);
+ clearKeyStore(keyStore);
- // test case sensitive
assertNull(keyStore.getCertificate(ALIAS_CERTIFICATE));
if (isReadOnly(keyStore)) {
try {
@@ -1077,10 +1204,8 @@
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 @@
}
// 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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 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 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 @@
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 @@
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 @@
// 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 @@
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 @@
}
for (KeyStore keyStore : keyStores()) {
- keyStore.load(null, null);
+ clearKeyStore(keyStore);
// test case sensitive
assertNull(keyStore.getKey(ALIAS_PRIVATE, PASSWORD_KEY));
@@ -1820,9 +2012,16 @@
}
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 @@
} 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 @@
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 @@
}
// 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 @@
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 @@
}
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/security/SignatureTest.java b/luni/src/test/java/libcore/java/security/SignatureTest.java
index 92b5513..63daa88 100644
--- a/luni/src/test/java/libcore/java/security/SignatureTest.java
+++ b/luni/src/test/java/libcore/java/security/SignatureTest.java
@@ -1253,4 +1253,23 @@
sig.update(Vector2Data);
assertTrue("Signature must verify correctly", sig.verify(SHA1withDSA_Vector2Signature));
}
+
+ // NetscapeCertRequest looks up Signature algorithms by OID from
+ // BC but BC version 1.47 had registration bugs and MD5withRSA was
+ // overlooked. http://b/7453821
+ public void testGetInstanceFromOID() throws Exception {
+ assertBouncyCastleSignatureFromOID("1.2.840.113549.1.1.4"); // MD5withRSA
+ assertBouncyCastleSignatureFromOID("1.2.840.113549.1.1.5"); // SHA1withRSA
+ assertBouncyCastleSignatureFromOID("1.3.14.3.2.29"); // SHA1withRSA
+ assertBouncyCastleSignatureFromOID("1.2.840.113549.1.1.11"); // SHA256withRSA
+ assertBouncyCastleSignatureFromOID("1.2.840.113549.1.1.12"); // SHA384withRSA
+ assertBouncyCastleSignatureFromOID("1.2.840.113549.1.1.13"); // SHA512withRSA
+ assertBouncyCastleSignatureFromOID("1.2.840.10040.4.3"); // SHA1withDSA
+ }
+
+ private void assertBouncyCastleSignatureFromOID(String oid) throws Exception {
+ Signature signature = Signature.getInstance(oid, "BC");
+ assertNotNull(oid, signature);
+ assertEquals(oid, signature.getAlgorithm());
+ }
}
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 @@
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/java/util/prefs/OldPreferencesTest.java b/luni/src/test/java/libcore/java/util/prefs/OldPreferencesTest.java
index aa5f088..f8a8154 100644
--- a/luni/src/test/java/libcore/java/util/prefs/OldPreferencesTest.java
+++ b/luni/src/test/java/libcore/java/util/prefs/OldPreferencesTest.java
@@ -29,8 +29,10 @@
public final class OldPreferencesTest extends TestCase {
- final static String longKey;
- final static String longValue;
+ private static final boolean ENCOURAGE_RACES = false;
+
+ private static final String longKey;
+ private static final String longValue;
static {
StringBuilder key = new StringBuilder(Preferences.MAX_KEY_LENGTH);
@@ -316,8 +318,7 @@
String longName = name.toString();
Preferences root = Preferences.userRoot();
- Preferences parent = Preferences
- .userNodeForPackage(Preferences.class);
+ Preferences parent = Preferences.userNodeForPackage(Preferences.class);
Preferences pref = parent.node("mock");
try {
@@ -352,8 +353,7 @@
public void testNodeExists() throws BackingStoreException {
- Preferences parent = Preferences
- .userNodeForPackage(Preferences.class);
+ Preferences parent = Preferences.userNodeForPackage(Preferences.class);
Preferences pref = parent.node("mock");
try {
@@ -393,16 +393,14 @@
}
public void testParent() {
- Preferences parent = Preferences
- .userNodeForPackage(Preferences.class);
+ Preferences parent = Preferences.userNodeForPackage(Preferences.class);
Preferences pref = parent.node("mock");
assertSame(parent, pref.parent());
}
public void testPut() throws BackingStoreException {
- Preferences pref = Preferences
- .userNodeForPackage(Preferences.class);
+ Preferences pref = Preferences.userNodeForPackage(Preferences.class);
pref.put("", "emptyvalue");
assertEquals("emptyvalue", pref.get("", null));
pref.put("testPutkey", "value1");
@@ -468,8 +466,7 @@
}
public void testPutDouble() {
- Preferences pref = Preferences
- .userNodeForPackage(Preferences.class);
+ Preferences pref = Preferences.userNodeForPackage(Preferences.class);
try {
pref.putDouble(null, 3);
fail();
@@ -580,8 +577,7 @@
}
public void testRemove() throws BackingStoreException {
- Preferences pref = Preferences
- .userNodeForPackage(Preferences.class);
+ Preferences pref = Preferences.userNodeForPackage(Preferences.class);
pref.remove("key");
pref.put("key", "value");
@@ -606,8 +602,7 @@
}
public void testRemoveNode() throws BackingStoreException {
- Preferences pref = Preferences
- .userNodeForPackage(Preferences.class);
+ Preferences pref = Preferences.userNodeForPackage(Preferences.class);
Preferences child = pref.node("child");
Preferences child1 = pref.node("child1");
Preferences grandchild = child.node("grandchild");
@@ -636,11 +631,12 @@
nl = new MockNodeChangeListener();
pref.addNodeChangeListener(nl);
child1 = pref.node("mock1");
- nl.waitForEvent();
+ nl.waitForEvent(1);
assertEquals(1, nl.getAdded());
nl.reset();
pref.node("mock1");
- nl.waitForEvent();
+ // There shouldn't be an event, but wait in case one arrives...
+ try { Thread.sleep(1000); } catch (InterruptedException ignored) {}
assertEquals(0, nl.getAdded());
nl.reset();
} finally {
@@ -653,7 +649,7 @@
pref.addNodeChangeListener(nl);
pref.addNodeChangeListener(nl);
child1 = pref.node("mock2");
- nl.waitForEvent();
+ nl.waitForEvent(2);
assertEquals(2, nl.getAdded());
nl.reset();
} finally {
@@ -667,7 +663,7 @@
pref.addNodeChangeListener(nl);
child1 = pref.node("mock3");
child1.removeNode();
- nl.waitForEvent();
+ nl.waitForEvent(2);
assertEquals(1, nl.getRemoved());
nl.reset();
} finally {
@@ -680,7 +676,7 @@
pref.addNodeChangeListener(nl);
child1 = pref.node("mock6");
child1.removeNode();
- nl.waitForEvent();
+ nl.waitForEvent(4);
assertEquals(2, nl.getRemoved());
nl.reset();
} finally {
@@ -695,27 +691,29 @@
child1 = pref.node("mock4");
child1.addNodeChangeListener(nl);
pref.node("mock4/mock5");
- nl.waitForEvent();
+ nl.waitForEvent(1);
assertEquals(1, nl.getAdded());
nl.reset();
child3 = pref.node("mock4/mock5/mock6");
- nl.waitForEvent();
+ // There shouldn't be an event, but wait in case one arrives...
+ try { Thread.sleep(1000); } catch (InterruptedException ignored) {}
assertEquals(0, nl.getAdded());
nl.reset();
child3.removeNode();
- nl.waitForEvent();
+ // There shouldn't be an event, but wait in case one arrives...
+ try { Thread.sleep(1000); } catch (InterruptedException ignored) {}
assertEquals(0, nl.getRemoved());
nl.reset();
pref.node("mock4/mock7");
- nl.waitForEvent();
+ nl.waitForEvent(1);
assertEquals(1, nl.getAdded());
nl.reset();
child1.removeNode();
- nl.waitForEvent();
- assertEquals(2, nl.getRemoved()); // fail 1
+ nl.waitForEvent(2);
+ assertEquals(2, nl.getRemoved());
nl.reset();
} finally {
try {
@@ -749,7 +747,7 @@
try {
pref.clear();
pl.waitForEvent(2);
- assertEquals(2, pl.getChanged()); // fail 1
+ assertEquals(2, pl.getChanged());
} catch(BackingStoreException bse) {
pl.reset();
fail("BackingStoreException is thrown");
@@ -784,7 +782,7 @@
try {
pref.clear();
pl.waitForEvent(3);
- assertEquals(3, pl.getChanged()); // fails
+ assertEquals(3, pl.getChanged());
} catch(BackingStoreException bse) {
fail("BackingStoreException is thrown");
}
@@ -868,25 +866,38 @@
static class MockNodeChangeListener implements NodeChangeListener {
private int added = 0;
private int removed = 0;
+ private int eventCount = 0;
- public synchronized void waitForEvent() {
- try {
- wait(500);
- } catch (InterruptedException ignored) {
+ public void waitForEvent(int count) {
+ synchronized (this) {
+ while (eventCount < count) {
+ try {
+ wait();
+ } catch (InterruptedException ignored) {
+ }
+ }
}
}
- public synchronized void childAdded(NodeChangeEvent e) {
- ++added;
- notifyAll();
+ public void childAdded(NodeChangeEvent e) {
+ if (ENCOURAGE_RACES) try { Thread.sleep(1000); } catch (InterruptedException ignored) { }
+ synchronized (this) {
+ ++eventCount;
+ ++added;
+ notifyAll();
+ }
}
- public synchronized void childRemoved(NodeChangeEvent e) {
- removed++;
- notifyAll();
+ public void childRemoved(NodeChangeEvent e) {
+ if (ENCOURAGE_RACES) try { Thread.sleep(1000); } catch (InterruptedException ignored) { }
+ synchronized (this) {
+ ++eventCount;
+ ++removed;
+ notifyAll();
+ }
}
- public synchronized int getAdded() {
+ public synchronized int getAdded() {
return added;
}
@@ -894,7 +905,8 @@
return removed;
}
- public void reset() {
+ public synchronized void reset() {
+ eventCount = 0;
added = 0;
removed = 0;
}
@@ -902,47 +914,35 @@
private static class MockPreferenceChangeListener implements PreferenceChangeListener {
private int changed = 0;
- private boolean addDispatched = false;
- private boolean result = false;
+ private int eventCount = 0;
public void waitForEvent(int count) {
- for (int i = 0; i < count; i++) {
- try {
- synchronized (this) {
- wait(500);
+ synchronized (this) {
+ while (eventCount < count) {
+ try {
+ wait();
+ } catch (InterruptedException ignored) {
}
- } catch (InterruptedException ignored) {
}
}
}
- public synchronized void preferenceChange(PreferenceChangeEvent pce) {
- changed++;
- addDispatched = true;
- notifyAll();
+ public void preferenceChange(PreferenceChangeEvent pce) {
+ if (ENCOURAGE_RACES) try { Thread.sleep(1000); } catch (InterruptedException ignored) { }
+ synchronized (this) {
+ ++eventCount;
+ ++changed;
+ notifyAll();
+ }
}
- public boolean getResult() throws InterruptedException {
- if (!addDispatched) {
- // TODO: don't know why must add limitation
- wait(100);
- }
- addDispatched = false;
- return result;
- }
-
- public synchronized int getChanged() throws InterruptedException {
- if (!addDispatched) {
- // TODO: don't know why must add limitation
- wait(1000);
- }
- addDispatched = false;
+ public synchronized int getChanged() {
return changed;
}
- public void reset() {
+ public synchronized void reset() {
+ eventCount = 0;
changed = 0;
- result = false;
}
}
diff --git a/luni/src/test/java/libcore/javax/crypto/CipherTest.java b/luni/src/test/java/libcore/javax/crypto/CipherTest.java
index d31825a..68a46f3 100644
--- a/luni/src/test/java/libcore/javax/crypto/CipherTest.java
+++ b/luni/src/test/java/libcore/javax/crypto/CipherTest.java
@@ -17,37 +17,87 @@
package libcore.javax.crypto;
import com.android.org.bouncycastle.asn1.x509.KeyUsage;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
-import java.security.InvalidParameterException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.PrivateKey;
-import java.security.Provider.Service;
import java.security.Provider;
import java.security.PublicKey;
+import java.security.SecureRandom;
import java.security.Security;
import java.security.cert.Certificate;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
-import javax.crypto.KeyGenerator;
import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.ShortBufferException;
+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;
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" }); // TOOD: , "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;
+ }
if (algorithm.equals("PBEWITHMD5ANDRC2")) {
return true;
}
- if (algorithm.equals("PBEWITHSHA1ANDRC2")) {
+ if (algorithm.startsWith("PBEWITHSHA1ANDRC2")) {
return true;
}
if (algorithm.equals("PBEWITHSHAAND40BITRC2-CBC")) {
@@ -59,6 +109,11 @@
if (algorithm.equals("PBEWITHSHAANDTWOFISH-CBC")) {
return true;
}
+ if (!IS_UNLIMITED) {
+ if (algorithm.equals("PBEWITHMD5ANDTRIPLEDES")) {
+ return true;
+ }
+ }
return false;
}
@@ -76,10 +131,13 @@
return Cipher.DECRYPT_MODE;
}
- private static String getBaseAlgoritm(String algorithm) {
+ private static String getBaseAlgorithm(String algorithm) {
if (algorithm.equals("AESWRAP")) {
return "AES";
}
+ if (algorithm.startsWith("AES/")) {
+ return "AES";
+ }
if (algorithm.equals("PBEWITHMD5AND128BITAES-CBC-OPENSSL")) {
return "AES";
}
@@ -114,18 +172,24 @@
return "DES";
}
if (algorithm.equals("DESEDEWRAP")) {
- return "DESede";
+ return "DESEDE";
}
if (algorithm.equals("PBEWITHSHAAND2-KEYTRIPLEDES-CBC")) {
- return "DESede";
+ return "DESEDE";
}
if (algorithm.equals("PBEWITHSHAAND3-KEYTRIPLEDES-CBC")) {
- return "DESede";
+ return "DESEDE";
}
- if (algorithm.equals("RSA/ECB/NoPadding")) {
+ if (algorithm.equals("PBEWITHMD5ANDTRIPLEDES")) {
+ return "DESEDE";
+ }
+ if (algorithm.equals("PBEWITHSHA1ANDDESEDE")) {
+ return "DESEDE";
+ }
+ if (algorithm.equals("RSA/ECB/NOPADDING")) {
return "RSA";
}
- if (algorithm.equals("RSA/ECB/PKCS1Padding")) {
+ if (algorithm.equals("RSA/ECB/PKCS1PADDING")) {
return "RSA";
}
if (algorithm.equals("PBEWITHSHAAND40BITRC4")) {
@@ -138,27 +202,36 @@
}
private static boolean isAsymmetric(String algorithm) {
- return getBaseAlgoritm(algorithm).equals("RSA");
+ return getBaseAlgorithm(algorithm).equals("RSA");
}
private static boolean isWrap(String algorithm) {
return algorithm.endsWith("WRAP");
}
+ private static boolean isPBE(String algorithm) {
+ return algorithm.startsWith("PBE");
+ }
+
private static Map<String, Key> ENCRYPT_KEYS = new HashMap<String, Key>();
private synchronized static Key getEncryptKey(String algorithm) throws Exception {
Key key = ENCRYPT_KEYS.get(algorithm);
if (key != null) {
return key;
}
- algorithm = getBaseAlgoritm(algorithm);
- if (algorithm.equals("RSA")) {
+ if (algorithm.startsWith("RSA")) {
KeyFactory kf = KeyFactory.getInstance("RSA");
RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(RSA_2048_modulus,
RSA_2048_privateExponent);
key = kf.generatePrivate(keySpec);
+ } else if (isPBE(algorithm)) {
+ SecretKeyFactory skf = SecretKeyFactory.getInstance(algorithm);
+ key = skf.generateSecret(new PBEKeySpec("secret".toCharArray()));
} else {
- KeyGenerator kg = KeyGenerator.getInstance(algorithm);
+ KeyGenerator kg = KeyGenerator.getInstance(getBaseAlgorithm(algorithm));
+ if (StandardNames.IS_RI && algorithm.equals("AES")) {
+ kg.init(128);
+ }
key = kg.generateKey();
}
ENCRYPT_KEYS.put(algorithm, key);
@@ -171,8 +244,7 @@
if (key != null) {
return key;
}
- algorithm = getBaseAlgoritm(algorithm);
- if (algorithm.equals("RSA")) {
+ if (algorithm.startsWith("RSA")) {
KeyFactory kf = KeyFactory.getInstance("RSA");
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(RSA_2048_modulus,
RSA_2048_publicExponent);
@@ -187,84 +259,213 @@
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);
- EXPECTED_BLOCK_SIZE.put("AESWRAP", 0);
+ if (StandardNames.IS_RI) {
+ setExpectedBlockSize("AESWRAP", 16);
+ } else {
+ setExpectedBlockSize("AESWRAP", 0);
+ }
- EXPECTED_BLOCK_SIZE.put("ARC4", 0);
- EXPECTED_BLOCK_SIZE.put("PBEWITHSHAAND40BITRC4", 0);
- EXPECTED_BLOCK_SIZE.put("PBEWITHSHAAND128BITRC4", 0);
+ setExpectedBlockSize("ARC4", 0);
+ setExpectedBlockSize("ARCFOUR", 0);
+ setExpectedBlockSize("PBEWITHSHAAND40BITRC4", 0);
+ setExpectedBlockSize("PBEWITHSHAAND128BITRC4", 0);
- EXPECTED_BLOCK_SIZE.put("BLOWFISH", 8);
+ setExpectedBlockSize("BLOWFISH", 8);
- EXPECTED_BLOCK_SIZE.put("DES", 8);
- EXPECTED_BLOCK_SIZE.put("PBEWITHMD5ANDDES", 8);
- EXPECTED_BLOCK_SIZE.put("PBEWITHSHA1ANDDES", 8);
+ setExpectedBlockSize("DES", 8);
+ setExpectedBlockSize("PBEWITHMD5ANDDES", 8);
+ setExpectedBlockSize("PBEWITHSHA1ANDDES", 8);
- EXPECTED_BLOCK_SIZE.put("DESEDE", 8);
- EXPECTED_BLOCK_SIZE.put("PBEWITHSHAAND2-KEYTRIPLEDES-CBC", 8);
- EXPECTED_BLOCK_SIZE.put("PBEWITHSHAAND3-KEYTRIPLEDES-CBC", 8);
+ setExpectedBlockSize("DESEDE", 8);
+ setExpectedBlockSize("PBEWITHSHAAND2-KEYTRIPLEDES-CBC", 8);
+ setExpectedBlockSize("PBEWITHSHAAND3-KEYTRIPLEDES-CBC", 8);
+ setExpectedBlockSize("PBEWITHMD5ANDTRIPLEDES", 8);
+ setExpectedBlockSize("PBEWITHSHA1ANDDESEDE", 8);
- EXPECTED_BLOCK_SIZE.put("DESEDEWRAP", 0);
- EXPECTED_BLOCK_SIZE.put("RSA", 255);
- EXPECTED_BLOCK_SIZE.put("RSA/ECB/NoPadding", 0);
- EXPECTED_BLOCK_SIZE.put("RSA/ECB/PKCS1Padding", 0);
+ if (StandardNames.IS_RI) {
+ setExpectedBlockSize("DESEDEWRAP", 8);
+ } else {
+ setExpectedBlockSize("DESEDEWRAP", 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);
+
+ // 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);
+
+ setExpectedBlockSize("RSA", Cipher.DECRYPT_MODE, 256);
+ setExpectedBlockSize("RSA/ECB/NoPadding", Cipher.DECRYPT_MODE, 256);
+ setExpectedBlockSize("RSA/ECB/PKCS1Padding", Cipher.DECRYPT_MODE, 256);
+ }
}
- private static int getExpectedBlockSize(String algorithm) {
- Integer expected = EXPECTED_BLOCK_SIZE.get(algorithm);
- assertNotNull(algorithm, expected);
+
+ private static String modeKey(String algorithm, int mode) {
+ return algorithm + ":" + mode;
+ }
+
+ 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);
- EXPECTED_OUTPUT_SIZE.put("AESWRAP", -1);
+ 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);
- EXPECTED_OUTPUT_SIZE.put("ARC4", 0);
- EXPECTED_OUTPUT_SIZE.put("PBEWITHSHAAND40BITRC4", 0);
- EXPECTED_OUTPUT_SIZE.put("PBEWITHSHAAND128BITRC4", 0);
+ if (StandardNames.IS_RI) {
+ setExpectedOutputSize("AESWRAP", Cipher.WRAP_MODE, 8);
+ setExpectedOutputSize("AESWRAP", Cipher.UNWRAP_MODE, 0);
+ } else {
+ setExpectedOutputSize("AESWRAP", -1);
+ }
- EXPECTED_OUTPUT_SIZE.put("BLOWFISH", 8);
+ setExpectedOutputSize("ARC4", 0);
+ setExpectedOutputSize("ARCFOUR", 0);
+ setExpectedOutputSize("PBEWITHSHAAND40BITRC4", 0);
+ setExpectedOutputSize("PBEWITHSHAAND128BITRC4", 0);
- EXPECTED_OUTPUT_SIZE.put("DES", 8);
- EXPECTED_OUTPUT_SIZE.put("PBEWITHMD5ANDDES", 8);
- EXPECTED_OUTPUT_SIZE.put("PBEWITHSHA1ANDDES", 8);
+ setExpectedOutputSize("BLOWFISH", Cipher.ENCRYPT_MODE, 8);
+ setExpectedOutputSize("BLOWFISH", 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("DES", Cipher.ENCRYPT_MODE, 8);
+ setExpectedOutputSize("PBEWITHMD5ANDDES", Cipher.ENCRYPT_MODE, 8);
+ setExpectedOutputSize("PBEWITHSHA1ANDDES", Cipher.ENCRYPT_MODE, 8);
- EXPECTED_OUTPUT_SIZE.put("DESEDEWRAP", -1);
+ setExpectedOutputSize("DES", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("PBEWITHMD5ANDDES", Cipher.DECRYPT_MODE, 0);
+ setExpectedOutputSize("PBEWITHSHA1ANDDES", Cipher.DECRYPT_MODE, 0);
- EXPECTED_OUTPUT_SIZE.put("RSA", 256);
- EXPECTED_OUTPUT_SIZE.put("RSA/ECB/NoPadding", 256);
- EXPECTED_OUTPUT_SIZE.put("RSA/ECB/PKCS1Padding", 256);
+ 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) {
+ setExpectedOutputSize("DESEDEWRAP", Cipher.WRAP_MODE, 16);
+ setExpectedOutputSize("DESEDEWRAP", Cipher.UNWRAP_MODE, 0);
+ } else {
+ 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) {
- Integer expected = EXPECTED_OUTPUT_SIZE.get(algorithm);
- assertNotNull(algorithm, expected);
- return expected;
+
+ private static void setExpectedOutputSize(String algorithm, int value) {
+ setExpectedSize(EXPECTED_OUTPUT_SIZE, algorithm, value);
+ }
+
+ 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 };
@@ -356,13 +557,28 @@
};
private static byte[] getExpectedPlainText(String algorithm) {
- if (algorithm.equals("RSA/ECB/NoPadding")) {
+ if (algorithm.equals("RSA/ECB/NOPADDING")) {
return PKCS1_BLOCK_TYPE_00_PADDED_PLAIN_TEXT;
}
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);
+
+ Set<String> seenBaseCipherNames = new HashSet<String>();
+ Set<String> seenCiphersWithModeAndPadding = new HashSet<String>();
+
Provider[] providers = Security.getProviders();
for (Provider provider : providers) {
Set<Provider.Service> services = provider.getServices();
@@ -371,37 +587,91 @@
if (!type.equals("Cipher")) {
continue;
}
+
String algorithm = service.getAlgorithm();
+
+ /*
+ * Any specific modes and paddings aren't tested directly here,
+ * but we need to make sure we see the bare algorithm from some
+ * provider. We will test each mode specifically when we get the
+ * base cipher.
+ */
+ final int firstSlash = algorithm.indexOf('/');
+ if (firstSlash == -1) {
+ seenBaseCipherNames.add(algorithm);
+ } else {
+ final String baseCipherName = algorithm.substring(0, firstSlash);
+ if (!seenBaseCipherNames.contains(baseCipherName)) {
+ seenCiphersWithModeAndPadding.add(baseCipherName);
+ }
+ continue;
+ }
+
try {
- // Cipher.getInstance(String)
- Cipher c1 = Cipher.getInstance(algorithm);
- assertEquals(algorithm, c1.getAlgorithm());
- test_Cipher(c1);
-
- // Cipher.getInstance(String, Provider)
- Cipher c2 = Cipher.getInstance(algorithm, provider);
- assertEquals(algorithm, c2.getAlgorithm());
- assertEquals(provider, c2.getProvider());
- test_Cipher(c2);
-
- // KeyGenerator.getInstance(String, String)
- Cipher c3 = Cipher.getInstance(algorithm, provider.getName());
- assertEquals(algorithm, c3.getAlgorithm());
- assertEquals(provider, c3.getProvider());
- test_Cipher(c3);
+ test_Cipher_Algorithm(provider, algorithm);
} catch (Throwable e) {
- throw new Exception("Problem testing Cipher." + algorithm, e);
+ out.append("Error encountered checking " + algorithm
+ + " with provider " + provider.getName() + "\n");
+ e.printStackTrace(out);
+ }
+
+ Set<String> modes = StandardNames.getModesForCipher(algorithm);
+ if (modes != null) {
+ for (String mode : modes) {
+ Set<String> paddings = StandardNames.getPaddingsForCipher(algorithm);
+ if (paddings != null) {
+ for (String padding : paddings) {
+ final String algorithmName = algorithm + "/" + mode + "/" + padding;
+ try {
+ test_Cipher_Algorithm(provider, algorithmName);
+ } catch (Throwable e) {
+ out.append("Error encountered checking " + algorithmName
+ + " with provider " + provider.getName() + "\n");
+ e.printStackTrace(out);
+ }
+ }
+ }
+ }
}
}
}
+
+ seenCiphersWithModeAndPadding.removeAll(seenBaseCipherNames);
+ assertEquals("Ciphers seen with mode and padding but not base cipher",
+ Collections.EMPTY_SET, seenCiphersWithModeAndPadding);
+
+ out.flush();
+ if (errBuffer.size() > 0) {
+ throw new Exception("Errors encountered:\n\n" + errBuffer.toString() + "\n\n");
+ }
+ }
+
+ private void test_Cipher_Algorithm(Provider provider, String algorithm) throws Exception {
+ // Cipher.getInstance(String)
+ Cipher c1 = Cipher.getInstance(algorithm);
+ assertEquals(algorithm, c1.getAlgorithm());
+ test_Cipher(c1);
+
+ // Cipher.getInstance(String, Provider)
+ Cipher c2 = Cipher.getInstance(algorithm, provider);
+ assertEquals(algorithm, c2.getAlgorithm());
+ assertEquals(provider, c2.getProvider());
+ test_Cipher(c2);
+
+ // KeyGenerator.getInstance(String, String)
+ Cipher c3 = Cipher.getInstance(algorithm, provider.getName());
+ assertEquals(algorithm, c3.getAlgorithm());
+ assertEquals(provider, c3.getProvider());
+ test_Cipher(c3);
}
private void test_Cipher(Cipher c) throws Exception {
- // TODO: test all supported modes and padding for a given algorithm
- String algorithm = c.getAlgorithm();
+ String algorithm = c.getAlgorithm().toUpperCase(Locale.US);
if (isUnsupported(algorithm)) {
return;
}
+ String providerName = c.getProvider().getName();
+ String cipherID = algorithm + ":" + providerName;
try {
c.getOutputSize(0);
@@ -410,21 +680,28 @@
// TODO: test keys from different factories (e.g. OpenSSLRSAPrivateKey vs JCERSAPrivateKey)
Key encryptKey = getEncryptKey(algorithm);
- c.init(getEncryptMode(algorithm), encryptKey);
- assertEquals(getExpectedBlockSize(algorithm), c.getBlockSize());
+ final AlgorithmParameterSpec spec = getAlgorithmParameterSpec(algorithm);
- assertEquals(getExpectedOutputSize(algorithm), c.getOutputSize(0));
+ int encryptMode = getEncryptMode(algorithm);
+ c.init(encryptMode, encryptKey, spec);
+ assertEquals(cipherID, getExpectedBlockSize(algorithm, encryptMode, providerName), c.getBlockSize());
+ assertEquals(cipherID, getExpectedOutputSize(algorithm, encryptMode, providerName), c.getOutputSize(0));
+ int decryptMode = getDecryptMode(algorithm);
+ c.init(decryptMode, encryptKey, spec);
+ assertEquals(cipherID, getExpectedBlockSize(algorithm, decryptMode, providerName), c.getBlockSize());
+ assertEquals(cipherID, getExpectedOutputSize(algorithm, decryptMode, providerName), c.getOutputSize(0));
// TODO: test Cipher.getIV()
// TODO: test Cipher.getParameters()
- assertNull(c.getExemptionMechanism());
+ assertNull(cipherID, c.getExemptionMechanism());
+ c.init(getEncryptMode(algorithm), encryptKey, spec);
if (isWrap(algorithm)) {
byte[] cipherText = c.wrap(encryptKey);
- c.init(getDecryptMode(algorithm), getDecryptKey(algorithm));
+ c.init(getDecryptMode(algorithm), getDecryptKey(algorithm), spec);
int keyType = (isAsymmetric(algorithm)) ? Cipher.PRIVATE_KEY : Cipher.SECRET_KEY;
Key decryptedKey = c.unwrap(cipherText, encryptKey.getAlgorithm(), keyType);
assertEquals("encryptKey.getAlgorithm()=" + encryptKey.getAlgorithm()
@@ -434,33 +711,40 @@
encryptKey, decryptedKey);
} else {
byte[] cipherText = c.doFinal(ORIGINAL_PLAIN_TEXT);
- c.init(getDecryptMode(algorithm), getDecryptKey(algorithm));
+ c.init(getDecryptMode(algorithm), 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"));
- try {
- testInputPKCS1Padding(PKCS1_BLOCK_TYPE_02_PADDED_PLAIN_TEXT, getEncryptKey("RSA"), getDecryptKey("RSA"));
- fail();
- } catch (BadPaddingException expected) {
+ for (String provider : RSA_PROVIDERS) {
+ testInputPKCS1Padding(provider);
}
- try {
- testInputPKCS1Padding(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"));
}
- private void testInputPKCS1Padding(byte[] prePaddedPlainText, Key encryptKey, Key decryptKey) throws Exception {
- Cipher encryptCipher = Cipher.getInstance("RSA/ECB/NoPadding");
+ private void testInputPKCS1Padding(String provider) throws Exception {
+ testInputPKCS1Padding(provider, PKCS1_BLOCK_TYPE_01_PADDED_PLAIN_TEXT, getEncryptKey("RSA"), getDecryptKey("RSA"));
+ try {
+ testInputPKCS1Padding(provider, PKCS1_BLOCK_TYPE_02_PADDED_PLAIN_TEXT, getEncryptKey("RSA"), getDecryptKey("RSA"));
+ fail();
+ } catch (BadPaddingException expected) {
+ }
+ try {
+ testInputPKCS1Padding(provider, PKCS1_BLOCK_TYPE_01_PADDED_PLAIN_TEXT, getDecryptKey("RSA"), getEncryptKey("RSA"));
+ fail();
+ } catch (BadPaddingException expected) {
+ }
+ testInputPKCS1Padding(provider, PKCS1_BLOCK_TYPE_02_PADDED_PLAIN_TEXT, getDecryptKey("RSA"), getEncryptKey("RSA"));
+ }
+
+ 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),
@@ -468,36 +752,51 @@
}
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(byte expectedBlockType, Key encryptKey, Key decryptKey) throws Exception {
- Cipher encryptCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
+ 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(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(expectedBlockType, ORIGINAL_PLAIN_TEXT, plainText);
+ assertPadding(provider, expectedBlockType, ORIGINAL_PLAIN_TEXT, plainText);
}
- private void assertPadding(byte expectedBlockType, byte[] expectedData, byte[] actualDataWithPadding) {
- assertNotNull(actualDataWithPadding);
- assertEquals(getExpectedOutputSize("RSA"), 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 {
@@ -935,13 +1234,19 @@
};
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
@@ -960,13 +1265,19 @@
}
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
@@ -988,13 +1299,20 @@
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
@@ -1020,12 +1338,18 @@
}
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
@@ -1051,12 +1375,18 @@
}
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
@@ -1065,22 +1395,26 @@
*/
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
@@ -1092,22 +1426,33 @@
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
@@ -1117,22 +1462,29 @@
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
@@ -1145,23 +1497,29 @@
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
@@ -1180,13 +1538,19 @@
}
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
@@ -1195,24 +1559,48 @@
*/
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
@@ -1226,18 +1614,28 @@
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
@@ -1254,17 +1652,26 @@
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
@@ -1283,26 +1690,46 @@
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");
@@ -1311,32 +1738,39 @@
}
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);
@@ -1345,12 +1779,390 @@
}
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());
}
+
+ /*
+ * Test vector generation:
+ * openssl rand -hex 16
+ * echo '3d4f8970b1f27537f40a39298a41555f' | sed 's/\(..\)/(byte) 0x\1, /g'
+ */
+ private static final byte[] AES_128_KEY = new byte[] {
+ (byte) 0x3d, (byte) 0x4f, (byte) 0x89, (byte) 0x70, (byte) 0xb1, (byte) 0xf2,
+ (byte) 0x75, (byte) 0x37, (byte) 0xf4, (byte) 0x0a, (byte) 0x39, (byte) 0x29,
+ (byte) 0x8a, (byte) 0x41, (byte) 0x55, (byte) 0x5f,
+ };
+
+ /*
+ * Test key generation:
+ * openssl rand -hex 24
+ * echo '5a7a3d7e40b64ed996f7afa15f97fd595e27db6af428e342' | sed 's/\(..\)/(byte) 0x\1, /g'
+ */
+ private static final byte[] AES_192_KEY = new byte[] {
+ (byte) 0x5a, (byte) 0x7a, (byte) 0x3d, (byte) 0x7e, (byte) 0x40, (byte) 0xb6,
+ (byte) 0x4e, (byte) 0xd9, (byte) 0x96, (byte) 0xf7, (byte) 0xaf, (byte) 0xa1,
+ (byte) 0x5f, (byte) 0x97, (byte) 0xfd, (byte) 0x59, (byte) 0x5e, (byte) 0x27,
+ (byte) 0xdb, (byte) 0x6a, (byte) 0xf4, (byte) 0x28, (byte) 0xe3, (byte) 0x42,
+ };
+
+ /*
+ * Test key generation:
+ * openssl rand -hex 32
+ * echo 'ec53c6d51d2c4973585fb0b8e51cd2e39915ff07a1837872715d6121bf861935' | sed 's/\(..\)/(byte) 0x\1, /g'
+ */
+ private static final byte[] AES_256_KEY = new byte[] {
+ (byte) 0xec, (byte) 0x53, (byte) 0xc6, (byte) 0xd5, (byte) 0x1d, (byte) 0x2c,
+ (byte) 0x49, (byte) 0x73, (byte) 0x58, (byte) 0x5f, (byte) 0xb0, (byte) 0xb8,
+ (byte) 0xe5, (byte) 0x1c, (byte) 0xd2, (byte) 0xe3, (byte) 0x99, (byte) 0x15,
+ (byte) 0xff, (byte) 0x07, (byte) 0xa1, (byte) 0x83, (byte) 0x78, (byte) 0x72,
+ (byte) 0x71, (byte) 0x5d, (byte) 0x61, (byte) 0x21, (byte) 0xbf, (byte) 0x86,
+ (byte) 0x19, (byte) 0x35,
+ };
+
+ private static final byte[][] AES_KEYS = new byte[][] {
+ AES_128_KEY, AES_192_KEY, AES_256_KEY,
+ };
+
+ private static final String[] AES_MODES = new String[] {
+ "AES/ECB",
+ "AES/CBC",
+ "AES/CFB",
+ "AES/CTR",
+ "AES/OFB",
+ };
+
+ /*
+ * Test vector creation:
+ * echo -n 'Hello, world!' | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext = new byte[] {
+ (byte) 0x48, (byte) 0x65, (byte) 0x6C, (byte) 0x6C, (byte) 0x6F, (byte) 0x2C,
+ (byte) 0x20, (byte) 0x77, (byte) 0x6F, (byte) 0x72, (byte) 0x6C, (byte) 0x64,
+ (byte) 0x21,
+ };
+
+ /*
+ * Test vector creation:
+ * openssl enc -aes-128-ecb -K 3d4f8970b1f27537f40a39298a41555f -in blah|openssl enc -aes-128-ecb -K 3d4f8970b1f27537f40a39298a41555f -nopad -d|recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext_Padded = new byte[] {
+ (byte) 0x48, (byte) 0x65, (byte) 0x6C, (byte) 0x6C, (byte) 0x6F, (byte) 0x2C,
+ (byte) 0x20, (byte) 0x77, (byte) 0x6F, (byte) 0x72, (byte) 0x6C, (byte) 0x64,
+ (byte) 0x21, (byte) 0x03, (byte) 0x03, (byte) 0x03
+ };
+
+ /*
+ * Test vector generation:
+ * openssl enc -aes-128-ecb -K 3d4f8970b1f27537f40a39298a41555f -in blah|recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] AES_128_ECB_PKCS5Padding_TestVector_1_Encrypted = new byte[] {
+ (byte) 0x65, (byte) 0x3E, (byte) 0x86, (byte) 0xFB, (byte) 0x05, (byte) 0x5A,
+ (byte) 0x52, (byte) 0xEA, (byte) 0xDD, (byte) 0x08, (byte) 0xE7, (byte) 0x48,
+ (byte) 0x33, (byte) 0x01, (byte) 0xFC, (byte) 0x5A,
+ };
+
+ /*
+ * Test key generation:
+ * openssl rand -hex 16
+ * echo 'ceaa31952dfd3d0f5af4b2042ba06094' | sed 's/\(..\)/(byte) 0x\1, /g'
+ */
+ private static final byte[] AES_256_CBC_PKCS5Padding_TestVector_1_IV = new byte[] {
+ (byte) 0xce, (byte) 0xaa, (byte) 0x31, (byte) 0x95, (byte) 0x2d, (byte) 0xfd,
+ (byte) 0x3d, (byte) 0x0f, (byte) 0x5a, (byte) 0xf4, (byte) 0xb2, (byte) 0x04,
+ (byte) 0x2b, (byte) 0xa0, (byte) 0x60, (byte) 0x94,
+ };
+
+ /*
+ * Test vector generation:
+ * echo -n 'I only regret that I have but one test to write.' | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] AES_256_CBC_PKCS5Padding_TestVector_1_Plaintext = new byte[] {
+ (byte) 0x49, (byte) 0x20, (byte) 0x6F, (byte) 0x6E, (byte) 0x6C, (byte) 0x79,
+ (byte) 0x20, (byte) 0x72, (byte) 0x65, (byte) 0x67, (byte) 0x72, (byte) 0x65,
+ (byte) 0x74, (byte) 0x20, (byte) 0x74, (byte) 0x68, (byte) 0x61, (byte) 0x74,
+ (byte) 0x20, (byte) 0x49, (byte) 0x20, (byte) 0x68, (byte) 0x61, (byte) 0x76,
+ (byte) 0x65, (byte) 0x20, (byte) 0x62, (byte) 0x75, (byte) 0x74, (byte) 0x20,
+ (byte) 0x6F, (byte) 0x6E, (byte) 0x65, (byte) 0x20, (byte) 0x74, (byte) 0x65,
+ (byte) 0x73, (byte) 0x74, (byte) 0x20, (byte) 0x74, (byte) 0x6F, (byte) 0x20,
+ (byte) 0x77, (byte) 0x72, (byte) 0x69, (byte) 0x74, (byte) 0x65, (byte) 0x2E
+ };
+
+ /*
+ * Test vector generation:
+ * echo -n 'I only regret that I have but one test to write.' | openssl enc -aes-256-cbc -K ec53c6d51d2c4973585fb0b8e51cd2e39915ff07a1837872715d6121bf861935 -iv ceaa31952dfd3d0f5af4b2042ba06094 | openssl enc -aes-256-cbc -K ec53c6d51d2c4973585fb0b8e51cd2e39915ff07a1837872715d6121bf861935 -iv ceaa31952dfd3d0f5af4b2042ba06094 -d -nopad | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] AES_256_CBC_PKCS5Padding_TestVector_1_Plaintext_Padded = new byte[] {
+ (byte) 0x49, (byte) 0x20, (byte) 0x6F, (byte) 0x6E, (byte) 0x6C, (byte) 0x79,
+ (byte) 0x20, (byte) 0x72, (byte) 0x65, (byte) 0x67, (byte) 0x72, (byte) 0x65,
+ (byte) 0x74, (byte) 0x20, (byte) 0x74, (byte) 0x68, (byte) 0x61, (byte) 0x74,
+ (byte) 0x20, (byte) 0x49, (byte) 0x20, (byte) 0x68, (byte) 0x61, (byte) 0x76,
+ (byte) 0x65, (byte) 0x20, (byte) 0x62, (byte) 0x75, (byte) 0x74, (byte) 0x20,
+ (byte) 0x6F, (byte) 0x6E, (byte) 0x65, (byte) 0x20, (byte) 0x74, (byte) 0x65,
+ (byte) 0x73, (byte) 0x74, (byte) 0x20, (byte) 0x74, (byte) 0x6F, (byte) 0x20,
+ (byte) 0x77, (byte) 0x72, (byte) 0x69, (byte) 0x74, (byte) 0x65, (byte) 0x2E,
+ (byte) 0x10, (byte) 0x10, (byte) 0x10, (byte) 0x10, (byte) 0x10, (byte) 0x10,
+ (byte) 0x10, (byte) 0x10, (byte) 0x10, (byte) 0x10, (byte) 0x10, (byte) 0x10,
+ (byte) 0x10, (byte) 0x10, (byte) 0x10, (byte) 0x10
+ };
+
+ /*
+ * Test vector generation:
+ * echo -n 'I only regret that I have but one test to write.' | openssl enc -aes-256-cbc -K ec53c6d51d2c4973585fb0b8e51cd2e39915ff07a1837872715d6121bf861935 -iv ceaa31952dfd3d0f5af4b2042ba06094 | recode ../x1 | sed 's/0x/(byte) 0x/g'
+ */
+ private static final byte[] AES_256_CBC_PKCS5Padding_TestVector_1_Ciphertext = new byte[] {
+ (byte) 0x90, (byte) 0x65, (byte) 0xDD, (byte) 0xAF, (byte) 0x7A, (byte) 0xCE,
+ (byte) 0xAE, (byte) 0xBF, (byte) 0xE8, (byte) 0xF6, (byte) 0x9E, (byte) 0xDB,
+ (byte) 0xEA, (byte) 0x65, (byte) 0x28, (byte) 0xC4, (byte) 0x9A, (byte) 0x28,
+ (byte) 0xEA, (byte) 0xA3, (byte) 0x95, (byte) 0x2E, (byte) 0xFF, (byte) 0xF1,
+ (byte) 0xA0, (byte) 0xCA, (byte) 0xC2, (byte) 0xA4, (byte) 0x65, (byte) 0xCD,
+ (byte) 0xBF, (byte) 0xCE, (byte) 0x9E, (byte) 0xF1, (byte) 0x57, (byte) 0xF6,
+ (byte) 0x32, (byte) 0x2E, (byte) 0x8F, (byte) 0x93, (byte) 0x2E, (byte) 0xAE,
+ (byte) 0x41, (byte) 0x33, (byte) 0x54, (byte) 0xD0, (byte) 0xEF, (byte) 0x8C,
+ (byte) 0x52, (byte) 0x14, (byte) 0xAC, (byte) 0x2D, (byte) 0xD5, (byte) 0xA4,
+ (byte) 0xF9, (byte) 0x20, (byte) 0x77, (byte) 0x25, (byte) 0x91, (byte) 0x3F,
+ (byte) 0xD1, (byte) 0xB9, (byte) 0x00, (byte) 0x3E
+ };
+
+ private static class CipherTestParam {
+ public final String mode;
+
+ public final byte[] key;
+
+ public final byte[] iv;
+
+ public final byte[] plaintext;
+
+ public final byte[] ciphertext;
+
+ public final byte[] plaintextPadded;
+
+ public CipherTestParam(String mode, byte[] key, byte[] iv, byte[] plaintext,
+ byte[] plaintextPadded, byte[] ciphertext) {
+ this.mode = mode;
+ this.key = key;
+ this.iv = iv;
+ this.plaintext = plaintext;
+ this.plaintextPadded = plaintextPadded;
+ this.ciphertext = ciphertext;
+ }
+ }
+
+ private static List<CipherTestParam> CIPHER_TEST_PARAMS = new ArrayList<CipherTestParam>();
+ static {
+ CIPHER_TEST_PARAMS.add(new CipherTestParam("AES/ECB", AES_128_KEY,
+ null,
+ AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext,
+ AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext_Padded,
+ AES_128_ECB_PKCS5Padding_TestVector_1_Encrypted));
+ 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, provider);
+ } catch (Exception e) {
+ out.append("Error encountered checking " + p.mode + ", keySize="
+ + (p.key.length * 8) + "\n");
+ e.printStackTrace(out);
+ }
+ }
+ out.flush();
+ if (errBuffer.size() > 0) {
+ throw new Exception("Errors encountered:\n\n" + errBuffer.toString() + "\n\n");
+ }
+ }
+
+ private void checkCipher(CipherTestParam p, String provider) throws Exception {
+ SecretKey key = new SecretKeySpec(p.key, "AES");
+ Cipher c = Cipher.getInstance(p.mode + "/PKCS5Padding", provider);
+ AlgorithmParameterSpec spec = null;
+ if (p.iv != null) {
+ spec = new IvParameterSpec(p.iv);
+ }
+ c.init(Cipher.ENCRYPT_MODE, key, spec);
+
+ final byte[] actualCiphertext = c.doFinal(p.plaintext);
+ assertTrue(Arrays.equals(p.ciphertext, actualCiphertext));
+
+ c.init(Cipher.DECRYPT_MODE, key, spec);
+
+ final byte[] actualPlaintext = c.doFinal(p.ciphertext);
+ assertTrue(Arrays.equals(p.plaintext, actualPlaintext));
+
+ Cipher cNoPad = Cipher.getInstance(p.mode + "/NoPadding", provider);
+ cNoPad.init(Cipher.DECRYPT_MODE, key, spec);
+
+ final byte[] actualPlaintextPadded = cNoPad.doFinal(p.ciphertext);
+ assertTrue(Arrays.equals(p.plaintextPadded, actualPlaintextPadded));
+ }
+
+ 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, provider);
+ } catch (Exception e) {
+ out.append("Error encountered checking " + p.mode + ", keySize="
+ + (p.key.length * 8) + "\n");
+ e.printStackTrace(out);
+ }
+ }
+ out.flush();
+ if (errBuffer.size() > 0) {
+ throw new Exception("Errors encountered:\n\n" + errBuffer.toString() + "\n\n");
+ }
+ }
+
+ 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", provider);
+ if (c.getBlockSize() == 0) {
+ return;
+ }
+
+ c.init(Cipher.ENCRYPT_MODE, key);
+ try {
+ c.doFinal(new byte[] { 0x01, 0x02, 0x03 });
+ fail("Should throw IllegalBlockSizeException on wrong-sized block");
+ } catch (IllegalBlockSizeException expected) {
+ }
+ }
+
+ 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", provider);
+ c.init(Cipher.ENCRYPT_MODE, key);
+
+ final byte[] fragmentOutput = c.update(AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext);
+ if (fragmentOutput != null) {
+ assertEquals(0, fragmentOutput.length);
+ }
+
+ // Provide null buffer.
+ {
+ try {
+ c.doFinal(null, 0);
+ fail("Should throw NullPointerException on null output buffer");
+ } catch (NullPointerException expected) {
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ // Provide short buffer.
+ {
+ final byte[] output = new byte[c.getBlockSize() - 1];
+ try {
+ c.doFinal(output, 0);
+ fail("Should throw ShortBufferException on short output buffer");
+ } catch (ShortBufferException expected) {
+ }
+ }
+
+ // Start 1 byte into output buffer.
+ {
+ final byte[] output = new byte[c.getBlockSize()];
+ try {
+ c.doFinal(output, 1);
+ fail("Should throw ShortBufferException on short output buffer");
+ } catch (ShortBufferException expected) {
+ }
+ }
+
+ // Should keep data for real output buffer
+ {
+ final byte[] output = new byte[c.getBlockSize()];
+ assertEquals(AES_128_ECB_PKCS5Padding_TestVector_1_Encrypted.length, c.doFinal(output, 0));
+ assertTrue(Arrays.equals(AES_128_ECB_PKCS5Padding_TestVector_1_Encrypted, output));
+ }
+ }
+
+ 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", provider);
+ c.init(Cipher.ENCRYPT_MODE, key);
+
+ for (int i = 0; i < AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext_Padded.length - 1; i++) {
+ final byte[] outputFragment = c.update(AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext_Padded, i, 1);
+ if (outputFragment != null) {
+ assertEquals(0, outputFragment.length);
+ }
+ }
+
+ final byte[] output = c.doFinal(AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext_Padded,
+ AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext_Padded.length - 1, 1);
+ assertNotNull(output);
+ assertEquals(AES_128_ECB_PKCS5Padding_TestVector_1_Plaintext_Padded.length, output.length);
+
+ assertTrue(Arrays.equals(AES_128_ECB_PKCS5Padding_TestVector_1_Encrypted, output));
+ }
+
+ private static final byte[] AES_IV_ZEROES = new byte[] {
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ };
+
+ 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", provider);
+
+ AlgorithmParameterSpec spec = new IvParameterSpec(AES_IV_ZEROES);
+ try {
+ c.init(Cipher.ENCRYPT_MODE, key, spec);
+ fail("Should not accept an IV in ECB mode");
+ } catch (InvalidAlgorithmParameterException expected) {
+ }
+ }
}
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 @@
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 @@
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 @@
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/archive/tests/java/util/zip/ZipFileTest.java b/luni/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipFileTest.java
index 17d251b..a423f22 100644
--- a/luni/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipFileTest.java
+++ b/luni/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipFileTest.java
@@ -32,6 +32,7 @@
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
+import libcore.java.lang.ref.FinalizationTester;
public class ZipFileTest extends junit.framework.TestCase {
@@ -150,11 +151,8 @@
* entry1); entry1 = null; zip = null;
*/
- assertNotNull("Did not find entry",
- test_finalize1(test_finalize2(file)));
- System.gc();
- System.gc();
- System.runFinalization();
+ assertNotNull("Did not find entry", test_finalize1(test_finalize2(file)));
+ FinalizationTester.induceFinalization();
file.delete();
assertTrue("Zip should not exist", !file.exists());
}
diff --git a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/CipherTest.java b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/CipherTest.java
index 7442210..c07b180 100644
--- a/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/CipherTest.java
+++ b/luni/src/test/java/org/apache/harmony/crypto/tests/javax/crypto/CipherTest.java
@@ -47,6 +47,7 @@
import javax.crypto.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 @@
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.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 @@
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 @@
// 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 @@
// 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 @@
}// 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 @@
// 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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
// 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 @@
assertTrue("Failed to add provider", addResult != -1);
Security.removeProvider(entrust.getName());
- Provider provTest[] = Security.getProviders();
- for (int i = 0; i < provTest.length; i++) {
- assertTrue(
- "the provider entrust is found after it was removed",
- provTest[i].getName() != entrust.getName());
+ for (Provider provider : Security.getProviders()) {
+ assertTrue("the provider entrust is found after it was removed",
+ provider.getName() != entrust.getName());
}
} finally {
// Tidy up - the following calls do nothing if the providers were
diff --git a/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/CertPinManagerTest.java b/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/CertPinManagerTest.java
new file mode 100644
index 0000000..8359c99
--- /dev/null
+++ b/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/CertPinManagerTest.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.xnet.provider.jsse;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.security.cert.X509Certificate;
+import java.security.KeyStore;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
+import junit.framework.TestCase;
+import libcore.java.security.TestKeyStore;
+
+public class CertPinManagerTest extends TestCase {
+
+ private X509Certificate[] chain;
+ private List<X509Certificate> shortChain;
+ private List<X509Certificate> longChain;
+ private String shortPin;
+ private String longPin;
+ private List<File> tmpFiles = new ArrayList<File>();
+
+ private String writeTmpPinFile(String text) throws Exception {
+ File tmp = File.createTempFile("pins", null);
+ FileWriter fstream = new FileWriter(tmp);
+ fstream.write(text);
+ fstream.close();
+ tmpFiles.add(tmp);
+ return tmp.getPath();
+ }
+
+ private static String getFingerprint(X509Certificate cert) throws NoSuchAlgorithmException {
+ MessageDigest dgst = MessageDigest.getInstance("SHA512");
+ byte[] encoded = cert.getPublicKey().getEncoded();
+ byte[] fingerprint = dgst.digest(encoded);
+ return IntegralToString.bytesToHexString(fingerprint, false);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ // build some valid chains
+ KeyStore.PrivateKeyEntry pke = TestKeyStore.getServer().getPrivateKey("RSA", "RSA");
+ chain = (X509Certificate[]) pke.getCertificateChain();
+ X509Certificate root = chain[2];
+ X509Certificate server = chain[0];
+
+ // build the short and long chains
+ shortChain = new ArrayList<X509Certificate>();
+ shortChain.add(root);
+ longChain = new ArrayList<X509Certificate>();
+ longChain.add(server);
+
+ // we'll use the root as the pin for the short entry and the server as the pin for the long
+ shortPin = getFingerprint(root);
+ longPin = getFingerprint(server);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ try {
+ for (File f : tmpFiles) {
+ f.delete();
+ }
+ tmpFiles.clear();
+ } finally {
+ super.tearDown();
+ }
+ }
+
+ public void testPinFileMaximumLookup() throws Exception {
+
+ // write a pinfile with two entries, one longer than the other
+ String shortEntry = "*.google.com=true|" + shortPin;
+ String longEntry = "*.clients.google.com=true|" + longPin;
+
+ // create the pinFile
+ String path = writeTmpPinFile(shortEntry + "\n" + longEntry);
+ CertPinManager pf = new CertPinManager(path, new TrustedCertificateStore());
+
+ // verify that the shorter chain doesn't work for a name matching the longer
+ assertTrue("short chain long uri failed",
+ pf.chainIsNotPinned("android.clients.google.com", shortChain));
+ // verify that the longer chain doesn't work for a name matching the shorter
+ assertTrue("long chain short uri failed",
+ pf.chainIsNotPinned("android.google.com", longChain));
+ // verify that the shorter chain works for the shorter domain
+ assertTrue("short chain short uri failed",
+ !pf.chainIsNotPinned("android.google.com", shortChain));
+ // and the same for the longer
+ assertTrue("long chain long uri failed",
+ !pf.chainIsNotPinned("android.clients.google.com", longChain));
+ }
+
+ public void testPinEntryMalformedEntry() throws Exception {
+ // set up the pinEntry with a bogus entry
+ String entry = "*.google.com=";
+ try {
+ new PinListEntry(entry, new TrustedCertificateStore());
+ fail("Accepted an empty pin list entry.");
+ } catch (PinEntryException expected) {
+ }
+ }
+
+ public void testPinEntryNull() throws Exception {
+ // set up the pinEntry with a bogus entry
+ String entry = null;
+ try {
+ new PinListEntry(entry, new TrustedCertificateStore());
+ fail("Accepted a basically wholly bogus entry.");
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ public void testPinEntryEmpty() throws Exception {
+ // set up the pinEntry with a bogus entry
+ try {
+ new PinListEntry("", new TrustedCertificateStore());
+ fail("Accepted an empty entry.");
+ } catch (PinEntryException expected) {
+ }
+ }
+
+ public void testPinEntryPinFailure() throws Exception {
+ // write a pinfile with two entries, one longer than the other
+ String shortEntry = "*.google.com=true|" + shortPin;
+
+ // set up the pinEntry with a pinlist that doesn't match what we'll give it
+ PinListEntry e = new PinListEntry(shortEntry, new TrustedCertificateStore());
+ assertTrue("Not enforcing!", e.getEnforcing());
+ // verify that it doesn't accept
+ boolean retval = e.chainIsNotPinned(longChain);
+ assertTrue("Accepted an incorrect pinning, this is very bad", retval);
+ }
+
+ public void testPinEntryPinSuccess() throws Exception {
+ // write a pinfile with two entries, one longer than the other
+ String shortEntry = "*.google.com=true|" + shortPin;
+
+ // set up the pinEntry with a pinlist that matches what we'll give it
+ PinListEntry e = new PinListEntry(shortEntry, new TrustedCertificateStore());
+ assertTrue("Not enforcing!", e.getEnforcing());
+ // verify that it accepts
+ boolean retval = e.chainIsNotPinned(shortChain);
+ assertTrue("Failed on a correct pinning, this is very bad", !retval);
+ }
+
+ public void testPinEntryNonEnforcing() throws Exception {
+ // write a pinfile with two entries, one longer than the other
+ String shortEntry = "*.google.com=false|" + shortPin;
+
+ // set up the pinEntry with a pinlist that matches what we'll give it
+ PinListEntry e = new PinListEntry(shortEntry, new TrustedCertificateStore());
+ assertFalse("Enforcing!", e.getEnforcing());
+ // verify that it accepts
+ boolean retval = e.chainIsNotPinned(shortChain);
+ assertTrue("Failed on an unenforced pinning, this is bad-ish", !retval);
+ }
+}
diff --git a/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/NativeCryptoTest.java b/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/NativeCryptoTest.java
index 15b175c..303c234 100644
--- a/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/NativeCryptoTest.java
+++ b/luni/src/test/java/org/apache/harmony/xnet/provider/jsse/NativeCryptoTest.java
@@ -21,10 +21,14 @@
import java.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;
@@ -38,6 +42,7 @@
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;
@@ -47,7 +52,8 @@
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;
@@ -131,6 +137,87 @@
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);
@@ -490,11 +577,14 @@
}
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;
}
@@ -546,6 +636,10 @@
}
this.handshakeCompletedCalled = true;
}
+
+ public Socket getSocket() {
+ return socket;
+ }
}
public static class ServerHooks extends Hooks {
@@ -583,12 +677,13 @@
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"
@@ -598,14 +693,19 @@
+ " 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;
}
});
@@ -777,17 +877,21 @@
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) {
@@ -795,35 +899,49 @@
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);
}
}
@@ -1150,7 +1268,7 @@
SSLHandshakeCallbacks callback)
throws Exception {
NativeCrypto.SSL_renegotiate(s);
- NativeCrypto.SSL_write(s, fd, callback, new byte[] { 42 }, 0, 1);
+ NativeCrypto.SSL_write(s, fd, callback, new byte[] { 42 }, 0, 1, 0);
super.afterHandshake(session, s, c, sock, fd, callback);
}
};
@@ -1317,7 +1435,7 @@
Socket sock, FileDescriptor fd,
SSLHandshakeCallbacks callback)
throws Exception {
- NativeCrypto.SSL_write(s, fd, callback, BYTES, 0, BYTES.length);
+ NativeCrypto.SSL_write(s, fd, callback, BYTES, 0, BYTES.length, 0);
super.afterHandshake(session, s, c, sock, fd, callback);
}
};
@@ -1360,7 +1478,7 @@
public void test_SSL_write() throws Exception {
try {
- NativeCrypto.SSL_write(NULL, null, null, null, 0, 0);
+ NativeCrypto.SSL_write(NULL, null, null, null, 0, 0, 0);
fail();
} catch (NullPointerException expected) {
}
@@ -1370,7 +1488,7 @@
int c = NativeCrypto.SSL_CTX_new();
int s = NativeCrypto.SSL_new(c);
try {
- NativeCrypto.SSL_write(s, null, DUMMY_CB, null, 0, 1);
+ NativeCrypto.SSL_write(s, null, DUMMY_CB, null, 0, 1, 0);
fail();
} catch (NullPointerException expected) {
}
@@ -1383,7 +1501,7 @@
int c = NativeCrypto.SSL_CTX_new();
int s = NativeCrypto.SSL_new(c);
try {
- NativeCrypto.SSL_write(s, INVALID_FD, null, null, 0, 1);
+ NativeCrypto.SSL_write(s, INVALID_FD, null, null, 0, 1, 0);
fail();
} catch (NullPointerException expected) {
}
@@ -1396,7 +1514,7 @@
int c = NativeCrypto.SSL_CTX_new();
int s = NativeCrypto.SSL_new(c);
try {
- NativeCrypto.SSL_write(s, INVALID_FD, DUMMY_CB, null, 0, 1);
+ NativeCrypto.SSL_write(s, INVALID_FD, DUMMY_CB, null, 0, 1, 0);
fail();
} catch (NullPointerException expected) {
}
@@ -1409,7 +1527,7 @@
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 @@
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 @@
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 @@
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 @@
} 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 @@
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/java/lang/ref/PhantomReferenceTest.java b/luni/src/test/java/tests/api/java/lang/ref/PhantomReferenceTest.java
index 06221c9..6470579 100644
--- a/luni/src/test/java/tests/api/java/lang/ref/PhantomReferenceTest.java
+++ b/luni/src/test/java/tests/api/java/lang/ref/PhantomReferenceTest.java
@@ -20,6 +20,7 @@
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
+import libcore.java.lang.ref.FinalizationTester;
//TODO: write a test to verify that the referent's finalize() happens
// before the PhantomReference is enqueued.
@@ -81,8 +82,8 @@
Thread t = new TestThread();
t.start();
t.join();
- System.gc();
- System.runFinalization();
+
+ FinalizationTester.induceFinalization();
assertNull("get() should return null.", tprs[0].get());
assertNull("get() should return null.", tprs[1].get());
diff --git a/luni/src/test/java/tests/api/java/lang/ref/ReferenceQueueTest.java b/luni/src/test/java/tests/api/java/lang/ref/ReferenceQueueTest.java
index dc7e738..cad61b3 100644
--- a/luni/src/test/java/tests/api/java/lang/ref/ReferenceQueueTest.java
+++ b/luni/src/test/java/tests/api/java/lang/ref/ReferenceQueueTest.java
@@ -22,6 +22,7 @@
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
+import libcore.java.lang.ref.FinalizationTester;
public class ReferenceQueueTest extends junit.framework.TestCase {
static Boolean b;
@@ -97,8 +98,7 @@
sr.enqueue();
wr.enqueue();
- System.gc();
- System.runFinalization();
+ FinalizationTester.induceFinalization();
assertNull(rq.poll());
}
diff --git a/luni/src/test/java/tests/api/java/lang/ref/ReferenceTest.java b/luni/src/test/java/tests/api/java/lang/ref/ReferenceTest.java
index a1a7a8c..7461b47 100644
--- a/luni/src/test/java/tests/api/java/lang/ref/ReferenceTest.java
+++ b/luni/src/test/java/tests/api/java/lang/ref/ReferenceTest.java
@@ -22,6 +22,7 @@
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import junit.framework.AssertionFailedError;
+import libcore.java.lang.ref.FinalizationTester;
public class ReferenceTest extends junit.framework.TestCase {
Object tmpA, tmpB, tmpC, obj;
@@ -146,16 +147,14 @@
ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
r = newWeakReference(queue);
- System.gc();
- System.runFinalization();
+ FinalizationTester.induceFinalization();
Reference ref = queue.remove();
assertNotNull("Object not enqueued.", ref);
assertSame("Unexpected ref1", ref, r);
assertNull("Object could not be reclaimed1.", r.get());
r = newWeakReference(queue);
- System.gc();
- System.runFinalization();
+ FinalizationTester.induceFinalization();
// wait for the reference queue thread to enqueue the newly-finalized object
Thread.yield();
@@ -213,8 +212,7 @@
Thread t = new TestThread();
t.start();
t.join();
- System.gc();
- System.runFinalization();
+ FinalizationTester.induceFinalization();
ref = rq.remove(5000L); // Give up after five seconds.
assertNotNull("Object not garbage collected.", ref);
@@ -238,8 +236,7 @@
public void test_get() {
WeakReference ref = newWeakReference(null);
- System.gc();
- System.runFinalization();
+ FinalizationTester.induceFinalization();
assertNull("get() doesn't return null after gc for WeakReference", ref.get());
obj = new Object();
@@ -322,8 +319,7 @@
Thread t = new TestThread();
t.start();
t.join();
- System.gc();
- System.runFinalization();
+ FinalizationTester.induceFinalization();
Thread.sleep(1000);
if (error != null) {
throw error;
diff --git a/luni/src/test/java/tests/api/java/lang/ref/SoftReferenceTest.java b/luni/src/test/java/tests/api/java/lang/ref/SoftReferenceTest.java
index 77c6536..197d829 100644
--- a/luni/src/test/java/tests/api/java/lang/ref/SoftReferenceTest.java
+++ b/luni/src/test/java/tests/api/java/lang/ref/SoftReferenceTest.java
@@ -22,6 +22,7 @@
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.Vector;
+import libcore.java.lang.ref.FinalizationTester;
public class SoftReferenceTest extends junit.framework.TestCase {
static Boolean bool;
@@ -124,8 +125,7 @@
TestThread t = new TestThread();
t.start();
t.join();
- System.gc();
- System.runFinalization();
+ FinalizationTester.induceFinalization();
ref = rq.poll();
assertNotNull("Object not garbage collected.", ref);
assertNull("Object is not null.", ref.get());
diff --git a/luni/src/test/java/tests/api/java/util/WeakHashMapTest.java b/luni/src/test/java/tests/api/java/util/WeakHashMapTest.java
index 0e43bf6..d1a43e5 100644
--- a/luni/src/test/java/tests/api/java/util/WeakHashMapTest.java
+++ b/luni/src/test/java/tests/api/java/util/WeakHashMapTest.java
@@ -25,6 +25,7 @@
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
+import libcore.java.lang.ref.FinalizationTester;
import tests.support.Support_MapTest2;
@@ -208,7 +209,7 @@
do {
System.gc();
System.gc();
- Runtime.getRuntime().runFinalization();
+ FinalizationTester.induceFinalization();
count++;
} while (count <= 5 && entrySet.size() == 100);
@@ -240,7 +241,8 @@
WeakHashMap map = new WeakHashMap();
map.put(null, "value"); // add null key
System.gc();
- System.runFinalization();
+ System.gc();
+ FinalizationTester.induceFinalization();
map.remove("nothing"); // Cause objects in queue to be removed
assertEquals("null key was removed", 1, map.size());
}
@@ -315,7 +317,7 @@
do {
System.gc();
System.gc();
- Runtime.getRuntime().runFinalization();
+ FinalizationTester.induceFinalization();
count++;
} while (count <= 5 && keySet.size() == 100);
@@ -352,7 +354,7 @@
do {
System.gc();
System.gc();
- Runtime.getRuntime().runFinalization();
+ FinalizationTester.induceFinalization();
count++;
} while (count <= 5 && valuesCollection.size() == 100);
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..19c6229 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;
@@ -27,8 +28,6 @@
*/
public class ThreadsTest extends TestCase {
private static Unsafe UNSAFE = null;
- private static RuntimeException INITIALIZEFAILED = null;
-
static {
/*
* Set up {@link #UNSAFE}. This subverts the access check to
@@ -42,78 +41,94 @@
UNSAFE = (Unsafe) field.get(null);
} catch (NoSuchFieldException ex) {
- INITIALIZEFAILED = new RuntimeException(ex);
+ throw new RuntimeException(ex);
} catch (IllegalAccessException ex) {
- INITIALIZEFAILED = new RuntimeException(ex);
+ throw new RuntimeException(ex);
}
}
/** Test the case where the park times out. */
- public void test_parkFor_1() {
- Parker parker = new Parker(false, 500);
+ public void test_parkFor_1() throws Exception {
+ 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();
parker.assertDurationIsInRange(500);
+ waiterThread.join();
+ parkerThread.join();
}
/** Test the case where the unpark happens before the timeout. */
- public void test_parkFor_2() {
- Parker parker = new Parker(false, 1000);
+ public void test_parkFor_2() throws Exception {
+ 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();
parker.assertDurationIsInRange(300);
+ waiterThread.join();
+ parkerThread.join();
}
/** Test the case where the thread is preemptively unparked. */
- public void test_parkFor_3() {
- Parker parker = new Parker(false, 1000);
+ public void test_parkFor_3() throws Exception {
+ CyclicBarrier barrier = new CyclicBarrier(1);
+ Parker parker = new Parker(barrier, false, 1000);
Thread parkerThread = new Thread(parker);
UNSAFE.unpark(parkerThread);
parkerThread.start();
parker.assertDurationIsInRange(0);
+ parkerThread.join();
}
/** Test the case where the park times out. */
- public void test_parkUntil_1() {
- Parker parker = new Parker(true, 500);
+ public void test_parkUntil_1() throws Exception {
+ 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();
parker.assertDurationIsInRange(500);
+ waiterThread.join();
+ parkerThread.join();
}
/** Test the case where the unpark happens before the timeout. */
- public void test_parkUntil_2() {
- Parker parker = new Parker(true, 1000);
+ public void test_parkUntil_2() throws Exception {
+ 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();
parker.assertDurationIsInRange(300);
+ waiterThread.join();
+ parkerThread.join();
}
/** Test the case where the thread is preemptively unparked. */
- public void test_parkUntil_3() {
- Parker parker = new Parker(true, 1000);
+ public void test_parkUntil_3() throws Exception {
+ CyclicBarrier barrier = new CyclicBarrier(1);
+ Parker parker = new Parker(barrier, true, 1000);
Thread parkerThread = new Thread(parker);
UNSAFE.unpark(parkerThread);
parkerThread.start();
parker.assertDurationIsInRange(0);
+ parkerThread.join();
}
// TODO: Add more tests.
@@ -123,6 +138,9 @@
* 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 +165,8 @@
* 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 +174,14 @@
}
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 +190,11 @@
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();
}
@@ -199,7 +224,7 @@
}
/**
- * Asserts that the actual duration is within 5% of the
+ * Asserts that the actual duration is within 10% of the
* given expected time.
*
* @param expectedMillis the expected duration, in milliseconds
@@ -209,18 +234,20 @@
* Allow a bit more slop for the maximum on "expected
* instantaneous" results.
*/
- long minimum = (long) ((double) expectedMillis * 0.95);
+ long minimum = (long) ((double) expectedMillis * 0.90);
long maximum =
- Math.max((long) ((double) expectedMillis * 1.05), 10);
+ Math.max((long) ((double) expectedMillis * 1.10), 10);
long waitMillis = Math.max(expectedMillis * 10, 10);
long duration = getDurationMillis(waitMillis);
if (duration < minimum) {
Assert.fail("expected duration: " + expectedMillis +
- "; actual too short: " + duration);
+ " minimum duration: " + minimum +
+ " actual duration too short: " + duration);
} else if (duration > maximum) {
Assert.fail("expected duration: " + expectedMillis +
- "; actual too long: " + duration);
+ " maximum duration: " + maximum +
+ " actual duration too long: " + duration);
}
}
}
@@ -230,16 +257,23 @@
* 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);
@@ -248,11 +282,4 @@
UNSAFE.unpark(thread);
}
}
-
- @Override
- protected void setUp() throws Exception {
- if (INITIALIZEFAILED != null) {
- throw INITIALIZEFAILED;
- }
- }
}
diff --git a/support/src/test/java/libcore/java/security/StandardNames.java b/support/src/test/java/libcore/java/security/StandardNames.java
index eb53ba5..be880d3 100644
--- a/support/src/test/java/libcore/java/security/StandardNames.java
+++ b/support/src/test/java/libcore/java/security/StandardNames.java
@@ -85,6 +85,13 @@
*/
public static final Map<String,Set<String>> PROVIDER_ALGORITHMS
= new HashMap<String,Set<String>>();
+
+ public static final Map<String,Set<String>> CIPHER_MODES
+ = new HashMap<String,Set<String>>();
+
+ public static final Map<String,Set<String>> CIPHER_PADDINGS
+ = new HashMap<String,Set<String>>();
+
private static void provide(String type, String algorithm) {
Set<String> algorithms = PROVIDER_ALGORITHMS.get(type);
if (algorithms == null) {
@@ -102,6 +109,22 @@
assertNotNull(PROVIDER_ALGORITHMS.remove(type));
}
}
+ private static void provideCipherModes(String algorithm, String newModes[]) {
+ Set<String> modes = CIPHER_MODES.get(algorithm);
+ if (modes == null) {
+ modes = new HashSet<String>();
+ CIPHER_MODES.put(algorithm, modes);
+ }
+ modes.addAll(Arrays.asList(newModes));
+ }
+ private static void provideCipherPaddings(String algorithm, String newPaddings[]) {
+ Set<String> paddings = CIPHER_MODES.get(algorithm);
+ if (paddings == null) {
+ paddings = new HashSet<String>();
+ CIPHER_MODES.put(algorithm, paddings);
+ }
+ paddings.addAll(Arrays.asList(newPaddings));
+ }
static {
provide("AlgorithmParameterGenerator", "DSA");
provide("AlgorithmParameterGenerator", "DiffieHellman");
@@ -122,7 +145,10 @@
provide("CertStore", "Collection");
provide("CertStore", "LDAP");
provide("CertificateFactory", "X.509");
+ // TODO: provideCipherModes and provideCipherPaddings for other Ciphers
provide("Cipher", "AES");
+ provideCipherModes("AES", new String[] { "CBC", "CFB", "CTR", "CTS", "ECB", "OFB" });
+ provideCipherPaddings("AES", new String[] { "NoPadding", "PKCS5Padding" });
provide("Cipher", "AESWrap");
provide("Cipher", "ARCFOUR");
provide("Cipher", "Blowfish");
@@ -322,18 +348,6 @@
unprovide("MessageDigest", "SHA");
provide("MessageDigest", "SHA-1");
- // 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");
provide("Cipher", "RSA/ECB/NOPADDING");
@@ -451,6 +465,12 @@
// Android's CA store
provide("KeyStore", "AndroidCAStore");
+
+ // Android's KeyStore provider
+ if (Security.getProvider("AndroidKeyStoreProvider") != null) {
+ provide("KeyStore", "AndroidKeyStore");
+ provide("KeyPairGenerator", "AndroidKeyPairGenerator");
+ }
}
}
@@ -850,4 +870,18 @@
assertValidCipherSuites(CIPHER_SUITES, cipherSuites);
assertEquals(CIPHER_SUITES_DEFAULT, Arrays.asList(cipherSuites));
}
+
+ /**
+ * Get all supported mode names for the given cipher.
+ */
+ public static Set<String> getModesForCipher(String cipher) {
+ return CIPHER_MODES.get(cipher);
+ }
+
+ /**
+ * Get all supported padding names for the given cipher.
+ */
+ public static Set<String> getPaddingsForCipher(String cipher) {
+ return CIPHER_PADDINGS.get(cipher);
+ }
}
diff --git a/support/src/test/java/tests/net/StuckServer.java b/support/src/test/java/tests/net/StuckServer.java
index eababce..f7a3118 100644
--- a/support/src/test/java/tests/net/StuckServer.java
+++ b/support/src/test/java/tests/net/StuckServer.java
@@ -17,6 +17,7 @@
package tests.net;
import java.io.IOException;
+import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
@@ -26,48 +27,57 @@
* A test ServerSocket that you can't connect to --- connects will time out.
*/
public final class StuckServer {
+ private static final boolean DEBUG = false;
+
private ServerSocket serverSocket;
+ private InetSocketAddress address;
private ArrayList<Socket> clients = new ArrayList<Socket>();
- public StuckServer() throws IOException {
+ public StuckServer(boolean useBacklog) throws IOException {
// Set a backlog and use it up so that we can expect the
- // connection to time out. According to Steven's
+ // connection to time out. According to Stevens
// 4.5 "listen function", Linux adds 3 to the specified
// backlog, so we need to connect 4 times before it will hang.
- serverSocket = new ServerSocket(0, 1);
- for (int i = 0; i < 4; i++) {
- clients.add(new Socket(serverSocket.getInetAddress(), serverSocket.getLocalPort()));
+ // The trouble with this is that it won't hang forever.
+ // After 10s or so, the kernel allows a couple more connections.
+ // This mode is ony useful if you actually want to continue eventually; we use it to
+ // test non-blocking connects, for example, where you want to test every part of the code.
+ if (useBacklog) {
+ this.serverSocket = new ServerSocket(0, 1);
+ this.address = (InetSocketAddress) serverSocket.getLocalSocketAddress();
+ if (DEBUG) {
+ System.err.println("StuckServer: " + serverSocket);
+ }
+ for (int i = 0; i < 4; ++i) {
+ Socket client = new Socket(serverSocket.getInetAddress(), serverSocket.getLocalPort());
+ clients.add(client);
+ if (DEBUG) {
+ System.err.println("StuckServer client " + i + " - " + client);
+ }
+ }
+ } else {
+ // In general, though, you don't want to rely on listen(2) backlog. http://b/6971145.
+ // RFC 5737 implies this network will be unreachable. (There are two other networks
+ // to try if we have trouble with this one.)
+ // We've had trouble with 10.* in the past (because test labs running CTS often use
+ // net 10!) but hopefully this network will be better.
+ InetAddress testNet1 = InetAddress.getByAddress(new byte[] { (byte) 192, 0, 2, 0 });
+ this.address = new InetSocketAddress(testNet1, 80);
}
}
- public void unblockAfterMs(final int ms) {
- Thread t = new Thread(new Runnable() {
- @Override public void run() {
- try {
- Thread.sleep(ms);
- for (Socket client : clients) {
- client.close();
- }
- clients.clear();
- clients.add(serverSocket.accept());
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- }
- });
- t.start();
- }
-
public InetSocketAddress getLocalSocketAddress() {
- return (InetSocketAddress) serverSocket.getLocalSocketAddress();
+ return address;
}
public int getLocalPort() {
- return serverSocket.getLocalPort();
+ return address.getPort();
}
public void close() throws IOException {
- serverSocket.close();
+ if (serverSocket != null) {
+ serverSocket.close();
+ }
for (Socket client : clients) {
client.close();
}