diff options
15 files changed, 616 insertions, 87 deletions
diff --git a/JavaLibrary.mk b/JavaLibrary.mk index c857390..57a8f82 100644 --- a/JavaLibrary.mk +++ b/JavaLibrary.mk @@ -84,9 +84,6 @@ LOCAL_MODULE_TAGS := optional LOCAL_MODULE := core-libart LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/JavaLibrary.mk LOCAL_REQUIRED_MODULES := tzdata -# Should not be dex-preopted as it isn't really a Dalvik boot jar or a -# regular java library, but part of the image for ART. -LOCAL_DEX_PREOPT := false include $(BUILD_JAVA_LIBRARY) ifeq ($(LIBCORE_SKIP_TESTS),) @@ -165,9 +162,6 @@ LOCAL_MODULE_TAGS := optional LOCAL_MODULE := core-libart-hostdex LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/JavaLibrary.mk LOCAL_REQUIRED_MODULES := tzdata-host -# Should not be dex-preopted as it isn't really a Dalvik boot jar or a -# regular java library, but part of the image for ART. -LOCAL_DEX_PREOPT := false include $(BUILD_HOST_DALVIK_JAVA_LIBRARY) # Make the core-tests library. diff --git a/expectations/knownfailures.txt b/expectations/knownfailures.txt index cf93bab..71f02ed 100644 --- a/expectations/knownfailures.txt +++ b/expectations/knownfailures.txt @@ -1461,6 +1461,7 @@ "com.squareup.okhttp.internal.spdy.SpdyConnectionTest", "com.squareup.okhttp.internal.http.HttpOverHttp20Draft09Test", "com.squareup.okhttp.internal.http.HttpOverSpdy3Test", + "com.squareup.okhttp.internal.http.ResponseCacheAdapterTest", "com.squareup.okhttp.internal.http.URLConnectionTest#npnSetsProtocolHeader_SPDY_3", "com.squareup.okhttp.internal.http.URLConnectionTest#npnSetsProtocolHeader_HTTP_2", "com.squareup.okhttp.internal.http.URLConnectionTest#zeroLengthPost_SPDY_3", diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/MulticastSocketTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/MulticastSocketTest.java index e3e1207..d531301 100644 --- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/MulticastSocketTest.java +++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/MulticastSocketTest.java @@ -56,6 +56,7 @@ public class MulticastSocketTest extends junit.framework.TestCase { private NetworkInterface loopbackInterface; private NetworkInterface ipv4NetworkInterface; private NetworkInterface ipv6NetworkInterface; + private boolean supportsMulticast; @Override protected void setUp() throws Exception { @@ -69,6 +70,14 @@ public class MulticastSocketTest extends junit.framework.TestCase { Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces(); assertNotNull(interfaces); + // Determine if the device is marked to support multicast or not. If this propery is not + // set we assume the device has an interface capable of supporting multicast. + supportsMulticast = Boolean.valueOf( + System.getProperty("android.cts.device.multicast", "true")); + if (!supportsMulticast) { + return; + } + while (interfaces.hasMoreElements() && (ipv4NetworkInterface == null || ipv6NetworkInterface == null)) { NetworkInterface nextInterface = interfaces.nextElement(); @@ -90,6 +99,9 @@ public class MulticastSocketTest extends junit.framework.TestCase { } public void test_Constructor() throws IOException { + if (!supportsMulticast) { + return; + } // Regression test for 497. MulticastSocket s = new MulticastSocket(); // Regression test for Harmony-1162. @@ -99,6 +111,9 @@ public class MulticastSocketTest extends junit.framework.TestCase { } public void test_ConstructorI() throws IOException { + if (!supportsMulticast) { + return; + } MulticastSocket orig = new MulticastSocket(); int port = orig.getLocalPort(); orig.close(); @@ -110,6 +125,9 @@ public class MulticastSocketTest extends junit.framework.TestCase { } public void test_getInterface() throws Exception { + if (!supportsMulticast) { + return; + } // Validate that we get the expected response when one was not set. MulticastSocket mss = new MulticastSocket(0); // We expect an ANY address in this case. @@ -134,6 +152,9 @@ public class MulticastSocketTest extends junit.framework.TestCase { } public void test_getNetworkInterface() throws IOException { + if (!supportsMulticast) { + return; + } // Validate that we get the expected response when one was not set. MulticastSocket mss = new MulticastSocket(0); NetworkInterface theInterface = mss.getNetworkInterface(); @@ -176,6 +197,9 @@ public class MulticastSocketTest extends junit.framework.TestCase { } public void test_getTimeToLive() throws Exception { + if (!supportsMulticast) { + return; + } MulticastSocket mss = new MulticastSocket(); mss.setTimeToLive(120); assertEquals("Returned incorrect 1st TTL", 120, mss.getTimeToLive()); @@ -185,6 +209,9 @@ public class MulticastSocketTest extends junit.framework.TestCase { } public void test_getTTL() throws Exception { + if (!supportsMulticast) { + return; + } MulticastSocket mss = new MulticastSocket(); mss.setTTL((byte) 120); assertEquals("Returned incorrect TTL", 120, mss.getTTL()); @@ -192,10 +219,16 @@ public class MulticastSocketTest extends junit.framework.TestCase { } public void test_joinGroupLjava_net_InetAddress_IPv4() throws Exception { + if (!supportsMulticast) { + return; + } test_joinGroupLjava_net_InetAddress(GOOD_IPv4); } public void test_joinGroupLjava_net_InetAddress_IPv6() throws Exception { + if (!supportsMulticast) { + return; + } test_joinGroupLjava_net_InetAddress(GOOD_IPv6); } @@ -220,6 +253,9 @@ public class MulticastSocketTest extends junit.framework.TestCase { } public void test_joinGroup_null_null() throws Exception { + if (!supportsMulticast) { + return; + } MulticastSocket mss = new MulticastSocket(0); try { mss.joinGroup(null, null); @@ -230,6 +266,9 @@ public class MulticastSocketTest extends junit.framework.TestCase { } public void test_joinGroup_non_multicast_address_IPv4() throws Exception { + if (!supportsMulticast) { + return; + } MulticastSocket mss = new MulticastSocket(0); try { mss.joinGroup(new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 0), null); @@ -240,6 +279,9 @@ public class MulticastSocketTest extends junit.framework.TestCase { } public void test_joinGroup_non_multicast_address_IPv6() throws Exception { + if (!supportsMulticast) { + return; + } MulticastSocket mss = new MulticastSocket(0); try { mss.joinGroup(new InetSocketAddress(InetAddress.getByName("::1"), 0), null); @@ -251,12 +293,18 @@ public class MulticastSocketTest extends junit.framework.TestCase { public void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv4() throws Exception { + if (!supportsMulticast) { + return; + } test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface( ipv4NetworkInterface, GOOD_IPv4, BAD_IPv4); } public void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv6() throws Exception { + if (!supportsMulticast) { + return; + } test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface( ipv6NetworkInterface, GOOD_IPv6, BAD_IPv6); } @@ -310,6 +358,9 @@ public class MulticastSocketTest extends junit.framework.TestCase { } public void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface() throws Exception { + if (!supportsMulticast) { + return; + } // Check that we can join on specific interfaces and that we only receive if data is // received on that interface. This test is only really useful on devices with multiple // non-loopback interfaces. @@ -378,12 +429,18 @@ public class MulticastSocketTest extends junit.framework.TestCase { public void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins_IPv4() throws Exception { + if (!supportsMulticast) { + return; + } test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins( ipv4NetworkInterface, GOOD_IPv4); } public void test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins_IPv6() throws Exception { + if (!supportsMulticast) { + return; + } test_joinGroupLjava_net_SocketAddressLjava_net_NetworkInterface_multiple_joins( ipv6NetworkInterface, GOOD_IPv6); } @@ -405,10 +462,16 @@ public class MulticastSocketTest extends junit.framework.TestCase { } public void test_leaveGroupLjava_net_InetAddress_IPv4() throws Exception { + if (!supportsMulticast) { + return; + } test_leaveGroupLjava_net_InetAddress(GOOD_IPv4); } public void test_leaveGroupLjava_net_InetAddress_IPv6() throws Exception { + if (!supportsMulticast) { + return; + } test_leaveGroupLjava_net_InetAddress(GOOD_IPv6); } @@ -428,6 +491,9 @@ public class MulticastSocketTest extends junit.framework.TestCase { } public void test_leaveGroup_null_null() throws Exception { + if (!supportsMulticast) { + return; + } MulticastSocket mss = new MulticastSocket(0); try { mss.leaveGroup(null, null); @@ -438,6 +504,9 @@ public class MulticastSocketTest extends junit.framework.TestCase { } public void test_leaveGroup_non_multicast_address_IPv4() throws Exception { + if (!supportsMulticast) { + return; + } MulticastSocket mss = new MulticastSocket(0); try { mss.leaveGroup(new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 0), null); @@ -448,6 +517,9 @@ public class MulticastSocketTest extends junit.framework.TestCase { } public void test_leaveGroup_non_multicast_address_IPv6() throws Exception { + if (!supportsMulticast) { + return; + } MulticastSocket mss = new MulticastSocket(0); try { mss.leaveGroup(new InetSocketAddress(InetAddress.getByName("::1"), 0), null); @@ -459,12 +531,18 @@ public class MulticastSocketTest extends junit.framework.TestCase { public void test_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv4() throws Exception { + if (!supportsMulticast) { + return; + } test_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface( ipv4NetworkInterface, GOOD_IPv4, BAD_IPv4); } public void test_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface_IPv6() throws Exception { + if (!supportsMulticast) { + return; + } test_leaveGroupLjava_net_SocketAddressLjava_net_NetworkInterface( ipv6NetworkInterface, GOOD_IPv6, BAD_IPv6); } @@ -505,10 +583,16 @@ public class MulticastSocketTest extends junit.framework.TestCase { } public void test_sendLjava_net_DatagramPacketB_IPv4() throws Exception { + if (!supportsMulticast) { + return; + } test_sendLjava_net_DatagramPacketB(GOOD_IPv4); } public void test_sendLjava_net_DatagramPacketB_IPv6() throws Exception { + if (!supportsMulticast) { + return; + } test_sendLjava_net_DatagramPacketB(GOOD_IPv6); } @@ -531,6 +615,9 @@ public class MulticastSocketTest extends junit.framework.TestCase { } public void test_setInterfaceLjava_net_InetAddress() throws Exception { + if (!supportsMulticast) { + return; + } MulticastSocket mss = new MulticastSocket(); mss.setInterface(InetAddress.getLocalHost()); InetAddress theInterface = mss.getInterface(); @@ -549,10 +636,16 @@ public class MulticastSocketTest extends junit.framework.TestCase { } public void test_setInterface_unbound_address_IPv4() throws Exception { + if (!supportsMulticast) { + return; + } test_setInterface_unbound_address(GOOD_IPv4); } public void test_setInterface_unbound_address_IPv6() throws Exception { + if (!supportsMulticast) { + return; + } test_setInterface_unbound_address(GOOD_IPv6); } @@ -568,6 +661,9 @@ public class MulticastSocketTest extends junit.framework.TestCase { } public void test_setNetworkInterfaceLjava_net_NetworkInterface_null() throws Exception { + if (!supportsMulticast) { + return; + } // Validate that null interface is handled ok. MulticastSocket mss = new MulticastSocket(); try { @@ -579,6 +675,9 @@ public class MulticastSocketTest extends junit.framework.TestCase { } public void test_setNetworkInterfaceLjava_net_NetworkInterface_round_trip() throws Exception { + if (!supportsMulticast) { + return; + } // Validate that we can get and set the interface. MulticastSocket mss = new MulticastSocket(); mss.setNetworkInterface(ipv4NetworkInterface); @@ -588,10 +687,16 @@ public class MulticastSocketTest extends junit.framework.TestCase { } public void test_setNetworkInterfaceLjava_net_NetworkInterface_IPv4() throws Exception { + if (!supportsMulticast) { + return; + } test_setNetworkInterfaceLjava_net_NetworkInterface(GOOD_IPv4); } public void test_setNetworkInterfaceLjava_net_NetworkInterface_IPv6() throws Exception { + if (!supportsMulticast) { + return; + } test_setNetworkInterfaceLjava_net_NetworkInterface(GOOD_IPv6); } @@ -630,6 +735,9 @@ public class MulticastSocketTest extends junit.framework.TestCase { } public void test_setTimeToLiveI() throws Exception { + if (!supportsMulticast) { + return; + } MulticastSocket mss = new MulticastSocket(); mss.setTimeToLive(120); assertEquals("Returned incorrect 1st TTL", 120, mss.getTimeToLive()); @@ -639,6 +747,9 @@ public class MulticastSocketTest extends junit.framework.TestCase { } public void test_setTTLB() throws Exception { + if (!supportsMulticast) { + return; + } MulticastSocket mss = new MulticastSocket(); mss.setTTL((byte) 120); assertEquals("Failed to set TTL", 120, mss.getTTL()); @@ -646,6 +757,9 @@ public class MulticastSocketTest extends junit.framework.TestCase { } public void test_ConstructorLjava_net_SocketAddress() throws Exception { + if (!supportsMulticast) { + return; + } MulticastSocket ms = new MulticastSocket((SocketAddress) null); assertTrue("should not be bound", !ms.isBound() && !ms.isClosed() && !ms.isConnected()); ms.bind(null); @@ -677,6 +791,9 @@ public class MulticastSocketTest extends junit.framework.TestCase { } public void test_getLoopbackMode() throws Exception { + if (!supportsMulticast) { + return; + } MulticastSocket ms = new MulticastSocket(null); assertTrue("should not be bound", !ms.isBound() && !ms.isClosed() && !ms.isConnected()); ms.getLoopbackMode(); @@ -686,6 +803,9 @@ public class MulticastSocketTest extends junit.framework.TestCase { } public void test_setLoopbackModeZ() throws Exception { + if (!supportsMulticast) { + return; + } MulticastSocket ms = new MulticastSocket(); ms.setLoopbackMode(true); assertTrue("loopback should be true", ms.getLoopbackMode()); @@ -696,10 +816,16 @@ public class MulticastSocketTest extends junit.framework.TestCase { } public void test_setLoopbackModeSendReceive_IPv4() throws Exception { + if (!supportsMulticast) { + return; + } test_setLoopbackModeSendReceive(GOOD_IPv4); } public void test_setLoopbackModeSendReceive_IPv6() throws Exception { + if (!supportsMulticast) { + return; + } test_setLoopbackModeSendReceive(GOOD_IPv6); } @@ -726,6 +852,9 @@ public class MulticastSocketTest extends junit.framework.TestCase { } public void test_setReuseAddressZ() throws Exception { + if (!supportsMulticast) { + return; + } // Test case were we to set ReuseAddress to false. MulticastSocket theSocket1 = new MulticastSocket(null); theSocket1.setReuseAddress(false); @@ -797,5 +926,4 @@ public class MulticastSocketTest extends junit.framework.TestCase { private static String extractMessage(DatagramPacket rdp) { return new String(rdp.getData(), 0, rdp.getLength()); } - } diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java index f55829d..0bc8920 100644 --- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java +++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java @@ -37,7 +37,14 @@ import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.Enumeration; +import java.util.List; import java.util.Vector; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.jar.Attributes; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -97,6 +104,27 @@ public class JarFileTest extends TestCase { private final String emptyEntryJar = "EmptyEntries_signed.jar"; + /* + * /usr/bin/openssl genrsa 2048 > root1.pem + * /usr/bin/openssl req -new -key root1.pem -out root1.csr -subj '/CN=root1' + * /usr/bin/openssl x509 -req -days 3650 -in root1.csr -signkey root1.pem -out root1.crt + * /usr/bin/openssl genrsa 2048 > root2.pem + * /usr/bin/openssl req -new -key root2.pem -out root2.csr -subj '/CN=root2' + * echo 4000 > root1.srl + * echo 8000 > root2.srl + * /usr/bin/openssl x509 -req -days 3650 -in root2.csr -CA root1.crt -CAkey root1.pem -out root2.crt + * /usr/bin/openssl x509 -req -days 3650 -in root1.csr -CA root2.crt -CAkey root2.pem -out root1.crt + * /usr/bin/openssl genrsa 2048 > signer.pem + * /usr/bin/openssl req -new -key signer.pem -out signer.csr -subj '/CN=signer' + * /usr/bin/openssl x509 -req -days 3650 -in signer.csr -CA root1.crt -CAkey root1.pem -out signer.crt + * /usr/bin/openssl pkcs12 -inkey signer.pem -in signer.crt -export -out signer.p12 -name signer -passout pass:certloop + * keytool -importkeystore -srckeystore signer.p12 -srcstoretype PKCS12 -destkeystore signer.jks -srcstorepass certloop -deststorepass certloop + * cat signer.crt root1.crt root2.crt > chain.crt + * zip -d hyts_certLoop.jar 'META-INF/*' + * jarsigner -keystore signer.jks -certchain chain.crt -storepass certloop hyts_certLoop.jar signer + */ + private final String certLoopJar = "hyts_certLoop.jar"; + private final String emptyEntry1 = "subfolder/internalSubset01.js"; private final String emptyEntry2 = "svgtest.js"; @@ -616,6 +644,9 @@ public class JarFileTest extends TestCase { // JAR with a signature that has PKCS#7 Authenticated Attributes checkSignedJar(authAttrsJar); + + // JAR with certificates that loop + checkSignedJar(certLoopJar, 3); } /** @@ -628,29 +659,52 @@ public class JarFileTest extends TestCase { checkSignedJar(jarName9); } + /** + * Checks that a JAR is signed correctly with a signature length of 1. + */ private void checkSignedJar(String jarName) throws Exception { - Support_Resources.copyFile(resources, null, jarName); + checkSignedJar(jarName, 1); + } - File file = new File(resources, jarName); - boolean foundCerts = false; + /** + * Checks that a JAR is signed correctly with a signature length of sigLength. + */ + private void checkSignedJar(String jarName, final int sigLength) throws Exception { + Support_Resources.copyFile(resources, null, jarName); - JarFile jarFile = new JarFile(file, true); - try { + final File file = new File(resources, jarName); - Enumeration<JarEntry> e = jarFile.entries(); - while (e.hasMoreElements()) { - JarEntry entry = e.nextElement(); - InputStream is = jarFile.getInputStream(entry); - is.skip(100000); - is.close(); - Certificate[] certs = entry.getCertificates(); - if (certs != null && certs.length > 0) { - foundCerts = true; - break; + ExecutorService executor = Executors.newSingleThreadExecutor(); + Future<Boolean> future = executor.submit(new Callable<Boolean>() { + @Override + public Boolean call() throws Exception { + JarFile jarFile = new JarFile(file, true); + try { + Enumeration<JarEntry> e = jarFile.entries(); + while (e.hasMoreElements()) { + JarEntry entry = e.nextElement(); + InputStream is = jarFile.getInputStream(entry); + is.skip(100000); + is.close(); + Certificate[] certs = entry.getCertificates(); + if (certs != null && certs.length > 0) { + assertEquals(sigLength, certs.length); + return true; + } + } + return false; + } finally { + jarFile.close(); } } - } finally { - jarFile.close(); + }); + executor.shutdown(); + final boolean foundCerts; + try { + foundCerts = future.get(10, TimeUnit.SECONDS); + } catch (TimeoutException e) { + fail("Could not finish building chain; possibly confused by loops"); + return; // Not actually reached. } assertTrue( diff --git a/luni/src/main/java/java/util/Locale.java b/luni/src/main/java/java/util/Locale.java index e509a6e..a6368e8 100644 --- a/luni/src/main/java/java/util/Locale.java +++ b/luni/src/main/java/java/util/Locale.java @@ -95,7 +95,7 @@ import libcore.icu.ICU; * <td><a href="http://site.icu-project.org/download/51">ICU 51</a></td> * <td><a href="http://cldr.unicode.org/index/downloads/cldr-23">CLDR 23</a></td> * <td><a href="http://www.unicode.org/versions/Unicode6.2.0/">Unicode 6.2</a></td></tr> - * <tr><td>Android 4.? (STOPSHIP)</td> + * <tr><td>Android 5.0 (Lollipop)</td> * <td><a href="http://site.icu-project.org/download/53">ICU 53</a></td> * <td><a href="http://cldr.unicode.org/index/downloads/cldr-25">CLDR 25</a></td> * <td><a href="http://www.unicode.org/versions/Unicode6.3.0/">Unicode 6.3</a></td></tr> diff --git a/luni/src/main/java/libcore/util/ZoneInfo.java b/luni/src/main/java/libcore/util/ZoneInfo.java index 4a70a83..4d58d93 100644 --- a/luni/src/main/java/libcore/util/ZoneInfo.java +++ b/luni/src/main/java/libcore/util/ZoneInfo.java @@ -360,10 +360,16 @@ public final class ZoneInfo extends TimeZone { private int gmtOffsetSeconds; public WallTime() { - this.calendar = new GregorianCalendar(false); + this.calendar = createGregorianCalendar(); calendar.setTimeZone(TimeZone.getTimeZone("UTC")); } + // LayoutLib replaces this method via bytecode manipulation, since the + // minimum-cost constructor is not available on host machines. + private static GregorianCalendar createGregorianCalendar() { + return new GregorianCalendar(false); + } + /** * Sets the wall time to a point in time using the time zone information provided. This * is a replacement for the old native localtime_tz() function. diff --git a/luni/src/main/java/org/apache/harmony/security/utils/JarUtils.java b/luni/src/main/java/org/apache/harmony/security/utils/JarUtils.java index 33584d8..020663e 100644 --- a/luni/src/main/java/org/apache/harmony/security/utils/JarUtils.java +++ b/luni/src/main/java/org/apache/harmony/security/utils/JarUtils.java @@ -31,6 +31,7 @@ import java.security.NoSuchAlgorithmException; import java.security.Principal; import java.security.Signature; import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.ArrayList; @@ -82,8 +83,10 @@ public class JarUtils { CertificateFactory cf = CertificateFactory.getInstance("X.509"); int i = 0; for (org.apache.harmony.security.x509.Certificate encCert : encCerts) { - final InputStream is = new ByteArrayInputStream(encCert.getEncoded()); - certs[i++] = (X509Certificate) cf.generateCertificate(is); + final byte[] encoded = encCert.getEncoded(); + final InputStream is = new ByteArrayInputStream(encoded); + certs[i++] = new VerbatimX509Certificate((X509Certificate) cf.generateCertificate(is), + encoded); } List<SignerInfo> sigInfos = signedData.getSignerInfos(); @@ -246,6 +249,10 @@ public class JarUtils { } chain.add(issuerCert); count++; + /* Prevent growing infinitely if there is a loop */ + if (count > candidates.length) { + break; + } issuer = issuerCert.getIssuerDN(); if (issuerCert.getSubjectDN().equals(issuer)) { break; @@ -263,4 +270,22 @@ public class JarUtils { return null; } + /** + * For legacy reasons we need to return exactly the original encoded + * certificate bytes, instead of letting the underlying implementation have + * a shot at re-encoding the data. + */ + private static class VerbatimX509Certificate extends WrappedX509Certificate { + private byte[] encodedVerbatim; + + public VerbatimX509Certificate(X509Certificate wrapped, byte[] encodedVerbatim) { + super(wrapped); + this.encodedVerbatim = encodedVerbatim; + } + + @Override + public byte[] getEncoded() throws CertificateEncodingException { + return encodedVerbatim; + } + } } diff --git a/luni/src/main/java/org/apache/harmony/security/utils/WrappedX509Certificate.java b/luni/src/main/java/org/apache/harmony/security/utils/WrappedX509Certificate.java new file mode 100644 index 0000000..2b09309 --- /dev/null +++ b/luni/src/main/java/org/apache/harmony/security/utils/WrappedX509Certificate.java @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2014 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.security.utils; + +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Principal; +import java.security.PublicKey; +import java.security.SignatureException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateNotYetValidException; +import java.security.cert.X509Certificate; +import java.util.Date; +import java.util.Set; + +public class WrappedX509Certificate extends X509Certificate { + private final X509Certificate wrapped; + + public WrappedX509Certificate(X509Certificate wrapped) { + this.wrapped = wrapped; + } + + @Override + public Set<String> getCriticalExtensionOIDs() { + return wrapped.getCriticalExtensionOIDs(); + } + + @Override + public byte[] getExtensionValue(String oid) { + return wrapped.getExtensionValue(oid); + } + + @Override + public Set<String> getNonCriticalExtensionOIDs() { + return wrapped.getNonCriticalExtensionOIDs(); + } + + @Override + public boolean hasUnsupportedCriticalExtension() { + return wrapped.hasUnsupportedCriticalExtension(); + } + + @Override + public void checkValidity() throws CertificateExpiredException, + CertificateNotYetValidException { + wrapped.checkValidity(); + } + + @Override + public void checkValidity(Date date) throws CertificateExpiredException, + CertificateNotYetValidException { + wrapped.checkValidity(date); + } + + @Override + public int getVersion() { + return wrapped.getVersion(); + } + + @Override + public BigInteger getSerialNumber() { + return wrapped.getSerialNumber(); + } + + @Override + public Principal getIssuerDN() { + return wrapped.getIssuerDN(); + } + + @Override + public Principal getSubjectDN() { + return wrapped.getSubjectDN(); + } + + @Override + public Date getNotBefore() { + return wrapped.getNotBefore(); + } + + @Override + public Date getNotAfter() { + return wrapped.getNotAfter(); + } + + @Override + public byte[] getTBSCertificate() throws CertificateEncodingException { + return wrapped.getTBSCertificate(); + } + + @Override + public byte[] getSignature() { + return wrapped.getSignature(); + } + + @Override + public String getSigAlgName() { + return wrapped.getSigAlgName(); + } + + @Override + public String getSigAlgOID() { + return wrapped.getSigAlgOID(); + } + + @Override + public byte[] getSigAlgParams() { + return wrapped.getSigAlgParams(); + } + + @Override + public boolean[] getIssuerUniqueID() { + return wrapped.getIssuerUniqueID(); + } + + @Override + public boolean[] getSubjectUniqueID() { + return wrapped.getSubjectUniqueID(); + } + + @Override + public boolean[] getKeyUsage() { + return wrapped.getKeyUsage(); + } + + @Override + public int getBasicConstraints() { + return wrapped.getBasicConstraints(); + } + + @Override + public byte[] getEncoded() throws CertificateEncodingException { + return wrapped.getEncoded(); + } + + @Override + public void verify(PublicKey key) throws CertificateException, NoSuchAlgorithmException, + InvalidKeyException, NoSuchProviderException, SignatureException { + wrapped.verify(key); + } + + @Override + public void verify(PublicKey key, String sigProvider) throws CertificateException, + NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, + SignatureException { + verify(key, sigProvider); + } + + @Override + public String toString() { + return wrapped.toString(); + } + + @Override + public PublicKey getPublicKey() { + return wrapped.getPublicKey(); + } +} diff --git a/luni/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java b/luni/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java index d1079c8..040a012 100644 --- a/luni/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java +++ b/luni/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java @@ -416,11 +416,13 @@ class DocumentBuilderImpl extends DocumentBuilder { private String resolveCharacterReference(String value, int base) { try { - int ch = Integer.parseInt(value, base); - if (ch < 0 || ch > Character.MAX_VALUE) { - return null; + int codePoint = Integer.parseInt(value, base); + if (Character.isBmpCodePoint(codePoint)) { + return String.valueOf((char) codePoint); + } else { + char[] surrogatePair = Character.toChars(codePoint); + return new String(surrogatePair); } - return String.valueOf((char) ch); } catch (NumberFormatException ex) { return null; } diff --git a/luni/src/test/java/libcore/icu/DateIntervalFormatTest.java b/luni/src/test/java/libcore/icu/DateIntervalFormatTest.java index bac8138..1c1296b 100644 --- a/luni/src/test/java/libcore/icu/DateIntervalFormatTest.java +++ b/luni/src/test/java/libcore/icu/DateIntervalFormatTest.java @@ -408,4 +408,16 @@ public class DateIntervalFormatTest extends junit.framework.TestCase { assertEquals("یکشنبه د ۱۹۸۰ د فبروري ۱۰", formatDateRange(new Locale("ps"), utc, thisYear, thisYear, flags)); assertEquals("วันอาทิตย์ 10 กุมภาพันธ์ 1980", formatDateRange(new Locale("th"), utc, thisYear, thisYear, flags)); } + + // http://b/13234532 + public void test13234532() throws Exception { + Locale l = Locale.US; + TimeZone utc = TimeZone.getTimeZone("UTC"); + + int flags = FORMAT_SHOW_TIME | FORMAT_ABBREV_ALL | FORMAT_12HOUR; + + assertEquals("10 – 11 AM", formatDateRange(l, utc, 10*HOUR, 11*HOUR, flags)); + assertEquals("11 AM – 1 PM", formatDateRange(l, utc, 11*HOUR, 13*HOUR, flags)); + assertEquals("2 – 3 PM", formatDateRange(l, utc, 14*HOUR, 15*HOUR, flags)); + } } diff --git a/luni/src/test/java/libcore/javax/net/ssl/DefaultHostnameVerifierTest.java b/luni/src/test/java/libcore/javax/net/ssl/DefaultHostnameVerifierTest.java index 1a24667..07ecd12 100644 --- a/luni/src/test/java/libcore/javax/net/ssl/DefaultHostnameVerifierTest.java +++ b/luni/src/test/java/libcore/javax/net/ssl/DefaultHostnameVerifierTest.java @@ -198,6 +198,11 @@ public final class DefaultHostnameVerifierTest extends TestCase { assertFalse(verifyWithDomainNamePattern("ddd.", "d*d.")); } + public void testNoPrefixMatch() { + assertFalse(verifyWithDomainNamePattern("imap.google.com.au", "imap.google.com")); + assertFalse(verifyWithDomainNamePattern("imap.google.com.au", "*.google.com")); + } + public void testVerifyHostName() { assertTrue(verifyWithDomainNamePattern("a.b.c.d", "a.b.c.d")); assertTrue(verifyWithDomainNamePattern("a.b.c.d", "*.b.c.d")); diff --git a/luni/src/test/java/libcore/xml/KxmlSerializerTest.java b/luni/src/test/java/libcore/xml/KxmlSerializerTest.java index 6a75a9b..5f68a99 100644 --- a/luni/src/test/java/libcore/xml/KxmlSerializerTest.java +++ b/luni/src/test/java/libcore/xml/KxmlSerializerTest.java @@ -22,7 +22,9 @@ import java.io.StringWriter; import junit.framework.TestCase; import org.kxml2.io.KXmlSerializer; import org.w3c.dom.Document; +import org.w3c.dom.Node; import org.w3c.dom.NodeList; +import org.w3c.dom.Text; import org.xmlpull.v1.XmlSerializer; import static tests.support.Support_Xml.domOf; @@ -87,12 +89,67 @@ public final class KxmlSerializerTest extends TestCase { return serializer; } + public String fromCodePoint(int codePoint) { + if (codePoint > Character.MAX_VALUE) { + return new String(Character.toChars(codePoint)); + } + return Character.toString((char) codePoint); + } + + // http://b/17960630 + public void testSpeakNoEvilMonkeys() throws Exception { + StringWriter stringWriter = new StringWriter(); + XmlSerializer serializer = new KXmlSerializer(); + serializer.setOutput(stringWriter); + serializer.startDocument("UTF-8", null); + serializer.startTag(NAMESPACE, "tag"); + serializer.attribute(NAMESPACE, "attr", "a\ud83d\ude4ab"); + serializer.text("c\ud83d\ude4ad"); + serializer.cdsect("e\ud83d\ude4af"); + serializer.endTag(NAMESPACE, "tag"); + serializer.endDocument(); + assertXmlEquals("<tag attr=\"a🙊b\">" + + "c🙊d" + + "<![CDATA[e]]>🙊<![CDATA[f]]>" + + "</tag>", stringWriter.toString()); + + // Check we can parse what we just output. + Document doc = domOf(stringWriter.toString()); + Node root = doc.getDocumentElement(); + assertEquals("a\ud83d\ude4ab", root.getAttributes().getNamedItem("attr").getNodeValue()); + Text text = (Text) root.getFirstChild(); + assertEquals("c\ud83d\ude4ade\ud83d\ude4af", text.getNodeValue()); + } + + public void testBadSurrogates() throws Exception { + StringWriter stringWriter = new StringWriter(); + XmlSerializer serializer = new KXmlSerializer(); + serializer.setOutput(stringWriter); + serializer.startDocument("UTF-8", null); + serializer.startTag(NAMESPACE, "tag"); + try { + serializer.attribute(NAMESPACE, "attr", "a\ud83d\u0040b"); + } catch (IllegalArgumentException expected) { + } + try { + serializer.text("c\ud83d\u0040d"); + } catch (IllegalArgumentException expected) { + } + try { + serializer.cdsect("e\ud83d\u0040f"); + } catch (IllegalArgumentException expected) { + } + } + + // Cover all the BMP code points plus a few that require us to use surrogates. + private static int MAX_TEST_CODE_POINT = 0x10008; + public void testInvalidCharactersInText() throws IOException { XmlSerializer serializer = newSerializer(); serializer.startTag(NAMESPACE, "root"); - for (int ch = 0; ch <= 0xffff; ++ch) { - final String s = Character.toString((char) ch); - if (isValidXmlCodePoint(ch)) { + for (int c = 0; c <= MAX_TEST_CODE_POINT; ++c) { + final String s = fromCodePoint(c); + if (isValidXmlCodePoint(c)) { serializer.text("a" + s + "b"); } else { try { @@ -108,9 +165,9 @@ public final class KxmlSerializerTest extends TestCase { public void testInvalidCharactersInAttributeValues() throws IOException { XmlSerializer serializer = newSerializer(); serializer.startTag(NAMESPACE, "root"); - for (int ch = 0; ch <= 0xffff; ++ch) { - final String s = Character.toString((char) ch); - if (isValidXmlCodePoint(ch)) { + for (int c = 0; c <= MAX_TEST_CODE_POINT; ++c) { + final String s = fromCodePoint(c); + if (isValidXmlCodePoint(c)) { serializer.attribute(NAMESPACE, "a", "a" + s + "b"); } else { try { @@ -126,9 +183,9 @@ public final class KxmlSerializerTest extends TestCase { public void testInvalidCharactersInCdataSections() throws IOException { XmlSerializer serializer = newSerializer(); serializer.startTag(NAMESPACE, "root"); - for (int ch = 0; ch <= 0xffff; ++ch) { - final String s = Character.toString((char) ch); - if (isValidXmlCodePoint(ch)) { + for (int c = 0; c <= MAX_TEST_CODE_POINT; ++c) { + final String s = fromCodePoint(c); + if (isValidXmlCodePoint(c)) { serializer.cdsect("a" + s + "b"); } else { try { diff --git a/support/src/test/java/libcore/java/security/TestKeyStore.java b/support/src/test/java/libcore/java/security/TestKeyStore.java index 203c028..bd64360 100644 --- a/support/src/test/java/libcore/java/security/TestKeyStore.java +++ b/support/src/test/java/libcore/java/security/TestKeyStore.java @@ -47,6 +47,7 @@ import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; import java.security.Security; +import java.security.UnrecoverableEntryException; import java.security.UnrecoverableKeyException; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; @@ -260,6 +261,7 @@ public final class TestKeyStore extends Assert { private X500Principal subject; private int keyUsage; private boolean ca; + private PrivateKeyEntry privateEntry; private PrivateKeyEntry signer; private Certificate rootCa; private final List<KeyPurposeId> extendedKeyUsages = new ArrayList<KeyPurposeId>(); @@ -314,6 +316,12 @@ public final class TestKeyStore extends Assert { return this; } + /** a private key entry to use for the generation of the certificate */ + public Builder privateEntry(PrivateKeyEntry privateEntry) { + this.privateEntry = privateEntry; + return this; + } + /** a private key entry to be used for signing, otherwise self-sign */ public Builder signer(PrivateKeyEntry signer) { this.signer = signer; @@ -368,21 +376,32 @@ public final class TestKeyStore extends Assert { } } + /* + * This is not implemented for other key types because the logic + * would be long to write and it's not needed currently. + */ + if (privateEntry != null + && (keyAlgorithms.length != 1 || !"RSA".equals(keyAlgorithms[0]))) { + throw new IllegalStateException( + "Only reusing an existing key is implemented for RSA"); + } + KeyStore keyStore = createKeyStore(); for (String keyAlgorithm : keyAlgorithms) { String publicAlias = aliasPrefix + "-public-" + keyAlgorithm; String privateAlias = aliasPrefix + "-private-" + keyAlgorithm; if ((keyAlgorithm.equals("EC_RSA") || keyAlgorithm.equals("DH_RSA")) && signer == null && rootCa == null) { - createKeys(keyStore, keyAlgorithm, publicAlias, privateAlias, - privateKey(keyStore, keyPassword, "RSA", "RSA")); + createKeys(keyStore, keyAlgorithm, publicAlias, privateAlias, null, + privateKey(keyStore, keyPassword, "RSA", "RSA")); continue; } else if (keyAlgorithm.equals("DH_DSA") && signer == null && rootCa == null) { - createKeys(keyStore, keyAlgorithm, publicAlias, privateAlias, + createKeys(keyStore, keyAlgorithm, publicAlias, privateAlias, null, privateKey(keyStore, keyPassword, "DSA", "DSA")); continue; } - createKeys(keyStore, keyAlgorithm, publicAlias, privateAlias, signer); + createKeys(keyStore, keyAlgorithm, publicAlias, privateAlias, privateEntry, + signer); } if (rootCa != null) { keyStore.setCertificateEntry(aliasPrefix @@ -416,6 +435,7 @@ public final class TestKeyStore extends Assert { String keyAlgorithm, String publicAlias, String privateAlias, + PrivateKeyEntry privateEntry, PrivateKeyEntry signer) throws Exception { PrivateKey caKey; X509Certificate caCert; @@ -430,41 +450,50 @@ public final class TestKeyStore extends Assert { caCertChain = (X509Certificate[])signer.getCertificateChain(); } - PrivateKey privateKey; + final PrivateKey privateKey; + final PublicKey publicKey; X509Certificate x509c; if (publicAlias == null && privateAlias == null) { // don't want anything apparently privateKey = null; + publicKey = null; x509c = null; } else { - // 1.) we make the keys - int keySize; - if (keyAlgorithm.equals("RSA")) { - // 512 breaks SSL_RSA_EXPORT_* on RI and TLS_ECDHE_RSA_WITH_RC4_128_SHA for us - keySize = 1024; - } else if (keyAlgorithm.equals("DH_RSA")) { - keySize = 512; - keyAlgorithm = "DH"; - } else if (keyAlgorithm.equals("DSA")) { - keySize = 512; - } else if (keyAlgorithm.equals("DH_DSA")) { - keySize = 512; - keyAlgorithm = "DH"; - } else if (keyAlgorithm.equals("EC")) { - keySize = 256; - } else if (keyAlgorithm.equals("EC_RSA")) { - keySize = 256; - keyAlgorithm = "EC"; - } else { - throw new IllegalArgumentException("Unknown key algorithm " + keyAlgorithm); - } + if (privateEntry == null) { + // 1a.) we make the keys + int keySize; + if (keyAlgorithm.equals("RSA")) { + // 512 breaks SSL_RSA_EXPORT_* on RI and + // TLS_ECDHE_RSA_WITH_RC4_128_SHA for us + keySize = 1024; + } else if (keyAlgorithm.equals("DH_RSA")) { + keySize = 512; + keyAlgorithm = "DH"; + } else if (keyAlgorithm.equals("DSA")) { + keySize = 512; + } else if (keyAlgorithm.equals("DH_DSA")) { + keySize = 512; + keyAlgorithm = "DH"; + } else if (keyAlgorithm.equals("EC")) { + keySize = 256; + } else if (keyAlgorithm.equals("EC_RSA")) { + keySize = 256; + keyAlgorithm = "EC"; + } else { + throw new IllegalArgumentException("Unknown key algorithm " + keyAlgorithm); + } - KeyPairGenerator kpg = KeyPairGenerator.getInstance(keyAlgorithm); - kpg.initialize(keySize, new SecureRandom()); + KeyPairGenerator kpg = KeyPairGenerator.getInstance(keyAlgorithm); + kpg.initialize(keySize, new SecureRandom()); - KeyPair kp = kpg.generateKeyPair(); - privateKey = kp.getPrivate(); - PublicKey publicKey = kp.getPublic(); + KeyPair kp = kpg.generateKeyPair(); + privateKey = kp.getPrivate(); + publicKey = kp.getPublic(); + } else { + // 1b.) we use the previous keys + privateKey = privateEntry.getPrivateKey(); + publicKey = privateEntry.getCertificate().getPublicKey(); + } // 2.) use keys to make certificate X500Principal issuer = ((caCert != null) @@ -820,6 +849,24 @@ public final class TestKeyStore extends Assert { } /** + * Return an {@code X509Certificate that matches the given {@code alias}. + */ + public KeyStore.Entry getEntryByAlias(String alias) { + return entryByAlias(keyStore, alias); + } + + /** + * Finds an entry in the keystore by the given alias. + */ + public static KeyStore.Entry entryByAlias(KeyStore keyStore, String alias) { + try { + return keyStore.getEntry(alias, null); + } catch (NoSuchAlgorithmException | UnrecoverableEntryException | KeyStoreException e) { + throw new RuntimeException(e); + } + } + + /** * Create a client key store that only contains self-signed certificates but no private keys */ public static KeyStore createClient(KeyStore caKeyStore) { diff --git a/support/src/test/java/tests/resources/hyts_certLoop.jar b/support/src/test/java/tests/resources/hyts_certLoop.jar Binary files differnew file mode 100644 index 0000000..cb4ebe1 --- /dev/null +++ b/support/src/test/java/tests/resources/hyts_certLoop.jar diff --git a/xml/src/main/java/org/kxml2/io/KXmlSerializer.java b/xml/src/main/java/org/kxml2/io/KXmlSerializer.java index 8fa2756..bfdeece 100644 --- a/xml/src/main/java/org/kxml2/io/KXmlSerializer.java +++ b/xml/src/main/java/org/kxml2/io/KXmlSerializer.java @@ -125,14 +125,18 @@ public class KXmlSerializer implements XmlSerializer { // otherwise generate. // Note: tab, newline, and carriage return have already been // handled above. - boolean valid = (c >= 0x20 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xfffd); - if (!valid) { - reportInvalidCharacter(c); - } - if (unicode || c < 127) { - writer.write(c); + boolean allowedInXml = (c >= 0x20 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xfffd); + if (allowedInXml) { + if (unicode || c < 127) { + writer.write(c); + } else { + writer.write("&#" + ((int) c) + ";"); + } + } else if (Character.isHighSurrogate(c) && i < s.length() - 1) { + writeSurrogate(c, s.charAt(i + 1)); + ++i; } else { - writer.write("&#" + ((int) c) + ";"); + reportInvalidCharacter(c); } // END android-changed } @@ -141,7 +145,7 @@ public class KXmlSerializer implements XmlSerializer { // BEGIN android-added private static void reportInvalidCharacter(char ch) { - throw new IllegalArgumentException("Illegal character (" + Integer.toHexString((int) ch) + ")"); + throw new IllegalArgumentException("Illegal character (U+" + Integer.toHexString((int) ch) + ")"); } // END android-added @@ -548,22 +552,41 @@ public class KXmlSerializer implements XmlSerializer { // BEGIN android-changed: ]]> is not allowed within a CDATA, // so break and start a new one when necessary. data = data.replace("]]>", "]]]]><![CDATA[>"); - char[] chars = data.toCharArray(); - // We also aren't allowed any invalid characters. - for (char ch : chars) { - boolean valid = (ch >= 0x20 && ch <= 0xd7ff) || + writer.write("<![CDATA["); + for (int i = 0; i < data.length(); ++i) { + char ch = data.charAt(i); + boolean allowedInCdata = (ch >= 0x20 && ch <= 0xd7ff) || (ch == '\t' || ch == '\n' || ch == '\r') || (ch >= 0xe000 && ch <= 0xfffd); - if (!valid) { + if (allowedInCdata) { + writer.write(ch); + } else if (Character.isHighSurrogate(ch) && i < data.length() - 1) { + // Character entities aren't valid in CDATA, so break out for this. + writer.write("]]>"); + writeSurrogate(ch, data.charAt(++i)); + writer.write("<![CDATA["); + } else { reportInvalidCharacter(ch); } } - writer.write("<![CDATA["); - writer.write(chars, 0, chars.length); writer.write("]]>"); // END android-changed } + // BEGIN android-added + private void writeSurrogate(char high, char low) throws IOException { + if (!Character.isLowSurrogate(low)) { + throw new IllegalArgumentException("Bad surrogate pair (U+" + Integer.toHexString((int) high) + + " U+" + Integer.toHexString((int) low) + ")"); + } + // Java-style surrogate pairs aren't allowed in XML. We could use the > 3-byte encodings, but that + // seems likely to upset anything expecting modified UTF-8 rather than "real" UTF-8. It seems more + // conservative in a Java environment to use an entity reference instead. + int codePoint = Character.toCodePoint(high, low); + writer.write("&#" + codePoint + ";"); + } + // END android-added + public void comment(String comment) throws IOException { check(false); writer.write("<!--"); |