summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWolfgang Wiedmeyer <wolfgit@wiedmeyer.de>2016-12-12 15:08:24 +0100
committerWolfgang Wiedmeyer <wolfgit@wiedmeyer.de>2016-12-12 15:08:24 +0100
commit674c9666d3405bac361677c72d2fb7c16f31dbad (patch)
treeea84d2c20955fffda046e6c9dbcd1ac596b47bb2
parent3a8f57d2dc82c0879b0e29fbdfaad9b9fb44e6f6 (diff)
parent1b7c3672b5219216119eb288d4363324a7f6667e (diff)
downloadlibcore-replicant-6.0.zip
libcore-replicant-6.0.tar.gz
libcore-replicant-6.0.tar.bz2
Merge branch 'cm-13.0' of https://github.com/CyanogenMod/android_libcore into replicant-6.0HEADreplicant-6.0-0001replicant-6.0
-rw-r--r--luni/src/main/native/libcore_icu_NativeIDN.cpp9
-rw-r--r--luni/src/test/java/com/android/org/bouncycastle/crypto/digests/DigestTest.java33
-rw-r--r--luni/src/test/java/libcore/java/lang/ref/FinalizeTest.java9
-rw-r--r--luni/src/test/java/libcore/java/net/IDNTest.java11
-rw-r--r--luni/src/test/java/libcore/javax/crypto/CipherTest.java91
-rw-r--r--luni/src/test/java/libcore/javax/net/ssl/SSLSessionTest.java2
-rw-r--r--luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java18
-rw-r--r--support/src/test/java/libcore/tlswire/handshake/HelloExtension.java3
-rw-r--r--support/src/test/java/tests/util/SummaryStatistics.java82
-rw-r--r--xml/src/main/java/org/kxml2/io/KXmlParser.java74
10 files changed, 303 insertions, 29 deletions
diff --git a/luni/src/main/native/libcore_icu_NativeIDN.cpp b/luni/src/main/native/libcore_icu_NativeIDN.cpp
index 43f3ce5..9786b9d 100644
--- a/luni/src/main/native/libcore_icu_NativeIDN.cpp
+++ b/luni/src/main/native/libcore_icu_NativeIDN.cpp
@@ -37,7 +37,8 @@ static jstring NativeIDN_convertImpl(JNIEnv* env, jclass, jstring javaSrc, jint
if (src.get() == NULL) {
return NULL;
}
- UChar dst[256];
+ static const size_t kDstSize = 512;
+ UChar dst[kDstSize];
UErrorCode status = U_ZERO_ERROR;
// We're stuck implementing IDNA-2003 for now since that's what we specify.
@@ -47,10 +48,10 @@ static jstring NativeIDN_convertImpl(JNIEnv* env, jclass, jstring javaSrc, jint
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
size_t resultLength = toAscii
- ? uidna_IDNToASCII(src.get(), src.size(), &dst[0], sizeof(dst), flags, NULL, &status)
- : uidna_IDNToUnicode(src.get(), src.size(), &dst[0], sizeof(dst), flags, NULL, &status);
+ ? uidna_IDNToASCII(src.get(), src.size(), &dst[0], kDstSize, flags, NULL, &status)
+ : uidna_IDNToUnicode(src.get(), src.size(), &dst[0], kDstSize, flags, NULL, &status);
#pragma GCC diagnostic pop
-
+
if (U_FAILURE(status)) {
jniThrowException(env, "java/lang/IllegalArgumentException", u_errorName(status));
return NULL;
diff --git a/luni/src/test/java/com/android/org/bouncycastle/crypto/digests/DigestTest.java b/luni/src/test/java/com/android/org/bouncycastle/crypto/digests/DigestTest.java
index 8708214..fce8507 100644
--- a/luni/src/test/java/com/android/org/bouncycastle/crypto/digests/DigestTest.java
+++ b/luni/src/test/java/com/android/org/bouncycastle/crypto/digests/DigestTest.java
@@ -19,6 +19,7 @@ package com.android.org.bouncycastle.crypto.digests;
import junit.framework.TestCase;
import com.android.org.bouncycastle.crypto.Digest;
import com.android.org.bouncycastle.crypto.ExtendedDigest;
+import tests.util.SummaryStatistics;
/**
* Implements unit tests for our JNI wrapper around OpenSSL. We use the
@@ -36,6 +37,7 @@ public class DigestTest extends TestCase {
* @param newDigest The new digest implementation, provided by OpenSSL
*/
public void doTestMessageDigest(Digest oldDigest, Digest newDigest) {
+ final int WARMUP = 10;
final int ITERATIONS = 100;
byte[] data = new byte[1024];
@@ -54,27 +56,31 @@ public class DigestTest extends TestCase {
data[i] = (byte)i;
}
- long oldTime = 0;
- long newTime = 0;
+ SummaryStatistics oldTime = new SummaryStatistics();
+ SummaryStatistics newTime = new SummaryStatistics();
- for (int j = 0; j < ITERATIONS; j++) {
- long t0 = System.currentTimeMillis();
+ for (int j = 0; j < ITERATIONS + WARMUP; j++) {
+ long t0 = System.nanoTime();
for (int i = 0; i < 4; i++) {
oldDigest.update(data, 0, data.length);
}
int oldLength = oldDigest.doFinal(oldHash, 0);
- long t1 = System.currentTimeMillis();
+ long t1 = System.nanoTime();
- oldTime = oldTime + (t1 - t0);
+ if (j >= WARMUP) {
+ oldTime.add(t1 - t0);
+ }
- long t2 = System.currentTimeMillis();
+ long t2 = System.nanoTime();
for (int i = 0; i < 4; i++) {
newDigest.update(data, 0, data.length);
}
int newLength = newDigest.doFinal(newHash, 0);
- long t3 = System.currentTimeMillis();
+ long t3 = System.nanoTime();
- newTime = newTime + (t3 - t2);
+ if (j >= WARMUP) {
+ newTime.add(t3 - t2);
+ }
assertEquals("Hash sizes must be equal", oldLength, newLength);
@@ -83,10 +89,13 @@ public class DigestTest extends TestCase {
}
}
- System.out.println("Time for " + ITERATIONS + " x old hash processing: " + oldTime + " ms");
- System.out.println("Time for " + ITERATIONS + " x new hash processing: " + newTime + " ms");
+ System.out.println("Time for " + ITERATIONS + " x old hash processing: "
+ + oldTime.toString());
+ System.out.println("Time for " + ITERATIONS + " x new hash processing: "
+ + newTime.toString());
- assertTrue("New hash should be faster", newTime < oldTime);
+ assertTrue("New hash should be faster:\nold=" + oldTime.toString() + "\nnew="
+ + newTime.toString(), newTime.mean() < oldTime.mean());
}
/**
diff --git a/luni/src/test/java/libcore/java/lang/ref/FinalizeTest.java b/luni/src/test/java/libcore/java/lang/ref/FinalizeTest.java
index ef303bd..d71b5b0 100644
--- a/luni/src/test/java/libcore/java/lang/ref/FinalizeTest.java
+++ b/luni/src/test/java/libcore/java/lang/ref/FinalizeTest.java
@@ -69,13 +69,18 @@ public final class FinalizeTest extends TestCase {
static class X {}
- // http://b/issue?id=2136462
- public void testBackFromTheDead() throws Exception {
+ // Helper function since we do not want a vreg to keep the allocated object live.
+ // For b/25851249
+ private void exceptionInConstructor() {
try {
new ConstructionFails();
} catch (AssertionError expected) {
}
+ }
+ // http://b/issue?id=2136462
+ public void testBackFromTheDead() throws Exception {
+ exceptionInConstructor();
FinalizationTester.induceFinalization();
assertTrue("object whose constructor threw was not finalized", ConstructionFails.finalized);
}
diff --git a/luni/src/test/java/libcore/java/net/IDNTest.java b/luni/src/test/java/libcore/java/net/IDNTest.java
index f01eca3..37f3505 100644
--- a/luni/src/test/java/libcore/java/net/IDNTest.java
+++ b/luni/src/test/java/libcore/java/net/IDNTest.java
@@ -37,4 +37,15 @@ public class IDNTest extends TestCase {
String longInput = makePunyString(512);
assertEquals(longInput, IDN.toUnicode(longInput));
}
+
+ // http://b/30765246
+ public void testLongDomainName() {
+ String label63 = "123456789-123456789-123456789-123456789-123456789-123456789-123";
+ String host255 = label63 + "." + label63 + "." + label63 + "." + label63;
+ try {
+ IDN.toASCII(host255.substring(3) + ".com");
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
}
diff --git a/luni/src/test/java/libcore/javax/crypto/CipherTest.java b/luni/src/test/java/libcore/javax/crypto/CipherTest.java
index dd7d6e7..398c688 100644
--- a/luni/src/test/java/libcore/javax/crypto/CipherTest.java
+++ b/luni/src/test/java/libcore/javax/crypto/CipherTest.java
@@ -3203,6 +3203,29 @@ public final class CipherTest extends TestCase {
}
}
+ // Test that when reading GCM parameters encoded using ASN1, a value for the tag size
+ // not present indicates a value of 12.
+ // https://b/29876633
+ public void test_DefaultGCMTagSizeAlgorithmParameterSpec() throws Exception {
+ final String AES = "AES";
+ final String AES_GCM = "AES/GCM/NoPadding";
+ byte[] input = new byte[16];
+ byte[] key = new byte[16];
+ Cipher cipher = Cipher.getInstance(AES_GCM, "BC");
+ AlgorithmParameters param = AlgorithmParameters.getInstance("GCM");
+ param.init(new byte[] {
+ (byte) 48, // DER encoding : tag_Sequence
+ (byte) 14, // DER encoding : total length
+ (byte) 4, // DER encoding : tag_OctetString
+ (byte) 12, // DER encoding : counter length
+ (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0,
+ (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0 });
+ cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, AES), param);
+ byte[] ciphertext = cipher.update(input);
+ byte[] tag = cipher.doFinal();
+ assertEquals(12, tag.length);
+ }
+
public void testAES_ECB_PKCS5Padding_ShortBuffer_Failure() throws Exception {
for (String provider : AES_PROVIDERS) {
testAES_ECB_PKCS5Padding_ShortBuffer_Failure(provider);
@@ -3515,4 +3538,72 @@ public final class CipherTest extends TestCase {
cipher.init(Cipher.ENCRYPT_MODE, keyGen.generateKeyPair().getPublic());
cipher.doFinal(new byte[] {1,2,3,4});
}
+
+ /*
+ * Check that two AAD updates are equivalent to one.
+ * http://b/27371173
+ */
+ public void test_AESGCMNoPadding_UpdateAADTwice_Success() throws Exception {
+ SecretKeySpec key = new SecretKeySpec(new byte[16], "AES");
+ GCMParameterSpec spec = new GCMParameterSpec(128, new byte[12]);
+ Cipher c1 = Cipher.getInstance("AES/GCM/NoPadding");
+ Cipher c2 = Cipher.getInstance("AES/GCM/NoPadding");
+
+ c1.init(Cipher.ENCRYPT_MODE, key, spec);
+ c1.updateAAD(new byte[] {
+ 0x01, 0x02, 0x03, 0x04, 0x05,
+ });
+ c1.updateAAD(new byte[] {
+ 0x06, 0x07, 0x08, 0x09, 0x10,
+ });
+
+ c2.init(Cipher.ENCRYPT_MODE, key, spec);
+ c2.updateAAD(new byte[] {
+ 0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x07, 0x08, 0x09, 0x10,
+ });
+
+ assertEquals(Arrays.toString(c1.doFinal()), Arrays.toString(c2.doFinal()));
+ }
+
+ /*
+ * Check that GCM encryption with old and new instances update correctly.
+ * http://b/26694388
+ */
+ public void test_AESGCMNoPadding_Reuse_Success() throws Exception {
+ SecretKeySpec key = new SecretKeySpec(new byte[16], "AES");
+ GCMParameterSpec spec = new GCMParameterSpec(128, new byte[12]);
+ Cipher c1 = Cipher.getInstance("AES/GCM/NoPadding");
+ Cipher c2 = Cipher.getInstance("AES/GCM/NoPadding");
+
+ // Pollute the c1 cipher with AAD
+ c1.init(Cipher.ENCRYPT_MODE, key, spec);
+ c1.updateAAD(new byte[] {
+ 0x01, 0x02, 0x03, 0x04, 0x05,
+ });
+
+ // Now init each again and make sure the outputs are the same
+ c1.init(Cipher.ENCRYPT_MODE, key, spec);
+ c2.init(Cipher.ENCRYPT_MODE, key, spec);
+
+ byte[] aad = new byte[] {
+ 0x10, 0x20, 0x30, 0x40, 0x50, 0x60,
+ };
+ c1.updateAAD(aad);
+ c2.updateAAD(aad);
+
+ assertEquals(Arrays.toString(c1.doFinal()), Arrays.toString(c2.doFinal()));
+
+ // .doFinal should also reset the state, so check that as well.
+ byte[] aad2 = new byte[] {
+ 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11,
+ };
+
+ Cipher c3 = Cipher.getInstance("AES/GCM/NoPadding");
+ c3.init(Cipher.ENCRYPT_MODE, key, spec);
+
+ c1.updateAAD(aad2);
+ c3.updateAAD(aad2);
+ assertEquals(Arrays.toString(c1.doFinal()), Arrays.toString(c3.doFinal()));
+ }
}
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLSessionTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLSessionTest.java
index a434d94..bc2b626 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLSessionTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLSessionTest.java
@@ -99,7 +99,7 @@ public class SSLSessionTest extends TestCase {
assertTrue("s.server.getLastAccessedTime()=" + s.server.getLastAccessedTime() + " " +
"s.client.getLastAccessedTime()=" + s.client.getLastAccessedTime(),
Math.abs(s.server.getLastAccessedTime()
- - s.client.getLastAccessedTime()) < 1 * 1000);
+ - s.client.getLastAccessedTime()) <= 1 * 1000);
assertTrue(s.server.getLastAccessedTime() >=
s.server.getCreationTime());
assertTrue(s.client.getLastAccessedTime() >=
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 bf2d0f8..11dfb3d 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
@@ -1559,7 +1559,23 @@ public class SSLSocketTest extends TestCase {
@Override
public void run(SSLSocketFactory sslSocketFactory) throws Exception {
ClientHello clientHello = captureTlsHandshakeClientHello(sslSocketFactory);
- String[] cipherSuites = new String[clientHello.cipherSuites.size()];
+ final String[] cipherSuites;
+
+ // RFC 5746 allows you to send an empty "renegotiation_info" extension *or*
+ // a special signaling cipher suite. The TLS API has no way to check or
+ // indicate that a certain TLS extension should be used.
+ HelloExtension renegotiationInfoExtension = clientHello.findExtensionByType(
+ HelloExtension.TYPE_RENEGOTIATION_INFO);
+ if (renegotiationInfoExtension != null &&
+ renegotiationInfoExtension.data.length == 1 &&
+ renegotiationInfoExtension.data[0] == 0) {
+ cipherSuites = new String[clientHello.cipherSuites.size() + 1];
+ cipherSuites[clientHello.cipherSuites.size()] =
+ StandardNames.CIPHER_SUITE_SECURE_RENEGOTIATION;
+ } else {
+ cipherSuites = new String[clientHello.cipherSuites.size()];
+ }
+
for (int i = 0; i < clientHello.cipherSuites.size(); i++) {
CipherSuite cipherSuite = clientHello.cipherSuites.get(i);
cipherSuites[i] = cipherSuite.getAndroidName();
diff --git a/support/src/test/java/libcore/tlswire/handshake/HelloExtension.java b/support/src/test/java/libcore/tlswire/handshake/HelloExtension.java
index 5741072..a648cdf 100644
--- a/support/src/test/java/libcore/tlswire/handshake/HelloExtension.java
+++ b/support/src/test/java/libcore/tlswire/handshake/HelloExtension.java
@@ -31,6 +31,7 @@ public class HelloExtension {
public static final int TYPE_SERVER_NAME = 0;
public static final int TYPE_PADDING = 21;
public static final int TYPE_SESSION_TICKET = 35;
+ public static final int TYPE_RENEGOTIATION_INFO = 65281;
private static final Map<Integer, String> TYPE_TO_NAME = new HashMap<Integer, String>();
static {
@@ -60,7 +61,7 @@ public class HelloExtension {
TYPE_TO_NAME.put(13172, "next_protocol_negotiation");
TYPE_TO_NAME.put(30031, "Channel ID (old)");
TYPE_TO_NAME.put(30032, "Channel ID (new)");
- TYPE_TO_NAME.put(65281, "renegotiation_info");
+ TYPE_TO_NAME.put(TYPE_RENEGOTIATION_INFO, "renegotiation_info");
}
public int type;
diff --git a/support/src/test/java/tests/util/SummaryStatistics.java b/support/src/test/java/tests/util/SummaryStatistics.java
new file mode 100644
index 0000000..4ce0a04
--- /dev/null
+++ b/support/src/test/java/tests/util/SummaryStatistics.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package tests.util;
+
+public class SummaryStatistics {
+ /** The number of values seen. */
+ private int numValues;
+
+ /** Sum of the values. */
+ private double sum;
+
+ /** Sum of the squares of the values added. */
+ private double squaresSum;
+
+ /** The previously added value. */
+ private double lastValue;
+
+ public SummaryStatistics() {
+ }
+
+ private double square(double value) {
+ return value * value;
+ }
+
+ /** Add a new value to the values seen. */
+ public void add(double value) {
+ sum += value - lastValue;
+ squaresSum += square(value) - square(lastValue);
+ numValues++;
+ lastValue = value;
+ }
+
+ /** Mean of the values seen. */
+ public double mean() {
+ return sum / numValues;
+ }
+
+ /** Variance of the values seen. */
+ public double var() {
+ return (squaresSum / numValues) - square(mean());
+ }
+
+ /** Standard deviation of the values seen. */
+ public double stddev() {
+ return Math.sqrt(var());
+ }
+
+ /** Coefficient of variation of the values seen. */
+ public double coeffVar() {
+ return stddev() / mean();
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder("SummaryStatistics{");
+ sb.append("n=");
+ sb.append(numValues);
+ sb.append(",mean=");
+ sb.append(mean());
+ sb.append(",var=");
+ sb.append(var());
+ sb.append(",stddev=");
+ sb.append(stddev());
+ sb.append(",coeffVar=");
+ sb.append(coeffVar());
+ sb.append('}');
+ return sb.toString();
+ }
+}
diff --git a/xml/src/main/java/org/kxml2/io/KXmlParser.java b/xml/src/main/java/org/kxml2/io/KXmlParser.java
index a90db3b..a75cc72 100644
--- a/xml/src/main/java/org/kxml2/io/KXmlParser.java
+++ b/xml/src/main/java/org/kxml2/io/KXmlParser.java
@@ -157,6 +157,8 @@ public class KXmlParser implements XmlPullParser, Closeable {
private boolean isWhitespace;
private String namespace;
private String prefix;
+ private String foundPrefix = null;
+ private String foundName = null;
private String name;
private String text;
@@ -268,15 +270,21 @@ public class KXmlParser implements XmlPullParser, Closeable {
}
}
- int cut = name.indexOf(':');
+ if (foundPrefix != null && foundName != null) {
+ prefix = foundPrefix;
+ name = foundName;
+ }
+ else {
+ int cut = name.indexOf(':');
if (cut == 0) {
checkRelaxed("illegal tag name: " + name);
}
- if (cut != -1) {
- prefix = name.substring(0, cut);
- name = name.substring(cut + 1);
+ if (cut != -1) {
+ prefix = name.substring(0, cut);
+ name = name.substring(cut + 1);
+ }
}
this.namespace = getNamespace(prefix);
@@ -961,13 +969,19 @@ public class KXmlParser implements XmlPullParser, Closeable {
}
private void readEndTag() throws IOException, XmlPullParserException {
+ int sp = (depth - 1) * 4;
read('<');
read('/');
- name = readName(); // TODO: pass the expected name in as a hint?
+ if (depth == 0) {
+ name = readName();
+ }
+ else {
+ // Pass the expected name in as a hint.
+ name = readExpectedName(elementStack[sp + 3]);
+ }
skip();
read('>');
- int sp = (depth - 1) * 4;
if (depth == 0) {
checkRelaxed("read end tag " + name + " with no tags open");
@@ -1055,7 +1069,7 @@ public class KXmlParser implements XmlPullParser, Closeable {
if (!xmldecl) {
read('<');
}
- name = readName();
+ name = readName(true);
attributeCount = 0;
while (true) {
@@ -1429,7 +1443,12 @@ public class KXmlParser implements XmlPullParser, Closeable {
}
if (result == null) {
- return stringPool.get(buffer, start, position - start);
+ if (isWhitespace) {
+ return stringPool.get(buffer, start, position - start);
+ }
+ else {
+ return new String(buffer, start, position - start);
+ }
} else {
result.append(buffer, start, position - start);
return result.toString();
@@ -1525,13 +1544,44 @@ public class KXmlParser implements XmlPullParser, Closeable {
* Returns an element or attribute name. This is always non-empty for
* non-relaxed parsers.
*/
+ private String readExpectedName(String expected) throws IOException, XmlPullParserException {
+ int length = expected.length();
+ int end = position + length;
+ if (end < limit) {
+ // Fast path for normal case.
+ boolean match = true;
+ for (int i = 0; i < length; i++) {
+ if (buffer[position+i] != expected.charAt(i)) {
+ match = false;
+ break;
+ }
+ }
+ if (match) {
+ position += length;
+ return expected;
+ }
+ }
+ return readName();
+ }
+
private String readName() throws IOException, XmlPullParserException {
+ return readName(false);
+ }
+
+ /**
+ * Returns an element or attribute name. This is always non-empty for
+ * non-relaxed parsers. findPrefix should only be true for element names
+ */
+ private String readName(boolean findPrefix) throws IOException, XmlPullParserException {
if (position >= limit && !fillBuffer(1)) {
checkRelaxed("name expected");
return "";
}
int start = position;
+ int nameStart = -1;
+ foundPrefix = null;
+ foundName = null;
StringBuilder result = null;
// read the first character
@@ -1575,12 +1625,20 @@ public class KXmlParser implements XmlPullParser, Closeable {
|| c == ':'
|| c == '.'
|| c >= '\u00b7') { // TODO: check the XML spec
+ // Fast path for common case
+ if (c == ':' && findPrefix && foundPrefix == null) {
+ foundPrefix = stringPool.get(buffer, start, position - start);
+ nameStart = position+1;
+ }
position++;
continue;
}
// we encountered a non-name character. done!
if (result == null) {
+ if (foundPrefix != null && position != nameStart) {
+ foundName = stringPool.get(buffer, nameStart, position - nameStart);
+ }
return stringPool.get(buffer, start, position - start);
} else {
result.append(buffer, start, position - start);